Do not do extra search for ipasshpubkey to generate fingerprints

Host, user and idview commands do unnnecessary extra search for
ipasshpubkey attribute to generate fingerprints.

Note: Host and user plugins shows ipasshpubkey only when the attribute
is changed, idviews show ipasshpubkey always. This behavior has been
kept by this commit.

common_pre/post_callbacks were fixed in [base|stage]user modules.
common_callbacks requires the same arguments as pre/post_callbacks now
(except baseuser_find.post_common_callback)

Note2: in *-add commands there is no need for managing ipasshpubkey as
this attribute should be shown always there.

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

Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
This commit is contained in:
Martin Basti
2016-03-14 17:42:56 +01:00
parent fe2ce02a6f
commit 14ee02dcbd
6 changed files with 115 additions and 35 deletions

View File

@@ -32,8 +32,14 @@ from ipalib.request import context
from ipalib import _ from ipalib import _
from ipapython.ipautil import ipa_generate_password from ipapython.ipautil import ipa_generate_password
from ipapython.ipavalidate import Email from ipapython.ipavalidate import Email
from ipalib.util import (normalize_sshpubkey, validate_sshpubkey, from ipalib.util import (
convert_sshpubkey_post) normalize_sshpubkey,
validate_sshpubkey,
convert_sshpubkey_post,
remove_sshpubkey_from_output_post,
remove_sshpubkey_from_output_list_post,
add_sshpubkey_to_attrs_pre,
)
if six.PY3: if six.PY3:
unicode = str unicode = str
@@ -490,15 +496,16 @@ class baseuser_add(LDAPCreate):
""" """
Prototype command plugin to be implemented by real plugin Prototype command plugin to be implemented by real plugin
""" """
def pre_common_callback(self, ldap, dn, entry_attrs, **options): def pre_common_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
**options):
assert isinstance(dn, DN) assert isinstance(dn, DN)
self.obj.convert_usercertificate_pre(entry_attrs) self.obj.convert_usercertificate_pre(entry_attrs)
def post_common_callback(self, ldap, dn, entry_attrs, **options): def post_common_callback(self, ldap, dn, entry_attrs, *keys, **options):
assert isinstance(dn, DN) assert isinstance(dn, DN)
self.obj.convert_usercertificate_post(entry_attrs, **options) self.obj.convert_usercertificate_post(entry_attrs, **options)
self.obj.get_password_attributes(ldap, dn, entry_attrs) self.obj.get_password_attributes(ldap, dn, entry_attrs)
convert_sshpubkey_post(ldap, dn, entry_attrs) convert_sshpubkey_post(entry_attrs)
radius_dn2pk(self.api, entry_attrs) radius_dn2pk(self.api, entry_attrs)
class baseuser_del(LDAPDelete): class baseuser_del(LDAPDelete):
@@ -565,8 +572,11 @@ class baseuser_mod(LDAPUpdate):
answer = self.api.Object['radiusproxy'].get_dn_if_exists(cl) answer = self.api.Object['radiusproxy'].get_dn_if_exists(cl)
entry_attrs['ipatokenradiusconfiglink'] = answer entry_attrs['ipatokenradiusconfiglink'] = answer
def pre_common_callback(self, ldap, dn, entry_attrs, **options): def pre_common_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
**options):
assert isinstance(dn, DN) assert isinstance(dn, DN)
add_sshpubkey_to_attrs_pre(self.context, attrs_list)
self.check_namelength(ldap, **options) self.check_namelength(ldap, **options)
self.check_mail(entry_attrs) self.check_mail(entry_attrs)
@@ -578,7 +588,7 @@ class baseuser_mod(LDAPUpdate):
self.check_objectclass(ldap, dn, entry_attrs) self.check_objectclass(ldap, dn, entry_attrs)
self.obj.convert_usercertificate_pre(entry_attrs) self.obj.convert_usercertificate_pre(entry_attrs)
def post_common_callback(self, ldap, dn, entry_attrs, **options): def post_common_callback(self, ldap, dn, entry_attrs, *keys, **options):
assert isinstance(dn, DN) assert isinstance(dn, DN)
if options.get('random', False): if options.get('random', False):
try: try:
@@ -589,7 +599,8 @@ class baseuser_mod(LDAPUpdate):
convert_nsaccountlock(entry_attrs) convert_nsaccountlock(entry_attrs)
self.obj.get_password_attributes(ldap, dn, entry_attrs) self.obj.get_password_attributes(ldap, dn, entry_attrs)
self.obj.convert_usercertificate_post(entry_attrs, **options) self.obj.convert_usercertificate_post(entry_attrs, **options)
convert_sshpubkey_post(ldap, dn, entry_attrs) convert_sshpubkey_post(entry_attrs)
remove_sshpubkey_from_output_post(self.context, entry_attrs)
radius_dn2pk(self.api, entry_attrs) radius_dn2pk(self.api, entry_attrs)
class baseuser_find(LDAPSearch): class baseuser_find(LDAPSearch):
@@ -615,6 +626,10 @@ class baseuser_find(LDAPSearch):
if cl in options: if cl in options:
newoptions[cl] = self.api.Object['radiusproxy'].get_dn(options[cl]) newoptions[cl] = self.api.Object['radiusproxy'].get_dn(options[cl])
def pre_common_callback(self, ldap, filters, attrs_list, base_dn, scope,
*args, **options):
add_sshpubkey_to_attrs_pre(self.context, attrs_list)
def post_common_callback(self, ldap, entries, lockout=False, **options): def post_common_callback(self, ldap, entries, lockout=False, **options):
for attrs in entries: for attrs in entries:
self.obj.convert_usercertificate_post(attrs, **options) self.obj.convert_usercertificate_post(attrs, **options)
@@ -622,17 +637,23 @@ class baseuser_find(LDAPSearch):
attrs['nsaccountlock'] = True attrs['nsaccountlock'] = True
else: else:
convert_nsaccountlock(attrs) convert_nsaccountlock(attrs)
convert_sshpubkey_post(ldap, attrs.dn, attrs) convert_sshpubkey_post(attrs)
remove_sshpubkey_from_output_list_post(self.context, entries)
class baseuser_show(LDAPRetrieve): class baseuser_show(LDAPRetrieve):
""" """
Prototype command plugin to be implemented by real plugin Prototype command plugin to be implemented by real plugin
""" """
def post_common_callback(self, ldap, dn, entry_attrs, **options): def pre_common_callback(self, ldap, dn, attrs_list, *keys, **options):
assert isinstance(dn, DN)
add_sshpubkey_to_attrs_pre(self.context, attrs_list)
def post_common_callback(self, ldap, dn, entry_attrs, *keys, **options):
assert isinstance(dn, DN) assert isinstance(dn, DN)
self.obj.get_password_attributes(ldap, dn, entry_attrs) self.obj.get_password_attributes(ldap, dn, entry_attrs)
self.obj.convert_usercertificate_post(entry_attrs, **options) self.obj.convert_usercertificate_post(entry_attrs, **options)
convert_sshpubkey_post(ldap, dn, entry_attrs) convert_sshpubkey_post(entry_attrs)
remove_sshpubkey_from_output_post(self.context, entry_attrs)
radius_dn2pk(self.api, entry_attrs) radius_dn2pk(self.api, entry_attrs)

View File

@@ -44,7 +44,10 @@ from ipalib import x509
from ipalib import output from ipalib import output
from ipalib.request import context from ipalib.request import context
from ipalib.util import (normalize_sshpubkey, validate_sshpubkey_no_options, from ipalib.util import (normalize_sshpubkey, validate_sshpubkey_no_options,
convert_sshpubkey_post, validate_hostname) convert_sshpubkey_post, validate_hostname,
add_sshpubkey_to_attrs_pre,
remove_sshpubkey_from_output_post,
remove_sshpubkey_from_output_list_post)
from ipapython.ipautil import ipa_generate_password, CheckedIPAddress from ipapython.ipautil import ipa_generate_password, CheckedIPAddress
from ipapython.dnsutil import DNSName from ipapython.dnsutil import DNSName
from ipapython.ssh import SSHPublicKey from ipapython.ssh import SSHPublicKey
@@ -712,7 +715,7 @@ class host_add(LDAPCreate):
# fetched anywhere. # fetched anywhere.
entry_attrs['has_keytab'] = False entry_attrs['has_keytab'] = False
convert_sshpubkey_post(ldap, dn, entry_attrs) convert_sshpubkey_post(entry_attrs)
return dn return dn
@@ -927,6 +930,8 @@ class host_mod(LDAPUpdate):
if 'krbticketpolicyaux' not in entry_attrs['objectclass']: if 'krbticketpolicyaux' not in entry_attrs['objectclass']:
entry_attrs['objectclass'].append('krbticketpolicyaux') entry_attrs['objectclass'].append('krbticketpolicyaux')
add_sshpubkey_to_attrs_pre(self.context, attrs_list)
return dn return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options): def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
@@ -947,7 +952,8 @@ class host_mod(LDAPUpdate):
self.obj.suppress_netgroup_memberof(ldap, entry_attrs) self.obj.suppress_netgroup_memberof(ldap, entry_attrs)
convert_sshpubkey_post(ldap, dn, entry_attrs) convert_sshpubkey_post(entry_attrs)
remove_sshpubkey_from_output_post(self.context, entry_attrs)
convert_ipaassignedidview_post(entry_attrs, options) convert_ipaassignedidview_post(entry_attrs, options)
return dn return dn
@@ -1015,6 +1021,8 @@ class host_find(LDAPSearch):
(filter, hosts_filter), ldap.MATCH_ALL (filter, hosts_filter), ldap.MATCH_ALL
) )
add_sshpubkey_to_attrs_pre(self.context, attrs_list)
return (filter.replace('locality', 'l'), base_dn, scope) return (filter.replace('locality', 'l'), base_dn, scope)
def post_callback(self, ldap, entries, truncated, *args, **options): def post_callback(self, ldap, entries, truncated, *args, **options):
@@ -1029,9 +1037,12 @@ class host_find(LDAPSearch):
if options.get('all', False): if options.get('all', False):
entry_attrs['managing'] = self.obj.get_managed_hosts(entry_attrs.dn) entry_attrs['managing'] = self.obj.get_managed_hosts(entry_attrs.dn)
convert_sshpubkey_post(ldap, entry_attrs.dn, entry_attrs) convert_sshpubkey_post(entry_attrs)
remove_sshpubkey_from_output_post(self.context, entry_attrs)
convert_ipaassignedidview_post(entry_attrs, options) convert_ipaassignedidview_post(entry_attrs, options)
remove_sshpubkey_from_output_list_post(self.context, entries)
return truncated return truncated
@@ -1048,6 +1059,11 @@ class host_show(LDAPRetrieve):
member_attributes = ['managedby'] member_attributes = ['managedby']
def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
assert isinstance(dn, DN)
add_sshpubkey_to_attrs_pre(self.context, attrs_list)
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options): def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
assert isinstance(dn, DN) assert isinstance(dn, DN)
self.obj.get_password_attributes(ldap, dn, entry_attrs) self.obj.get_password_attributes(ldap, dn, entry_attrs)
@@ -1065,7 +1081,8 @@ class host_show(LDAPRetrieve):
self.obj.suppress_netgroup_memberof(ldap, entry_attrs) self.obj.suppress_netgroup_memberof(ldap, entry_attrs)
convert_sshpubkey_post(ldap, dn, entry_attrs) convert_sshpubkey_post(entry_attrs)
remove_sshpubkey_from_output_post(self.context, entry_attrs)
convert_ipaassignedidview_post(entry_attrs, options) convert_ipaassignedidview_post(entry_attrs, options)
return dn return dn

View File

@@ -954,7 +954,7 @@ class idoverrideuser_add(baseidoverride_add):
def post_callback(self, ldap, dn, entry_attrs, *keys, **options): def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
dn = super(idoverrideuser_add, self).post_callback(ldap, dn, dn = super(idoverrideuser_add, self).post_callback(ldap, dn,
entry_attrs, *keys, **options) entry_attrs, *keys, **options)
convert_sshpubkey_post(ldap, dn, entry_attrs) convert_sshpubkey_post(entry_attrs)
return dn return dn
@@ -990,7 +990,7 @@ class idoverrideuser_mod(baseidoverride_mod):
def post_callback(self, ldap, dn, entry_attrs, *keys, **options): def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
dn = super(idoverrideuser_mod, self).post_callback(ldap, dn, dn = super(idoverrideuser_mod, self).post_callback(ldap, dn,
entry_attrs, *keys, **options) entry_attrs, *keys, **options)
convert_sshpubkey_post(ldap, dn, entry_attrs) convert_sshpubkey_post(entry_attrs)
return dn return dn
@@ -1004,7 +1004,7 @@ class idoverrideuser_find(baseidoverride_find):
truncated = super(idoverrideuser_find, self).post_callback( truncated = super(idoverrideuser_find, self).post_callback(
ldap, entries, truncated, *args, **options) ldap, entries, truncated, *args, **options)
for entry in entries: for entry in entries:
convert_sshpubkey_post(ldap, entry.dn, entry) convert_sshpubkey_post(entry)
return truncated return truncated
@@ -1015,7 +1015,7 @@ class idoverrideuser_show(baseidoverride_show):
def post_callback(self, ldap, dn, entry_attrs, *keys, **options): def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
dn = super(idoverrideuser_show, self).post_callback(ldap, dn, dn = super(idoverrideuser_show, self).post_callback(ldap, dn,
entry_attrs, *keys, **options) entry_attrs, *keys, **options)
convert_sshpubkey_post(ldap, dn, entry_attrs) convert_sshpubkey_post(entry_attrs)
return dn return dn

View File

@@ -374,7 +374,8 @@ class stageuser_add(baseuser_add):
answer = self.api.Object['radiusproxy'].get_dn_if_exists(cl) answer = self.api.Object['radiusproxy'].get_dn_if_exists(cl)
entry_attrs['ipatokenradiusconfiglink'] = answer entry_attrs['ipatokenradiusconfiglink'] = answer
self.pre_common_callback(ldap, dn, entry_attrs, **options) self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys,
**options)
return dn return dn
@@ -394,7 +395,7 @@ class stageuser_add(baseuser_add):
# if both randompassword and userpassword options were used # if both randompassword and userpassword options were used
pass pass
self.post_common_callback(ldap, dn, entry_attrs, **options) self.post_common_callback(ldap, dn, entry_attrs, *keys, **options)
return dn return dn
@register() @register()
@@ -412,7 +413,8 @@ class stageuser_mod(baseuser_mod):
has_output_params = baseuser_mod.has_output_params + stageuser_output_params has_output_params = baseuser_mod.has_output_params + stageuser_output_params
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
self.pre_common_callback(ldap, dn, entry_attrs, **options) self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys,
**options)
# Make sure it is not possible to authenticate with a Stage user account # Make sure it is not possible to authenticate with a Stage user account
if 'nsaccountlock' in entry_attrs: if 'nsaccountlock' in entry_attrs:
del entry_attrs['nsaccountlock'] del entry_attrs['nsaccountlock']
@@ -433,6 +435,8 @@ class stageuser_find(baseuser_find):
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *keys, **options): def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *keys, **options):
assert isinstance(base_dn, DN) assert isinstance(base_dn, DN)
self.pre_common_callback(ldap, filter, attrs_list, base_dn, scope,
*keys, **options)
container_filter = "(objectclass=posixaccount)" container_filter = "(objectclass=posixaccount)"
# provisioning system can create non posixaccount stage user # provisioning system can create non posixaccount stage user
@@ -458,9 +462,14 @@ class stageuser_show(baseuser_show):
has_output_params = baseuser_show.has_output_params + stageuser_output_params has_output_params = baseuser_show.has_output_params + stageuser_output_params
def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
assert isinstance(dn, DN)
self.pre_common_callback(ldap, dn, attrs_list, *keys, **options)
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options): def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
entry_attrs['nsaccountlock'] = True entry_attrs['nsaccountlock'] = True
self.post_common_callback(ldap, dn, entry_attrs, **options) self.post_common_callback(ldap, dn, entry_attrs, *keys, **options)
return dn return dn

View File

@@ -542,7 +542,8 @@ class user_add(baseuser_add):
answer = self.api.Object['radiusproxy'].get_dn_if_exists(rcl) answer = self.api.Object['radiusproxy'].get_dn_if_exists(rcl)
entry_attrs['ipatokenradiusconfiglink'] = answer entry_attrs['ipatokenradiusconfiglink'] = answer
self.pre_common_callback(ldap, dn, entry_attrs, **options) self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys,
**options)
return dn return dn
@@ -588,7 +589,7 @@ class user_add(baseuser_add):
self.obj.get_preserved_attribute(entry_attrs, options) self.obj.get_preserved_attribute(entry_attrs, options)
self.post_common_callback(ldap, dn, entry_attrs, **options) self.post_common_callback(ldap, dn, entry_attrs, *keys, **options)
return dn return dn
@@ -752,12 +753,13 @@ class user_mod(baseuser_mod):
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
dn = self.obj.get_either_dn(*keys, **options) dn = self.obj.get_either_dn(*keys, **options)
self.pre_common_callback(ldap, dn, entry_attrs, **options) self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys,
**options)
validate_nsaccountlock(entry_attrs) validate_nsaccountlock(entry_attrs)
return dn return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options): def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
self.post_common_callback(ldap, dn, entry_attrs, **options) self.post_common_callback(ldap, dn, entry_attrs, *keys, **options)
self.obj.get_preserved_attribute(entry_attrs, options) self.obj.get_preserved_attribute(entry_attrs, options)
return dn return dn
@@ -782,6 +784,8 @@ class user_find(baseuser_find):
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *keys, **options): def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *keys, **options):
assert isinstance(base_dn, DN) assert isinstance(base_dn, DN)
self.pre_common_callback(ldap, filter, attrs_list, base_dn, scope,
*keys, **options)
if options.get('whoami'): if options.get('whoami'):
return ("(&(objectclass=posixaccount)(krbprincipalname=%s))"%\ return ("(&(objectclass=posixaccount)(krbprincipalname=%s))"%\
@@ -830,11 +834,12 @@ class user_show(baseuser_show):
def pre_callback(self, ldap, dn, attrs_list, *keys, **options): def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
dn = self.obj.get_either_dn(*keys, **options) dn = self.obj.get_either_dn(*keys, **options)
self.pre_common_callback(ldap, dn, attrs_list, *keys, **options)
return dn return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options): def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
convert_nsaccountlock(entry_attrs) convert_nsaccountlock(entry_attrs)
self.post_common_callback(ldap, dn, entry_attrs, **options) self.post_common_callback(ldap, dn, entry_attrs, *keys, **options)
self.obj.get_preserved_attribute(entry_attrs, options) self.obj.get_preserved_attribute(entry_attrs, options)
return dn return dn

View File

@@ -290,12 +290,9 @@ def validate_sshpubkey_no_options(ugettext, value):
if pubkey.has_options(): if pubkey.has_options():
return _('options are not allowed') return _('options are not allowed')
def convert_sshpubkey_post(ldap, dn, entry_attrs):
if 'ipasshpubkey' in entry_attrs: def convert_sshpubkey_post(entry_attrs):
pubkeys = entry_attrs['ipasshpubkey'] pubkeys = entry_attrs.get('ipasshpubkey')
else:
old_entry_attrs = ldap.get_entry(dn, ['ipasshpubkey'])
pubkeys = old_entry_attrs.get('ipasshpubkey')
if not pubkeys: if not pubkeys:
return return
@@ -321,6 +318,37 @@ def convert_sshpubkey_post(ldap, dn, entry_attrs):
if fingerprints: if fingerprints:
entry_attrs['sshpubkeyfp'] = fingerprints entry_attrs['sshpubkeyfp'] = fingerprints
def add_sshpubkey_to_attrs_pre(context, attrs_list):
"""
Attribute ipasshpubkey should be added to attrs_list to be able compute
ssh fingerprint. This attribute must be removed later if was added here
(see remove_sshpubkey_from_output_post).
"""
if not ('ipasshpubkey' in attrs_list or '*' in attrs_list):
setattr(context, 'ipasshpubkey_added', True)
attrs_list.append('ipasshpubkey')
def remove_sshpubkey_from_output_post(context, entry_attrs):
"""
Remove ipasshpubkey from output if it was added in pre_callbacks
"""
if getattr(context, 'ipasshpubkey_added', False):
entry_attrs.pop('ipasshpubkey', None)
delattr(context, 'ipasshpubkey_added')
def remove_sshpubkey_from_output_list_post(context, entries):
"""
Remove ipasshpubkey from output if it was added in pre_callbacks
"""
if getattr(context, 'ipasshpubkey_added', False):
for entry_attrs in entries:
entry_attrs.pop('ipasshpubkey', None)
delattr(context, 'ipasshpubkey_added')
class cachedproperty(object): class cachedproperty(object):
""" """
A property-like attribute that caches the return value of a method call. A property-like attribute that caches the return value of a method call.