Make framework consider krbcanonicalname as service primary key

The framework does not allow single param to appear as both positional
argument and option in a single command, or to represent two different
positional arguments for that matter. Since principal aliases shall go to
krbprincipalname attribute, the framework has to be tricked to believe
krbcanonicalname is the service's primary key. The entry DN stored in LDAP
remains the same.

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

Reviewed-By: David Kupka <dkupka@redhat.com>
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
This commit is contained in:
Martin Babinsky
2016-06-23 20:01:34 +02:00
committed by Martin Basti
parent 750a392fe2
commit a28d312796
3 changed files with 97 additions and 20 deletions

29
API.txt
View File

@@ -4271,7 +4271,7 @@ output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: service_add/1
args: 1,12,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Flag('force', autofill=True, default=False)
@@ -4289,7 +4289,7 @@ output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: service_add_cert/1
args: 1,5,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Flag('no_members', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
@@ -4300,7 +4300,7 @@ output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: service_add_host/1
args: 1,5,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('host*', alwaysask=True, cli_name='hosts')
option: Flag('no_members', autofill=True, default=False)
@@ -4311,7 +4311,7 @@ output: Output('failed', type=[<type 'dict'>])
output: Entry('result')
command: service_allow_create_keytab/1
args: 1,8,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('group*', alwaysask=True, cli_name='groups')
option: Str('host*', alwaysask=True, cli_name='hosts')
@@ -4325,7 +4325,7 @@ output: Output('failed', type=[<type 'dict'>])
output: Entry('result')
command: service_allow_retrieve_keytab/1
args: 1,8,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('group*', alwaysask=True, cli_name='groups')
option: Str('host*', alwaysask=True, cli_name='hosts')
@@ -4339,7 +4339,7 @@ output: Output('failed', type=[<type 'dict'>])
output: Entry('result')
command: service_del/1
args: 1,2,3
arg: Principal('krbprincipalname+', cli_name='principal')
arg: Principal('krbcanonicalname+', cli_name='canonical_principal')
option: Flag('continue', autofill=True, cli_name='continue', default=False)
option: Str('version?')
output: Output('result', type=[<type 'dict'>])
@@ -4347,14 +4347,14 @@ output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: ListOfPrimaryKeys('value')
command: service_disable/1
args: 1,1,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Str('version?')
output: Output('result', type=[<type 'bool'>])
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: service_disallow_create_keytab/1
args: 1,8,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('group*', alwaysask=True, cli_name='groups')
option: Str('host*', alwaysask=True, cli_name='hosts')
@@ -4368,7 +4368,7 @@ output: Output('failed', type=[<type 'dict'>])
output: Entry('result')
command: service_disallow_retrieve_keytab/1
args: 1,8,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('group*', alwaysask=True, cli_name='groups')
option: Str('host*', alwaysask=True, cli_name='hosts')
@@ -4381,10 +4381,11 @@ output: Output('completed', type=[<type 'int'>])
output: Output('failed', type=[<type 'dict'>])
output: Entry('result')
command: service_find/1
args: 1,12,4
args: 1,13,4
arg: Str('criteria?')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: StrEnum('ipakrbauthzdata*', autofill=False, cli_name='pac_type', values=[u'MS-PAC', u'PAD', u'NONE'])
option: Principal('krbcanonicalname?', autofill=False, cli_name='canonical_principal')
option: Str('krbprincipalauthind*', autofill=False, cli_name='auth_ind')
option: Principal('krbprincipalname?', autofill=False, cli_name='principal')
option: Str('man_by_host*', cli_name='man_by_hosts')
@@ -4401,7 +4402,7 @@ output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: Output('truncated', type=[<type 'bool'>])
command: service_mod/1
args: 1,13,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Str('addattr*', cli_name='addattr')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('delattr*', cli_name='delattr')
@@ -4420,7 +4421,7 @@ output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: service_remove_cert/1
args: 1,5,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Flag('no_members', autofill=True, default=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False)
@@ -4431,7 +4432,7 @@ output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
output: PrimaryKey('value')
command: service_remove_host/1
args: 1,5,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Str('host*', alwaysask=True, cli_name='hosts')
option: Flag('no_members', autofill=True, default=False)
@@ -4442,7 +4443,7 @@ output: Output('failed', type=[<type 'dict'>])
output: Entry('result')
command: service_show/1
args: 1,6,3
arg: Principal('krbprincipalname', cli_name='principal')
arg: Principal('krbcanonicalname', cli_name='canonical_principal')
option: Flag('all', autofill=True, cli_name='all', default=False)
option: Flag('no_members', autofill=True, default=False)
option: Str('out?')

View File

@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
IPA_API_VERSION_MINOR=206
# Last change: mbabinsk: commands that use positional parameters to manage attributes
IPA_API_VERSION_MINOR=207
# Last change: mbabinsk: Make framework consider krbcanonicalname as service primary key

View File

@@ -436,9 +436,9 @@ class service(LDAPObject):
takes_params = (
Principal(
'krbprincipalname',
'krbcanonicalname',
validate_realm,
cli_name='principal',
cli_name='canonical_principal',
label=_('Principal'),
doc=_('Service principal'),
primary_key=True,
@@ -503,6 +503,16 @@ class service(LDAPObject):
" Use 'radius' to allow RADIUS-based 2FA authentications."
" Other values may be used for custom configurations."),
),
Principal(
'krbprincipalname',
validate_realm,
cli_name='principal',
label=_('Principal Alias'),
doc=_('Service principal alias'),
normalizer=normalize_principal,
require_service=True,
flags={'no_create', 'no_update'}
),
) + ticket_flags_params
def validate_ipakrbauthzdata(self, entry):
@@ -521,8 +531,51 @@ class service(LDAPObject):
error=_('NONE value cannot be combined with other PAC types'))
def get_dn(self, *keys, **kwargs):
keys = (normalize_principal(k) for k in keys)
return super(service, self).get_dn(*keys, **kwargs)
key = keys[0]
if isinstance(key, six.text_type):
key = kerberos.Principal(key)
key = unicode(normalize_principal(key))
parent_dn = DN(self.container_dn, self.api.env.basedn)
true_rdn = 'krbprincipalname'
return self.backend.make_dn_from_attr(
true_rdn, key, parent_dn
)
def get_primary_key_from_dn(self, dn):
"""
If the entry has krbcanonicalname set return the value of the
attribute. If the attribute is not found, assume old-style entry which
should have only single value of krbprincipalname and return it.
Otherwise return input DN.
"""
assert isinstance(dn, DN)
try:
entry_attrs = self.backend.get_entry(
dn, [self.primary_key.name]
)
try:
return entry_attrs[self.primary_key.name][0]
except (KeyError, IndexError):
return ''
except errors.NotFound:
pass
try:
return dn['krbprincipalname'][0]
except KeyError:
return unicode(dn)
def populate_krbcanonicalname(self, entry_attrs, options):
if options.get('raw', False):
return
entry_attrs.setdefault(
'krbcanonicalname', entry_attrs['krbprincipalname'])
@register()
@@ -587,6 +640,7 @@ class service_add(LDAPCreate):
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
set_kerberos_attrs(entry_attrs, options)
rename_ipaallowedtoperform_from_ldap(entry_attrs, options)
self.obj.populate_krbcanonicalname(entry_attrs, options)
return dn
@@ -655,6 +709,7 @@ class service_mod(LDAPUpdate):
set_certificate_attrs(entry_attrs)
set_kerberos_attrs(entry_attrs, options)
rename_ipaallowedtoperform_from_ldap(entry_attrs, options)
self.obj.populate_krbcanonicalname(entry_attrs, options)
return dn
@@ -667,6 +722,8 @@ class service_find(LDAPSearch):
'%(count)d service matched', '%(count)d services matched', 0
)
member_attributes = ['managedby']
sort_result_entries = False
takes_options = LDAPSearch.takes_options
has_output_params = LDAPSearch.has_output_params + output_params
@@ -680,12 +737,25 @@ class service_find(LDAPSearch):
'(krbprincipalname=krbtgt/*))' \
')' \
')'
if options.get('pkey_only', False):
attrs_list.append('krbprincipalname')
return (
ldap.combine_filters((custom_filter, filter), rules=ldap.MATCH_ALL),
base_dn, scope
)
def post_callback(self, ldap, entries, truncated, *args, **options):
# we have to sort entries manually instead of relying on inherited
# mechanisms
def sort_key(x):
if 'krbcanonicalname' in x:
return x['krbcanonicalname'][0]
else:
return x['krbprincipalname'][0]
entries.sort(key=sort_key)
if options.get('pkey_only', False):
return truncated
for entry_attrs in entries:
@@ -707,6 +777,7 @@ class service_find(LDAPSearch):
set_kerberos_attrs(entry_attrs, options)
rename_ipaallowedtoperform_from_ldap(entry_attrs, options)
self.obj.populate_krbcanonicalname(entry_attrs, options)
return truncated
@@ -744,6 +815,7 @@ class service_show(LDAPRetrieve):
set_kerberos_attrs(entry_attrs, options)
rename_ipaallowedtoperform_from_ldap(entry_attrs, options)
self.obj.populate_krbcanonicalname(entry_attrs, options)
return dn
@@ -781,6 +853,7 @@ class service_allow_retrieve_keytab(LDAPAddMember):
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
rename_ipaallowedtoperform_from_ldap(entry_attrs, options)
rename_ipaallowedtoperform_from_ldap(failed, options)
self.obj.populate_krbcanonicalname(entry_attrs, options)
return (completed, dn)
@@ -799,6 +872,7 @@ class service_disallow_retrieve_keytab(LDAPRemoveMember):
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
rename_ipaallowedtoperform_from_ldap(entry_attrs, options)
rename_ipaallowedtoperform_from_ldap(failed, options)
self.obj.populate_krbcanonicalname(entry_attrs, options)
return (completed, dn)
@@ -818,6 +892,7 @@ class service_allow_create_keytab(LDAPAddMember):
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
rename_ipaallowedtoperform_from_ldap(entry_attrs, options)
rename_ipaallowedtoperform_from_ldap(failed, options)
self.obj.populate_krbcanonicalname(entry_attrs, options)
return (completed, dn)
@@ -836,6 +911,7 @@ class service_disallow_create_keytab(LDAPRemoveMember):
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
rename_ipaallowedtoperform_from_ldap(entry_attrs, options)
rename_ipaallowedtoperform_from_ldap(failed, options)
self.obj.populate_krbcanonicalname(entry_attrs, options)
return (completed, dn)