summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorence Blanc-Renaud <flo@redhat.com>2016-12-20 16:21:58 +0100
committerDavid Kupka <dkupka@redhat.com>2017-03-02 15:09:42 +0100
commit9e24918c89f30a6d7064844dc0dd848bb35140df (patch)
tree42d9144b5aaba9bb9ee33e0bd405e4734adbcc5e
parent22d7492c94837342a559c368454c223f566490ac (diff)
downloadfreeipa-9e24918c89f30a6d7064844dc0dd848bb35140df.tar.gz
freeipa-9e24918c89f30a6d7064844dc0dd848bb35140df.tar.xz
freeipa-9e24918c89f30a6d7064844dc0dd848bb35140df.zip
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>
-rw-r--r--ACI.txt16
-rw-r--r--API.txt181
-rw-r--r--VERSION.m44
-rw-r--r--install/share/73certmap.ldif14
-rw-r--r--install/share/Makefile.am1
-rw-r--r--install/updates/73-certmap.update23
-rw-r--r--install/updates/Makefile.am1
-rw-r--r--ipalib/constants.py2
-rw-r--r--ipapython/dn.py8
-rw-r--r--ipaserver/install/dsinstance.py1
-rw-r--r--ipaserver/plugins/baseuser.py174
-rw-r--r--ipaserver/plugins/certmap.py391
-rw-r--r--ipaserver/plugins/stageuser.py16
-rw-r--r--ipaserver/plugins/user.py23
-rw-r--r--ipatests/test_ipapython/test_dn.py20
15 files changed, 862 insertions, 13 deletions
diff --git a/ACI.txt b/ACI.txt
index 0b4748953..a36d460b7 100644
--- a/ACI.txt
+++ b/ACI.txt
@@ -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
diff --git a/API.txt b/API.txt
index 3ebebabac..a8f8ff187 100644
--- a/API.txt
+++ b/API.txt
@@ -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
diff --git a/VERSION.m4 b/VERSION.m4
index 8d6671847..8c9327731 100644
--- a/VERSION.m4
+++ b/VERSION.m4
@@ -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
########################################################
diff --git a/install/share/73certmap.ldif b/install/share/73certmap.ldif
new file mode 100644
index 000000000..9c67ccb36
--- /dev/null
+++ b/install/share/73certmap.ldif
@@ -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' )
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index c58e1d2dd..bbf6ce10a 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -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 \
diff --git a/install/updates/73-certmap.update b/install/updates/73-certmap.update
new file mode 100644
index 000000000..ecb3db353
--- /dev/null
+++ b/install/updates/73-certmap.update
@@ -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";)
diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am
index e8a55e173..0ff0edb93 100644
--- a/install/updates/Makefile.am
+++ b/install/updates/Makefile.am
@@ -61,6 +61,7 @@ app_DATA = \
72-domainlevels.update \
73-custodia.update \
73-winsync.update \
+ 73-certmap.update \
90-post_upgrade_plugins.update \
$(NULL)
diff --git a/ipalib/constants.py b/ipalib/constants.py
index bc78422ea..8789a95d0 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -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'),
diff --git a/ipapython/dn.py b/ipapython/dn.py
index 4e8c22bb0..a54629e8b 100644
--- a/ipapython/dn.py
+++ b/ipapython/dn.py
@@ -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__())
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 99e61903d..733dd4006 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -70,6 +70,7 @@ IPA_SCHEMA_FILES = ("60kerberos.ldif",
"70topology.ldif",
"71idviews.ldif",
"72domainlevels.ldif",
+ "73certmap.ldif",
"15rfc2307bis.ldif",
"15rfc4876.ldif")
diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py
index 75cf7d81a..44adc76ec 100644
--- a/ipaserver/plugins/baseuser.py
+++ b/ipaserver/plugins/baseuser.py
@@ -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"')
diff --git a/ipaserver/plugins/certmap.py b/ipaserver/plugins/certmap.py
new file mode 100644
index 000000000..c37eae38e
--- /dev/null
+++ b/ipaserver/plugins/certmap.py
@@ -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),
+ )
diff --git a/ipaserver/plugins/stageuser.py b/ipaserver/plugins/stageuser.py
index 560251486..c7ea478ab 100644
--- a/ipaserver/plugins/stageuser.py
+++ b/ipaserver/plugins/stageuser.py
@@ -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.")
diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
index 88171cf40..2d29dfb11 100644
--- a/ipaserver/plugins/user.py
+++ b/ipaserver/plugins/user.py
@@ -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 + (
@@ -1185,6 +1194,16 @@ class user_remove_cert(baseuser_remove_cert):
@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")
diff --git a/ipatests/test_ipapython/test_dn.py b/ipatests/test_ipapython/test_dn.py
index 3ca3b570a..24b609343 100644
--- a/ipatests/test_ipapython/test_dn.py
+++ b/ipatests/test_ipapython/test_dn.py
@@ -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):