From 979947f7f21749b45176c39f66060564e19466e3 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale Date: Mon, 18 May 2015 22:11:52 -0400 Subject: Add usercertificate attribute to user plugin Part of: https://fedorahosted.org/freeipa/tickets/4938 Reviewed-By: Martin Basti --- ACI.txt | 2 +- API.txt | 18 ++++++++++++------ install/share/default-aci.ldif | 1 + install/updates/20-aci.update | 4 ++++ ipalib/plugins/baseuser.py | 10 ++++++++-- ipalib/plugins/user.py | 2 +- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/ACI.txt b/ACI.txt index 543d8da69..59173ac1b 100644 --- a/ACI.txt +++ b/ACI.txt @@ -297,7 +297,7 @@ aci: (targetattr = "krbprincipalkey || passwordhistory || sambalmpassword || sam dn: cn=users,cn=accounts,dc=ipa,dc=example aci: (targetattr = "ipasshpubkey")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage User SSH Public Keys";allow (write) groupdn = "ldap:///cn=System: Manage User SSH Public Keys,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=users,cn=accounts,dc=ipa,dc=example -aci: (targetattr = "businesscategory || carlicense || cn || description || displayname || employeetype || facsimiletelephonenumber || gecos || givenname || homephone || inetuserhttpurl || initials || l || labeleduri || loginshell || manager || mepmanagedentry || mobile || objectclass || ou || pager || postalcode || preferredlanguage || roomnumber || secretary || seealso || sn || st || street || telephonenumber || title || userclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Modify Users";allow (write) groupdn = "ldap:///cn=System: Modify Users,cn=permissions,cn=pbac,dc=ipa,dc=example";) +aci: (targetattr = "businesscategory || carlicense || cn || description || displayname || employeetype || facsimiletelephonenumber || gecos || givenname || homephone || inetuserhttpurl || initials || l || labeleduri || loginshell || manager || mepmanagedentry || mobile || objectclass || ou || pager || postalcode || preferredlanguage || roomnumber || secretary || seealso || sn || st || street || telephonenumber || title || usercertificate || userclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Modify Users";allow (write) groupdn = "ldap:///cn=System: Modify Users,cn=permissions,cn=pbac,dc=ipa,dc=example";) 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 diff --git a/API.txt b/API.txt index 81aca14af..abd9407af 100644 --- a/API.txt +++ b/API.txt @@ -3960,7 +3960,7 @@ output: Entry('result', , Gettext('A dictionary representing an LDA output: Output('summary', (, ), None) output: PrimaryKey('value', None, None) command: stageuser_add -args: 1,43,3 +args: 1,44,3 arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', 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') @@ -4002,6 +4002,7 @@ option: Str('street', attribute=True, cli_name='street', multivalue=False, requi option: Str('telephonenumber', attribute=True, cli_name='phone', multivalue=True, required=False) option: Str('title', attribute=True, cli_name='title', multivalue=False, required=False) option: Int('uidnumber', attribute=True, cli_name='uid', minvalue=1, multivalue=False, required=False) +option: Bytes('usercertificate', attribute=True, cli_name='certificate', multivalue=True, required=False) option: Str('userclass', attribute=True, cli_name='class', multivalue=True, required=False) option: Password('userpassword', attribute=True, cli_name='password', exclude='webui', multivalue=False, required=False) option: Str('version?', exclude='webui') @@ -4017,7 +4018,7 @@ output: Output('result', , None) output: Output('summary', (, ), None) output: ListOfPrimaryKeys('value', None, None) command: stageuser_find -args: 1,52,4 +args: 1,53,4 arg: Str('criteria?', noextrawhitespace=False) option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') option: Str('carlicense', attribute=True, autofill=False, cli_name='carlicense', multivalue=True, query=True, required=False) @@ -4068,6 +4069,7 @@ option: Int('timelimit?', autofill=False, minvalue=0) option: Str('title', attribute=True, autofill=False, cli_name='title', multivalue=False, query=True, required=False) option: Str('uid', attribute=True, autofill=False, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=False) option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', minvalue=1, multivalue=False, query=True, required=False) +option: Bytes('usercertificate', attribute=True, autofill=False, cli_name='certificate', multivalue=True, query=True, required=False) option: Str('userclass', attribute=True, autofill=False, cli_name='class', multivalue=True, query=True, required=False) option: Password('userpassword', attribute=True, autofill=False, cli_name='password', exclude='webui', multivalue=False, query=True, required=False) option: Str('version?', exclude='webui') @@ -4076,7 +4078,7 @@ output: ListOfEntries('result', (, ), Gettext('A list output: Output('summary', (, ), None) output: Output('truncated', , None) command: stageuser_mod -args: 1,44,3 +args: 1,45,3 arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', 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') @@ -4119,6 +4121,7 @@ option: Str('street', attribute=True, autofill=False, cli_name='street', multiva option: Str('telephonenumber', attribute=True, autofill=False, cli_name='phone', multivalue=True, required=False) option: Str('title', attribute=True, autofill=False, cli_name='title', multivalue=False, required=False) option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', minvalue=1, multivalue=False, required=False) +option: Bytes('usercertificate', attribute=True, autofill=False, cli_name='certificate', multivalue=True, required=False) option: Str('userclass', attribute=True, autofill=False, cli_name='class', multivalue=True, required=False) option: Password('userpassword', attribute=True, autofill=False, cli_name='password', exclude='webui', multivalue=False, required=False) option: Str('version?', exclude='webui') @@ -4746,7 +4749,7 @@ output: Entry('result', , Gettext('A dictionary representing an LDA output: Output('summary', (, ), None) output: PrimaryKey('value', None, None) command: user_add -args: 1,44,3 +args: 1,45,3 arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', 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') @@ -4789,6 +4792,7 @@ option: Str('street', attribute=True, cli_name='street', multivalue=False, requi option: Str('telephonenumber', attribute=True, cli_name='phone', multivalue=True, required=False) option: Str('title', attribute=True, cli_name='title', multivalue=False, required=False) option: Int('uidnumber', attribute=True, cli_name='uid', minvalue=1, multivalue=False, required=False) +option: Bytes('usercertificate', attribute=True, cli_name='certificate', multivalue=True, required=False) option: Str('userclass', attribute=True, cli_name='class', multivalue=True, required=False) option: Password('userpassword', attribute=True, cli_name='password', exclude='webui', multivalue=False, required=False) option: Str('version?', exclude='webui') @@ -4820,7 +4824,7 @@ output: Output('result', , None) output: Output('summary', (, ), None) output: PrimaryKey('value', None, None) command: user_find -args: 1,55,4 +args: 1,56,4 arg: Str('criteria?', noextrawhitespace=False) option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') option: Str('carlicense', attribute=True, autofill=False, cli_name='carlicense', multivalue=True, query=True, required=False) @@ -4873,6 +4877,7 @@ option: Int('timelimit?', autofill=False, minvalue=0) option: Str('title', attribute=True, autofill=False, cli_name='title', multivalue=False, query=True, required=False) option: Str('uid', attribute=True, autofill=False, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=False) option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', minvalue=1, multivalue=False, query=True, required=False) +option: Bytes('usercertificate', attribute=True, autofill=False, cli_name='certificate', multivalue=True, query=True, required=False) option: Str('userclass', attribute=True, autofill=False, cli_name='class', multivalue=True, query=True, required=False) option: Password('userpassword', attribute=True, autofill=False, cli_name='password', exclude='webui', multivalue=False, query=True, required=False) option: Str('version?', exclude='webui') @@ -4882,7 +4887,7 @@ output: ListOfEntries('result', (, ), Gettext('A list output: Output('summary', (, ), None) output: Output('truncated', , None) command: user_mod -args: 1,45,3 +args: 1,46,3 arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', 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') @@ -4926,6 +4931,7 @@ option: Str('street', attribute=True, autofill=False, cli_name='street', multiva option: Str('telephonenumber', attribute=True, autofill=False, cli_name='phone', multivalue=True, required=False) option: Str('title', attribute=True, autofill=False, cli_name='title', multivalue=False, required=False) option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', minvalue=1, multivalue=False, required=False) +option: Bytes('usercertificate', attribute=True, autofill=False, cli_name='certificate', multivalue=True, required=False) option: Str('userclass', attribute=True, autofill=False, cli_name='class', multivalue=True, required=False) option: Password('userpassword', attribute=True, autofill=False, cli_name='password', exclude='webui', multivalue=False, required=False) option: Str('version?', exclude='webui') diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif index af7eedb0b..7b174e774 100644 --- a/install/share/default-aci.ldif +++ b/install/share/default-aci.ldif @@ -10,6 +10,7 @@ changetype: modify add: aci aci: (targetattr = "givenname || sn || cn || displayname || title || initials || loginshell || gecos || homephone || mobile || pager || facsimiletelephonenumber || telephonenumber || street || roomnumber || l || st || postalcode || manager || secretary || description || carlicense || labeleduri || inetuserhttpurl || seealso || employeetype || businesscategory || ou")(version 3.0;acl "selfservice:User Self service";allow (write) userdn = "ldap:///self";) aci: (targetattr = "ipasshpubkey")(version 3.0;acl "selfservice:Users can manage their own SSH public keys";allow (write) userdn = "ldap:///self";) +aci: (targetattr = "usercertificate")(version 3.0;acl "selfservice:Users can manage their own X.509 certificates";allow (write) userdn = "ldap:///self";) dn: cn=etc,$SUFFIX changetype: modify diff --git a/install/updates/20-aci.update b/install/updates/20-aci.update index fde3afeee..4a8b67c65 100644 --- a/install/updates/20-aci.update +++ b/install/updates/20-aci.update @@ -79,3 +79,7 @@ add:aci: (targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Group add:aci: (targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Entities are allowed to rekey themselves"; allow(write) userdn="ldap:///self";) add:aci: (targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Admins are allowed to rekey any entity"; allow(write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) add:aci: (targetfilter="(|(objectclass=ipaHost)(objectclass=ipaService))")(targetattr="ipaProtectedOperation;write_keys")(version 3.0; acl "Entities are allowed to rekey managed entries"; allow(write) userattr="managedby#USERDN";) + +# User certificates +dn: $SUFFIX +add:aci:(targetattr = "usercertificate")(version 3.0;acl "selfservice:Users can manage their own X.509 certificates";allow (write) userdn = "ldap:///self";) diff --git a/ipalib/plugins/baseuser.py b/ipalib/plugins/baseuser.py index a1be29d83..d2bc68f45 100644 --- a/ipalib/plugins/baseuser.py +++ b/ipalib/plugins/baseuser.py @@ -23,10 +23,11 @@ import posixpath import os from ipalib import api, errors -from ipalib import Flag, Int, Password, Str, Bool, StrEnum, DateTime +from ipalib import Flag, Int, Password, Str, Bool, StrEnum, DateTime, Bytes from ipalib.plugable import Registry from ipalib.plugins.baseldap import DN, LDAPObject, \ LDAPCreate, LDAPUpdate, LDAPSearch, LDAPDelete, LDAPRetrieve +from ipalib.plugins.service import validate_certificate from ipalib.plugins import baseldap from ipalib.request import context from ipalib import _, ngettext @@ -188,7 +189,7 @@ class baseuser(LDAPObject): 'telephonenumber', 'title', 'memberof', 'nsaccountlock', 'memberofindirect', 'ipauserauthtype', 'userclass', 'ipatokenradiusconfiglink', 'ipatokenradiususername', - 'krbprincipalexpiration' + 'krbprincipalexpiration', 'usercertificate', ] search_display_attributes = [ 'uid', 'givenname', 'sn', 'homedirectory', 'loginshell', @@ -383,6 +384,11 @@ class baseuser(LDAPObject): + '(\s*,\s*[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?(;q\=((0(\.[0-9]{0,3})?)|(1(\.0{0,3})?)))?)*)|(\*))$', pattern_errmsg='must match RFC 2068 - 14.4, e.g., "da, en-gb;q=0.8, en;q=0.7"', ), + Bytes('usercertificate*', validate_certificate, + cli_name='certificate', + label=_('Certificate'), + doc=_('Base-64 encoded server certificate'), + ), ) def normalize_and_validate_email(self, email, config=None): diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py index 54d47bb01..119294b19 100644 --- a/ipalib/plugins/user.py +++ b/ipalib/plugins/user.py @@ -267,7 +267,7 @@ class user(baseuser): 'mepmanagedentry', 'mobile', 'objectclass', 'ou', 'pager', 'postalcode', 'roomnumber', 'secretary', 'seealso', 'sn', 'st', 'street', 'telephonenumber', 'title', 'userclass', - 'preferredlanguage', + 'preferredlanguage', 'usercertificate', }, 'replaces': [ '(targetattr = "givenname || sn || cn || displayname || title || initials || loginshell || gecos || homephone || mobile || pager || facsimiletelephonenumber || telephonenumber || street || roomnumber || l || st || postalcode || manager || secretary || description || carlicense || labeleduri || inetuserhttpurl || seealso || employeetype || businesscategory || ou || mepmanagedentry || objectclass")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Users";allow (write) groupdn = "ldap:///cn=Modify Users,cn=permissions,cn=pbac,$SUFFIX";)', -- cgit