Support for Certificate Identity Mapping

See design http://www.freeipa.org/page/V4/Certificate_Identity_Mapping

https://fedorahosted.org/freeipa/ticket/6542

Reviewed-By: Martin Basti <mbasti@redhat.com>
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Reviewed-By: David Kupka <dkupka@redhat.com>
This commit is contained in:
Florence Blanc-Renaud 2016-12-20 16:21:58 +01:00 committed by David Kupka
parent 22d7492c94
commit 9e24918c89
15 changed files with 862 additions and 13 deletions

16
ACI.txt
View File

@ -40,6 +40,18 @@ 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=certmap,dc=ipa,dc=example
aci: (targetattr = "ipacertmappromptusername")(targetfilter = "(objectclass=ipacertmapconfigobject)")(version 3.0;acl "permission:System: Modify Certmap Configuration";allow (write) groupdn = "ldap:///cn=System: Modify Certmap Configuration,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=certmap,dc=ipa,dc=example
aci: (targetattr = "cn || ipacertmappromptusername")(targetfilter = "(objectclass=ipacertmapconfigobject)")(version 3.0;acl "permission:System: Read Certmap Configuration";allow (compare,read,search) userdn = "ldap:///all";)
dn: cn=certmaprules,cn=certmap,dc=ipa,dc=example
aci: (targetfilter = "(objectclass=ipacertmaprule)")(version 3.0;acl "permission:System: Add Certmap Rules";allow (add) groupdn = "ldap:///cn=System: Add Certmap Rules,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=certmaprules,cn=certmap,dc=ipa,dc=example
aci: (targetfilter = "(objectclass=ipacertmaprule)")(version 3.0;acl "permission:System: Delete Certmap Rules";allow (delete) groupdn = "ldap:///cn=System: Delete Certmap Rules,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=certmaprules,cn=certmap,dc=ipa,dc=example
aci: (targetattr = "associateddomain || cn || description || ipacertmapmaprule || ipacertmapmatchrule || ipacertmappriority || ipaenabledflag || objectclass")(targetfilter = "(objectclass=ipacertmaprule)")(version 3.0;acl "permission:System: Modify Certmap Rules";allow (write) groupdn = "ldap:///cn=System: Modify Certmap Rules,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=certmaprules,cn=certmap,dc=ipa,dc=example
aci: (targetattr = "associateddomain || cn || createtimestamp || description || entryusn || ipacertmapmaprule || ipacertmapmatchrule || ipacertmappriority || ipaenabledflag || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipacertmaprule)")(version 3.0;acl "permission:System: Read Certmap Rules";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
@ -337,6 +349,8 @@ aci: (targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:S
dn: cn=users,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "krbprincipalkey || passwordhistory || sambalmpassword || sambantpassword || userpassword")(targetfilter = "(&(!(memberOf=cn=admins,cn=groups,cn=accounts,dc=ipa,dc=example))(objectclass=posixaccount))")(version 3.0;acl "permission:System: Change User password";allow (write) groupdn = "ldap:///cn=System: Change User password,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=users,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "ipacertmapdata || objectclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage User Certificate Mappings";allow (write) groupdn = "ldap:///cn=System: Manage User Certificate Mappings,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=users,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "usercertificate")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage User Certificates";allow (write) groupdn = "ldap:///cn=System: Manage User Certificates,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=users,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "krbcanonicalname || krbprincipalname")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage User Principals";allow (write) groupdn = "ldap:///cn=System: Manage User Principals,cn=permissions,cn=pbac,dc=ipa,dc=example";)
@ -347,7 +361,7 @@ aci: (targetattr = "businesscategory || carlicense || cn || departmentnumber ||
dn: cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,dc=ipa,dc=example
aci: (targetattr = "*")(target = "ldap:///cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read UPG Definition";allow (compare,read,search) groupdn = "ldap:///cn=System: Read UPG Definition,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=users,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "audio || businesscategory || carlicense || departmentnumber || destinationindicator || employeenumber || employeetype || facsimiletelephonenumber || homephone || homepostaladdress || inetuserhttpurl || inetuserstatus || internationalisdnnumber || jpegphoto || l || labeleduri || mail || mobile || o || ou || pager || photo || physicaldeliveryofficename || postaladdress || postalcode || postofficebox || preferreddeliverymethod || preferredlanguage || registeredaddress || roomnumber || secretary || seealso || st || street || telephonenumber || teletexterminalidentifier || telexnumber || usercertificate || usersmimecertificate || x121address || x500uniqueidentifier")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User Addressbook Attributes";allow (compare,read,search) userdn = "ldap:///all";)
aci: (targetattr = "audio || businesscategory || carlicense || departmentnumber || destinationindicator || employeenumber || employeetype || facsimiletelephonenumber || homephone || homepostaladdress || inetuserhttpurl || inetuserstatus || internationalisdnnumber || ipacertmapdata || jpegphoto || l || labeleduri || mail || mobile || o || ou || pager || photo || physicaldeliveryofficename || postaladdress || postalcode || postofficebox || preferreddeliverymethod || preferredlanguage || registeredaddress || roomnumber || secretary || seealso || st || street || telephonenumber || teletexterminalidentifier || telexnumber || usercertificate || usersmimecertificate || x121address || x500uniqueidentifier")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User Addressbook Attributes";allow (compare,read,search) userdn = "ldap:///all";)
dn: dc=ipa,dc=example
aci: (targetattr = "cn || createtimestamp || entryusn || gecos || gidnumber || homedirectory || loginshell || modifytimestamp || objectclass || uid || uidnumber")(target = "ldap:///cn=users,cn=compat,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read User Compat Tree";allow (compare,read,search) userdn = "ldap:///anyone";)
dn: cn=users,cn=accounts,dc=ipa,dc=example

181
API.txt
View File

@ -824,6 +824,116 @@ option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: certmapconfig_mod/1
args: 0,8,3
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('delattr*', cli_name='delattr')
option: Bool('ipacertmappromptusername?', autofill=False, cli_name='promptusername')
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Flag('rights', autofill=True, default=False)
option: Str('setattr*', cli_name='setattr')
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: certmapconfig_show/1
args: 0,4,3
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Flag('rights', autofill=True, default=False)
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: certmaprule_add/1
args: 1,11,3
arg: Str('cn', cli_name='rulename')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: DNSNameParam('associateddomain*', cli_name='domain')
option: Str('description?', cli_name='desc')
option: Str('ipacertmapmaprule?', cli_name='maprule')
option: Str('ipacertmapmatchrule?', cli_name='matchrule')
option: Int('ipacertmappriority?', cli_name='priority')
option: Flag('ipaenabledflag?', autofill=True, default=True)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Str('setattr*', cli_name='setattr')
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: certmaprule_del/1
args: 1,2,3
arg: Str('cn+', cli_name='rulename')
option: Flag('continue', autofill=True, cli_name='continue', default=False)
option: Str('version?')
output: Output('result', type=[<type 'dict'>])
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: ListOfPrimaryKeys('value')
command: certmaprule_disable/1
args: 1,1,3
arg: Str('cn', cli_name='rulename')
option: Str('version?')
output: Output('result', type=[<type 'bool'>])
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: certmaprule_enable/1
args: 1,1,3
arg: Str('cn', cli_name='rulename')
option: Str('version?')
output: Output('result', type=[<type 'bool'>])
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: certmaprule_find/1
args: 1,13,4
arg: Str('criteria?')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: DNSNameParam('associateddomain*', autofill=False, cli_name='domain')
option: Str('cn?', autofill=False, cli_name='rulename')
option: Str('description?', autofill=False, cli_name='desc')
option: Str('ipacertmapmaprule?', autofill=False, cli_name='maprule')
option: Str('ipacertmapmatchrule?', autofill=False, cli_name='matchrule')
option: Int('ipacertmappriority?', autofill=False, cli_name='priority')
option: Bool('ipaenabledflag?', autofill=False, default=True)
option: Flag('pkey_only?', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Int('sizelimit?', autofill=False)
option: Int('timelimit?', autofill=False)
option: Str('version?')
output: Output('count', type=[<type 'int'>])
output: ListOfEntries('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: Output('truncated', type=[<type 'bool'>])
command: certmaprule_mod/1
args: 1,13,3
arg: Str('cn', cli_name='rulename')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: DNSNameParam('associateddomain*', autofill=False, cli_name='domain')
option: Str('delattr*', cli_name='delattr')
option: Str('description?', autofill=False, cli_name='desc')
option: Str('ipacertmapmaprule?', autofill=False, cli_name='maprule')
option: Str('ipacertmapmatchrule?', autofill=False, cli_name='matchrule')
option: Int('ipacertmappriority?', autofill=False, cli_name='priority')
option: Flag('ipaenabledflag?', autofill=True, default=True)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Flag('rights', autofill=True, default=False)
option: Str('setattr*', cli_name='setattr')
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: certmaprule_show/1
args: 1,4,3
arg: Str('cn', cli_name='rulename')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: Flag('rights', autofill=True, default=False)
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: certprofile_del/1
args: 1,2,3
arg: Str('cn+', cli_name='id')
@ -4762,6 +4872,20 @@ option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: stageuser_add_certmapdata/1
args: 2,7,3
arg: Str('uid', cli_name='login')
arg: Str('ipacertmapdata*', alwaysask=False, cli_name='certmapdata')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Bytes('certificate*', cli_name='certificate')
option: DNParam('issuer?', cli_name='issuer')
option: Flag('no_members', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: DNParam('subject?', cli_name='subject')
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: stageuser_add_manager/1
args: 1,5,3
arg: Str('uid', cli_name='login')
@ -4915,6 +5039,20 @@ option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: stageuser_remove_certmapdata/1
args: 2,7,3
arg: Str('uid', cli_name='login')
arg: Str('ipacertmapdata*', alwaysask=False, cli_name='certmapdata')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Bytes('certificate*', cli_name='certificate')
option: DNParam('issuer?', cli_name='issuer')
option: Flag('no_members', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: DNParam('subject?', cli_name='subject')
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: stageuser_remove_manager/1
args: 1,5,3
arg: Str('uid', cli_name='login')
@ -5796,6 +5934,20 @@ option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: user_add_certmapdata/1
args: 2,7,3
arg: Str('uid', cli_name='login')
arg: Str('ipacertmapdata*', alwaysask=False, cli_name='certmapdata')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Bytes('certificate*', cli_name='certificate')
option: DNParam('issuer?', cli_name='issuer')
option: Flag('no_members', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: DNParam('subject?', cli_name='subject')
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: user_add_manager/1
args: 1,5,3
arg: Str('uid', cli_name='login')
@ -5968,6 +6120,20 @@ option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: user_remove_certmapdata/1
args: 2,7,3
arg: Str('uid', cli_name='login')
arg: Str('ipacertmapdata*', alwaysask=False, cli_name='certmapdata')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Bytes('certificate*', cli_name='certificate')
option: DNParam('issuer?', cli_name='issuer')
option: Flag('no_members', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
option: DNParam('subject?', cli_name='subject')
option: Str('version?')
output: Entry('result')
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: user_remove_manager/1
args: 1,5,3
arg: Str('uid', cli_name='login')
@ -6351,6 +6517,17 @@ default: cert_request/1
default: cert_revoke/1
default: cert_show/1
default: cert_status/1
default: certmapconfig/1
default: certmapconfig_mod/1
default: certmapconfig_show/1
default: certmaprule/1
default: certmaprule_add/1
default: certmaprule_del/1
default: certmaprule_disable/1
default: certmaprule_enable/1
default: certmaprule_find/1
default: certmaprule_mod/1
default: certmaprule_show/1
default: certprofile/1
default: certprofile_del/1
default: certprofile_find/1
@ -6706,12 +6883,14 @@ default: stageuser/1
default: stageuser_activate/1
default: stageuser_add/1
default: stageuser_add_cert/1
default: stageuser_add_certmapdata/1
default: stageuser_add_manager/1
default: stageuser_add_principal/1
default: stageuser_del/1
default: stageuser_find/1
default: stageuser_mod/1
default: stageuser_remove_cert/1
default: stageuser_remove_certmapdata/1
default: stageuser_remove_manager/1
default: stageuser_remove_principal/1
default: stageuser_show/1
@ -6789,6 +6968,7 @@ default: trustdomain_mod/1
default: user/1
default: user_add/1
default: user_add_cert/1
default: user_add_certmapdata/1
default: user_add_manager/1
default: user_add_principal/1
default: user_del/1
@ -6797,6 +6977,7 @@ default: user_enable/1
default: user_find/1
default: user_mod/1
default: user_remove_cert/1
default: user_remove_certmapdata/1
default: user_remove_manager/1
default: user_remove_principal/1
default: user_show/1

View File

@ -73,8 +73,8 @@ define(IPA_DATA_VERSION, 20100614120000)
# #
########################################################
define(IPA_API_VERSION_MAJOR, 2)
define(IPA_API_VERSION_MINOR, 218)
# Last change: Remove no_option flag for nsaccountlock and add cli_name='disabled'
define(IPA_API_VERSION_MINOR, 219)
# Last change: Support for Certificate Identity Mapping
########################################################

View File

@ -0,0 +1,14 @@
## IPA Base OID:
##
## Attributes: 2.16.840.1.113730.3.8.22.1.x
## ObjectClasses: 2.16.840.1.113730.3.8.22.2.y
##
dn: cn=schema
attributeTypes: (2.16.840.1.113730.3.8.22.1.1 NAME 'ipaCertMapPromptUsername' DESC 'Prompt for the username when multiple identities are mapped to a certificate' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v4.5' )
attributeTypes: (2.16.840.1.113730.3.8.22.1.2 NAME 'ipaCertMapMapRule' DESC 'Certificate Mapping Rule' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v4.5' )
attributeTypes: (2.16.840.1.113730.3.8.22.1.3 NAME 'ipaCertMapMatchRule' DESC 'Certificate Matching Rule' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v4.5' )
attributeTypes: (2.16.840.1.113730.3.8.22.1.4 NAME 'ipaCertMapData' DESC 'Certificate Mapping Data' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.5' )
attributeTypes: (2.16.840.1.113730.3.8.22.1.5 NAME 'ipaCertMapPriority' DESC 'Rule priority' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA v4.5' )
objectClasses: (2.16.840.1.113730.3.8.22.2.1 NAME 'ipaCertMapConfigObject' DESC 'IPA Certificate Mapping global config options' AUXILIARY MAY ipaCertMapPromptUsername X-ORIGIN 'IPA v4.5' )
objectClasses: (2.16.840.1.113730.3.8.22.2.2 NAME 'ipaCertMapRule' DESC 'IPA Certificate Mapping rule' SUP top STRUCTURAL MUST cn MAY ( description $ ipaCertMapMapRule $ ipaCertMapMatchRule $ associatedDomain $ ipaCertMapPriority $ ipaEnabledFlag ) X-ORIGIN 'IPA v4.5' )
objectClasses: (2.16.840.1.113730.3.8.22.2.3 NAME 'ipaCertMapObject' DESC 'IPA Object for Certificate Mapping' AUXILIARY MAY ipaCertMapData X-ORIGIN 'IPA v4.5' )

View File

@ -27,6 +27,7 @@ dist_app_DATA = \
70topology.ldif \
71idviews.ldif \
72domainlevels.ldif \
73certmap.ldif \
anon-princ-aci.ldif \
bootstrap-template.ldif \
ca-topology.uldif \

View File

@ -0,0 +1,23 @@
# Configuration for Certificate Identity Mapping
dn: cn=certmap,$SUFFIX
default:objectclass: top
default:objectclass: nsContainer
default:objectclass: ipaCertMapConfigObject
default:cn: certmap
default:ipaCertMapPromptUsername: FALSE
dn: cn=certmaprules,cn=certmap,$SUFFIX
default:objectclass: top
default:objectclass: nsContainer
default:cn: certmaprules
# Certificate Identity Mapping Administrators
dn: cn=Certificate Identity Mapping Administrators,cn=privileges,cn=pbac,$SUFFIX
default:objectClass: top
default:objectClass: groupofnames
default:objectClass: nestedgroup
default:cn: Certificate Identity Mapping Administrators
default:description: Certificate Identity Mapping Administrators
dn: $SUFFIX
add:aci: (targetattr = "ipacertmapdata")(targattrfilters="add=objectclass:(objectclass=ipacertmapobject)")(version 3.0;acl "selfservice:Users can manage their own X.509 certificate identity mappings";allow (write) userdn = "ldap:///self";)

View File

@ -61,6 +61,7 @@ app_DATA = \
72-domainlevels.update \
73-custodia.update \
73-winsync.update \
73-certmap.update \
90-post_upgrade_plugins.update \
$(NULL)

View File

@ -122,6 +122,8 @@ DEFAULT_CONFIG = (
('container_dnsservers', DN(('cn', 'servers'), ('cn', 'dns'))),
('container_custodia', DN(('cn', 'custodia'), ('cn', 'ipa'), ('cn', 'etc'))),
('container_sysaccounts', DN(('cn', 'sysaccounts'), ('cn', 'etc'))),
('container_certmap', DN(('cn', 'certmap'))),
('container_certmaprules', DN(('cn', 'certmaprules'), ('cn', 'certmap'))),
# Ports, hosts, and URIs:
('xmlrpc_uri', 'http://localhost:8888/ipa/xml'),

View File

@ -1155,9 +1155,15 @@ class DN(object):
def _get_rdn(self, rdn):
return self.RDN_type(*rdn, **{'raw': True})
def __str__(self):
def ldap_text(self):
return dn2str(self.rdns)
def x500_text(self):
return dn2str(reversed(self.rdns))
def __str__(self):
return self.ldap_text()
def __repr__(self):
return "%s.%s('%s')" % (self.__module__, self.__class__.__name__, self.__str__())

View File

@ -70,6 +70,7 @@ IPA_SCHEMA_FILES = ("60kerberos.ldif",
"70topology.ldif",
"71idviews.ldif",
"72domainlevels.ldif",
"73certmap.ldif",
"15rfc2307bis.ldif",
"15rfc4876.ldif")

View File

@ -19,14 +19,17 @@
import six
from ipalib import api, errors
from ipalib import Flag, Int, Password, Str, Bool, StrEnum, DateTime, Bytes
from ipalib import api, errors, x509
from ipalib import (
Flag, Int, Password, Str, Bool, StrEnum, DateTime, Bytes, DNParam)
from ipalib.parameters import Principal
from ipalib.plugable import Registry
from .baseldap import (
DN, LDAPObject, LDAPCreate, LDAPUpdate, LDAPSearch, LDAPDelete,
LDAPRetrieve, LDAPAddAttribute, LDAPRemoveAttribute, LDAPAddMember,
LDAPRemoveMember, LDAPAddAttributeViaOption, LDAPRemoveAttributeViaOption)
LDAPRetrieve, LDAPAddAttribute, LDAPModAttribute, LDAPRemoveAttribute,
LDAPAddMember, LDAPRemoveMember,
LDAPAddAttributeViaOption, LDAPRemoveAttributeViaOption,
add_missing_object_class)
from ipaserver.plugins.service import (
validate_certificate, validate_realm, normalize_principal)
from ipalib.request import context
@ -134,7 +137,7 @@ class baseuser(LDAPObject):
object_class_config = 'ipauserobjectclasses'
possible_objectclasses = [
'meporiginentry', 'ipauserauthtypeclass', 'ipauser',
'ipatokenradiusproxyuser'
'ipatokenradiusproxyuser', 'ipacertmapobject'
]
disallow_object_classes = ['krbticketpolicyaux']
permission_filter_objectclasses = ['posixaccount']
@ -146,7 +149,8 @@ class baseuser(LDAPObject):
'memberofindirect', 'ipauserauthtype', 'userclass',
'ipatokenradiusconfiglink', 'ipatokenradiususername',
'krbprincipalexpiration', 'usercertificate;binary',
'krbprincipalname', 'krbcanonicalname'
'krbprincipalname', 'krbcanonicalname',
'ipacertmapdata'
]
search_display_attributes = [
'uid', 'givenname', 'sn', 'homedirectory', 'krbcanonicalname',
@ -360,6 +364,13 @@ class baseuser(LDAPObject):
label=_('Certificate'),
doc=_('Base-64 encoded user certificate'),
),
Str(
'ipacertmapdata*',
cli_name='certmapdata',
label=_('Certificate mapping data'),
doc=_('Certificate mapping data'),
flags=['no_create', 'no_update', 'no_search'],
),
)
def normalize_and_validate_email(self, email, config=None):
@ -728,3 +739,154 @@ class baseuser_remove_cert(LDAPRemoveAttributeViaOption):
self.obj.convert_usercertificate_post(entry_attrs, **options)
return dn
class ModCertMapData(LDAPModAttribute):
attribute = 'ipacertmapdata'
takes_options = (
DNParam(
'issuer?',
cli_name='issuer',
label=_('Issuer'),
doc=_('Issuer of the certificate'),
flags=['virtual_attribute']
),
DNParam(
'subject?',
cli_name='subject',
label=_('Subject'),
doc=_('Subject of the certificate'),
flags=['virtual_attribute']
),
Bytes(
'certificate*', validate_certificate,
cli_name='certificate',
label=_('Certificate'),
doc=_('Base-64 encoded user certificate'),
flags=['virtual_attribute']
),
)
@staticmethod
def _build_mapdata(subject, issuer):
return u'X509:<I>{issuer}<S>{subject}'.format(
issuer=issuer.x500_text(), subject=subject.x500_text())
@classmethod
def _convert_options_to_certmap(cls, entry_attrs, issuer=None,
subject=None, certificates=()):
"""
Converts options to ipacertmapdata
When --subject --issuer or --certificate options are used,
the value for ipacertmapdata is built from extracting subject and
issuer,
converting their values to X500 ordering and using the format
X509:<I>issuer<S>subject
For instance:
X509:<I>O=DOMAIN,CN=Certificate Authority<S>O=DOMAIN,CN=user
A list of values can be returned if --certificate is used multiple
times, or in conjunction with --subject --issuer.
"""
data = []
data.extend(entry_attrs.get(cls.attribute, list()))
if issuer or subject:
data.append(cls._build_mapdata(subject, issuer))
for dercert in certificates:
cert = x509.load_certificate(dercert, x509.DER)
issuer = DN(cert.issuer)
subject = DN(cert.subject)
if not subject:
raise errors.ValidationError(
name='certificate',
error=_('cannot have an empty subject'))
data.append(cls._build_mapdata(subject, issuer))
entry_attrs[cls.attribute] = data
def get_args(self):
# ipacertmapdata is not mandatory as it can be built
# from the values subject+issuer or from reading certificate
for arg in super(ModCertMapData, self).get_args():
if arg.name == 'ipacertmapdata':
yield arg.clone(required=False, alwaysask=False)
else:
yield arg.clone()
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
**options):
# The 3 valid calls are
# ipa user-add-certmapdata LOGIN --subject xx --issuer yy
# ipa user-add-certmapdata LOGIN [DATA] --certificate xx
# ipa user-add-certmapdata LOGIN DATA
# Check that at least one of the 3 formats is used
try:
certmapdatas = keys[1] or []
except IndexError:
certmapdatas = []
issuer = options.get('issuer')
subject = options.get('subject')
certificates = options.get('certificate', [])
# If only LOGIN is supplied, then we need either subject or issuer or
# certificate
if (not certmapdatas and not issuer and not subject and
not certificates):
raise errors.RequirementError(name='ipacertmapdata')
# If subject or issuer is provided, other options are not allowed
if subject or issuer:
if certificates:
raise errors.MutuallyExclusiveError(
reason=_('cannot specify both subject/issuer '
'and certificate'))
if certmapdatas:
raise errors.MutuallyExclusiveError(
reason=_('cannot specify both subject/issuer '
'and ipacertmapdata'))
# If subject or issuer is provided, then the other one is required
if not subject:
raise errors.RequirementError(name='subject')
if not issuer:
raise errors.RequirementError(name='issuer')
# if the command is called with --subject --issuer or --certificate
# we need to add ipacertmapdata to the attrs_list in order to
# display the resulting value in the command output
if 'ipacertmapdata' not in attrs_list:
attrs_list.append('ipacertmapdata')
self._convert_options_to_certmap(
entry_attrs,
issuer=issuer,
subject=subject,
certificates=certificates)
return dn
class baseuser_add_certmapdata(ModCertMapData, LDAPAddAttribute):
__doc__ = _("Add one or more certificate mappings to the user entry.")
msg_summary = _('Added certificate mappings to user "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
**options):
dn = super(baseuser_add_certmapdata, self).pre_callback(
ldap, dn, entry_attrs, attrs_list, *keys, **options)
# The objectclass ipacertmapobject may not be present on
# existing user entries. We need to add it if we define a new
# value for ipacertmapdata
add_missing_object_class(ldap, u'ipacertmapobject', dn)
return dn
class baseuser_remove_certmapdata(ModCertMapData,
LDAPRemoveAttribute):
__doc__ = _("Remove one or more certificate mappings from the user entry.")
msg_summary = _('Removed certificate mappings from user "%(value)s"')

View File

@ -0,0 +1,391 @@
# Authors:
# Florence Blanc-Renaud <flo@redhat.com>
#
# Copyright (C) 2017 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import six
from ipalib import api, errors
from ipalib.parameters import Bool, DNSNameParam, Flag, Int, Str
from ipalib.plugable import Registry
from .baseldap import (
LDAPCreate,
LDAPDelete,
LDAPObject,
LDAPQuery,
LDAPRetrieve,
LDAPSearch,
LDAPUpdate,
pkey_to_value)
from ipalib import _, ngettext
from ipalib import output
if six.PY3:
unicode = str
__doc__ = _("""
Certificate Identity Mapping
""") + _("""
Manage Certificate Identity Mapping configuration and rules.
""") + _("""
IPA supports the use of certificates for authentication. Certificates can
either be stored in the user entry (full certificate in the usercertificate
attribute), or simply linked to the user entry through a mapping.
This code enables the management of the rules allowing to link a
certificate to a user entry.
""") + _("""
EXAMPLES:
""") + _("""
Display the Certificate Identity Mapping global configuration:
ipa certmapconfig-show
""") + _("""
Modify Certificate Identity Mapping global configuration:
ipa certmapconfig-mod --promptusername=TRUE
""") + _("""
Create a new Certificate Identity Mapping Rule:
ipa certmaprule-add rule1 --desc="Link certificate with subject and issuer"
""") + _("""
Modify a Certificate Identity Mapping Rule:
ipa certmaprule-mod rule1 --maprule="<ALT-SEC-ID-I-S:altSecurityIdentities>"
""") + _("""
Disable a Certificate Identity Mapping Rule:
ipa certmaprule-disable rule1
""") + _("""
Enable a Certificate Identity Mapping Rule:
ipa certmaprule-enable rule1
""") + _("""
Display information about a Certificate Identity Mapping Rule:
ipa certmaprule-show rule1
""") + _("""
Find all Certificate Identity Mapping Rules with the specified domain:
ipa certmaprule-find --domain example.com
""") + _("""
Delete a Certificate Identity Mapping Rule:
ipa certmaprule-del rule1
""")
register = Registry()
def check_associateddomain_is_trusted(api_inst, options):
"""
Check that the associateddomain in options are either IPA domain or
a trusted domain.
:param api_inst: API instance
:param associateddomain: domains to be checked
:raises: ValidationError if the domain is neither IPA domain nor trusted
"""
domains = options.get('associateddomain')
if domains:
trust_suffix_namespace = set()
trust_suffix_namespace.add(api_inst.env.domain.lower())
trust_objects = api_inst.Command.trust_find(sizelimit=0)['result']
for obj in trust_objects:
trustdomains = api_inst.Command.trustdomain_find(
obj['cn'][0], sizelimit=0)['result']
for domain in trustdomains:
trust_suffix_namespace.add(domain['cn'][0].lower())
for dom in domains:
if not str(dom).lower() in trust_suffix_namespace:
raise errors.ValidationError(
name=_('domain'),
error=_('The domain %s is neither IPA domain nor a trusted'
'domain.') % dom
)
@register()
class certmapconfig(LDAPObject):
"""
Certificate Identity Mapping configuration object
"""
object_name = _('Certificate Identity Mapping configuration options')
default_attributes = ['ipacertmappromptusername']
container_dn = api.env.container_certmap
label = _('Certificate Identity Mapping Global Configuration')
label_singular = _('Certificate Identity Mapping Global Configuration')
takes_params = (
Bool(
'ipacertmappromptusername',
cli_name='promptusername',
label=_('Prompt for the username'),
doc=_('Prompt for the username when multiple identities'
' are mapped to a certificate'),
),
)
permission_filter_objectclasses = ['ipacertmapconfigobject']
managed_permissions = {
'System: Read Certmap Configuration': {
'replaces_global_anonymous_aci': True,
'ipapermbindruletype': 'all',
'ipapermright': {'read', 'search', 'compare'},
'ipapermdefaultattr': {
'ipacertmappromptusername',
'cn',
},
},
'System: Modify Certmap Configuration': {
'replaces_global_anonymous_aci': True,
'ipapermright': {'write'},
'ipapermdefaultattr': {
'ipacertmappromptusername',
},
'default_privileges': {
'Certificate Identity Mapping Administrators'},
},
}
@register()
class certmapconfig_mod(LDAPUpdate):
__doc__ = _('Modify Certificate Identity Mapping configuration.')
@register()
class certmapconfig_show(LDAPRetrieve):
__doc__ = _('Show the current Certificate Identity Mapping configuration.')
@register()
class certmaprule(LDAPObject):
"""
Certificate Identity Mapping Rules
"""
label = _('Certificate Identity Mapping Rules')
label_singular = _('Certificate Identity Mapping Rule')
object_name = _('Certificate Identity Mapping Rule')
object_name_plural = _('Certificate Identity Mapping Rules')
object_class = ['ipacertmaprule']
container_dn = api.env.container_certmaprules
default_attributes = [
'cn', 'description',
'ipacertmapmaprule',
'ipacertmapmatchrule',
'associateddomain',
'ipacertmappriority',
'ipaenabledflag'
]
search_attributes = [
'cn', 'description',
'ipacertmapmaprule',
'ipacertmapmatchrule',
'associateddomain',
'ipacertmappriority',
'ipaenabledflag'
]
takes_params = (
Str(
'cn',
cli_name='rulename',
primary_key=True,
label=_('Rule name'),
doc=_('Certificate Identity Mapping Rule name'),
),
Str(
'description?',
cli_name='desc',
label=_('Description'),
doc=_('Certificate Identity Mapping Rule description'),
),
Str(
'ipacertmapmaprule?',
cli_name='maprule',
label=_('Mapping rule'),
doc=_('Rule used to map the certificate with a user entry'),
),
Str(
'ipacertmapmatchrule?',
cli_name='matchrule',
label=_('Matching rule'),
doc=_('Rule used to check if a certificate can be used for'
' authentication'),
),
DNSNameParam(
'associateddomain*',
cli_name='domain',
label=_('Domain name'),
doc=_('Domain where the user entry will be searched'),
),
Int(
'ipacertmappriority?',
cli_name='priority',
label=_('Priority'),
doc=_('Priority of the rule (higher number means lower priority'),
minvalue=0,
),
Flag(
'ipaenabledflag?',
label=_('Enabled'),
flags=['no_option'],
default=True
),
)
permission_filter_objectclasses = ['ipacertmaprule']
managed_permissions = {
'System: Add Certmap Rules': {
'replaces_global_anonymous_aci': True,
'ipapermright': {'add'},
'default_privileges': {
'Certificate Identity Mapping Administrators'},
},
'System: Read Certmap Rules': {
'replaces_global_anonymous_aci': True,
'ipapermbindruletype': 'all',
'ipapermright': {'read', 'search', 'compare'},
'ipapermdefaultattr': {
'objectclass', 'cn', 'description',
'ipacertmapmaprule', 'ipacertmapmatchrule', 'associateddomain',
'ipacertmappriority', 'ipaenabledflag',
},
},
'System: Delete Certmap Rules': {
'replaces_global_anonymous_aci': True,
'ipapermright': {'delete'},
'default_privileges': {
'Certificate Identity Mapping Administrators'},
},
'System: Modify Certmap Rules': {
'replaces_global_anonymous_aci': True,
'ipapermright': {'write'},
'ipapermdefaultattr': {
'objectclass', 'cn', 'description',
'ipacertmapmaprule', 'ipacertmapmatchrule', 'associateddomain',
'ipacertmappriority', 'ipaenabledflag',
},
'default_privileges': {
'Certificate Identity Mapping Administrators'},
},
}
@register()
class certmaprule_add(LDAPCreate):
__doc__ = _('Create a new Certificate Identity Mapping Rule.')
msg_summary = _('Added Certificate Identity Mapping Rule "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
**options):
check_associateddomain_is_trusted(self.api, options)
return dn
@register()
class certmaprule_mod(LDAPUpdate):
__doc__ = _('Modify a Certificate Identity Mapping Rule.')
msg_summary = _('Modified Certificate Identity Mapping Rule "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
**options):
check_associateddomain_is_trusted(self.api, options)
return dn
@register()
class certmaprule_find(LDAPSearch):
__doc__ = _('Search for Certificate Identity Mapping Rules.')
msg_summary = ngettext(
'%(count)d Certificate Identity Mapping Rule matched',
'%(count)d Certificate Identity Mapping Rules matched', 0
)
@register()
class certmaprule_show(LDAPRetrieve):
__doc__ = _('Display information about a Certificate Identity Mapping'
' Rule.')
@register()
class certmaprule_del(LDAPDelete):
__doc__ = _('Delete a Certificate Identity Mapping Rule.')
msg_summary = _('Deleted Certificate Identity Mapping Rule "%(value)s"')
@register()
class certmaprule_enable(LDAPQuery):
__doc__ = _('Enable a Certificate Identity Mapping Rule.')
msg_summary = _('Enabled Certificate Identity Mapping Rule "%(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 certmaprule_disable(LDAPQuery):
__doc__ = _('Disable a Certificate Identity Mapping Rule.')
msg_summary = _('Disabled Certificate Identity Mapping Rule "%(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),
)

View File

@ -44,7 +44,9 @@ from .baseuser import (
baseuser_add_principal,
baseuser_remove_principal,
baseuser_add_manager,
baseuser_remove_manager)
baseuser_remove_manager,
baseuser_add_certmapdata,
baseuser_remove_certmapdata)
from ipalib.request import context
from ipalib.util import set_krbcanonicalname
from ipalib import _, ngettext
@ -772,3 +774,15 @@ class stageuser_add_principal(baseuser_add_principal):
class stageuser_remove_principal(baseuser_remove_principal):
__doc__ = _('Remove principal alias from the stageuser entry')
msg_summary = _('Removed aliases from stageuser "%(value)s"')
@register()
class stageuser_add_certmapdata(baseuser_add_certmapdata):
__doc__ = _("Add one or more certificate mappings to the stage user"
" entry.")
@register()
class stageuser_remove_certmapdata(baseuser_remove_certmapdata):
__doc__ = _("Remove one or more certificate mappings from the stage user"
" entry.")

View File

@ -22,7 +22,6 @@ import time
from time import gmtime, strftime
import posixpath
import os
import six
from ipalib import api
@ -46,7 +45,9 @@ from .baseuser import (
baseuser_add_cert,
baseuser_remove_cert,
baseuser_add_principal,
baseuser_remove_principal)
baseuser_remove_principal,
baseuser_add_certmapdata,
baseuser_remove_certmapdata)
from .idviews import remove_ipaobject_overrides
from ipalib.plugable import Registry
from .baseldap import (
@ -179,6 +180,7 @@ class user(baseuser):
'secretary', 'usercertificate',
'usersmimecertificate', 'x500uniqueidentifier',
'inetuserhttpurl', 'inetuserstatus',
'ipacertmapdata',
},
'fixup_function': fix_addressbook_permission_bindrule,
},
@ -366,6 +368,13 @@ class user(baseuser):
},
'default_privileges': {'PassSync Service'},
},
'System: Manage User Certificate Mappings': {
'ipapermright': {'write'},
'ipapermdefaultattr': {'ipacertmapdata', 'objectclass'},
'default_privileges': {
'Certificate Identity Mapping Administrators'
},
},
}
takes_params = baseuser.takes_params + (
@ -1184,6 +1193,16 @@ class user_remove_cert(baseuser_remove_cert):
msg_summary = _('Removed certificates from user "%(value)s"')
@register()
class user_add_certmapdata(baseuser_add_certmapdata):
__doc__ = _("Add one or more certificate mappings to the user entry.")
@register()
class user_remove_certmapdata(baseuser_remove_certmapdata):
__doc__ = _("Remove one or more certificate mappings from the user entry.")
@register()
class user_add_manager(baseuser_add_manager):
__doc__ = _("Add a manager to the user entry")

View File

@ -1184,6 +1184,26 @@ class TestDN(unittest.TestCase):
self.assertFalse(dn3_a in s)
self.assertFalse(dn3_b in s)
def test_x500_text(self):
# null DN x500 ordering and LDAP ordering are the same
nulldn = DN()
self.assertEqual(nulldn.ldap_text(), nulldn.x500_text())
# reverse a DN with a single RDN
self.assertEqual(self.dn1.ldap_text(), self.dn1.x500_text())
# reverse a DN with 2 RDNs
dn3_x500 = self.dn3.x500_text()
dn3_rev = DN(self.rdn2, self.rdn1)
self.assertEqual(dn3_rev.ldap_text(), dn3_x500)
# reverse a longer DN
longdn_x500 = self.base_container_dn.x500_text()
longdn_rev = DN(longdn_x500)
l = len(self.base_container_dn)
for i in range(l):
self.assertEquals(longdn_rev[i], self.base_container_dn[l-1-i])
class TestEscapes(unittest.TestCase):
def setUp(self):