mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
service delegation: allow to add and remove host principals
Service delegation rules and targets deal with Kerberos principals. As FreeIPA has separate service objects for hosts and Kerberos services, it is not possible to specify host principal in the service delegation rule or a target because the code assumes it always operates on Kerberos service objects. Simplify the code to add and remove members from delegation rules and targets. New code looks up a name of the principal in cn=accounts,$BASEDN as a krbPrincipalName attribute of an object with krbPrincipalAux object class. This search path is optimized already for Kerberos KDC driver. To support host principals, the specified principal name is checked to have only one component (a host name). Service principals have more than one component, typically service name and a host name, separated by '/' sign. If the principal name has only one component, the name is prepended with 'host/' to be able to find a host principal. The logic described above allows to capture also aliases of both Kerberos service and host principals. Additional check was added to allow specifying single-component aliases ending with '$' sign. These are typically used for Active Directory-related services like databases or file services. RN: service delegation rules and targets now allow to specify hosts as RN: a rule or a target's member principal. Fixes: https://pagure.io/freeipa/issue/8289 Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Rob Crittenden <rcritten@redhat.com> Reviewed-By: Christian Heimes <cheimes@redhat.com>
This commit is contained in:
parent
0fa31ef123
commit
1f82d281cc
@ -15,10 +15,10 @@ from .baseldap import (
|
||||
LDAPDelete,
|
||||
LDAPSearch,
|
||||
LDAPRetrieve)
|
||||
from .service import normalize_principal
|
||||
from ipalib import _, ngettext
|
||||
from ipalib import errors
|
||||
from ipapython.dn import DN
|
||||
from ipapython import kerberos
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
@ -46,6 +46,13 @@ A target consists of a list of principals that can be delegated.
|
||||
In English, a rule says that this principal can delegate as this
|
||||
list of principals, as defined by these targets.
|
||||
|
||||
In both a rule and a target Kerberos principals may be specified
|
||||
by their name or an alias and the realm can be omitted. Additionally,
|
||||
hosts can be specified by their names. If Kerberos principal specified
|
||||
has a single component and does not end with '$' sign, it will be treated
|
||||
as a host name. Kerberos principal names ending with '$' are typically
|
||||
used as aliases for Active Directory-related services.
|
||||
|
||||
EXAMPLES:
|
||||
|
||||
Add a new constrained delegation rule:
|
||||
@ -58,6 +65,10 @@ EXAMPLES:
|
||||
ipa servicedelegationrule-add-member --principals=ftp/ipa.example.com \
|
||||
ftp-delegation
|
||||
|
||||
Add a host principal of the host 'ipa.example.com' to the rule:
|
||||
ipa servicedelegationrule-add-member --principals=ipa.example.com \
|
||||
ftp-delegation
|
||||
|
||||
Add our target to the rule:
|
||||
ipa servicedelegationrule-add-target \
|
||||
--servicedelegationtargets=ftp-delegation-target ftp-delegation
|
||||
@ -169,6 +180,21 @@ class servicedelegation(LDAPObject):
|
||||
)
|
||||
|
||||
|
||||
def normalize_principal_name(name, realm):
|
||||
try:
|
||||
princ = kerberos.Principal(name, realm=realm)
|
||||
except ValueError as e:
|
||||
raise errors.ValidationError(
|
||||
name='principal',
|
||||
reason=_("Malformed principal: %(error)s") % dict(error=str(e)))
|
||||
|
||||
if len(princ.components) == 1 and not princ.components[0].endswith('$'):
|
||||
nprinc = 'host/' + unicode(princ)
|
||||
else:
|
||||
nprinc = unicode(princ)
|
||||
return nprinc
|
||||
|
||||
|
||||
class servicedelegation_add_member(LDAPAddMember):
|
||||
__doc__ = _('Add target to a named service delegation.')
|
||||
member_attrs = ['memberprincipal']
|
||||
@ -212,22 +238,31 @@ class servicedelegation_add_member(LDAPAddMember):
|
||||
failed[self.principal_failedattr] = {}
|
||||
failed[self.principal_failedattr][self.principal_attr] = []
|
||||
names = options.get(self.member_names[self.principal_attr], [])
|
||||
ldap_obj = self.api.Object['service']
|
||||
basedn = self.api.env.container_accounts + self.api.env.basedn
|
||||
if names:
|
||||
for name in names:
|
||||
if not name:
|
||||
continue
|
||||
name = normalize_principal(name)
|
||||
obj_dn = ldap_obj.get_dn(name)
|
||||
|
||||
princ = normalize_principal_name(name, self.api.env.realm)
|
||||
try:
|
||||
ldap.get_entry(obj_dn, ['krbprincipalname'])
|
||||
e_attrs = ldap.find_entry_by_attr(
|
||||
'krbprincipalname', princ, 'krbprincipalaux',
|
||||
attrs_list=['krbprincipalname'],
|
||||
base_dn=basedn)
|
||||
except errors.NotFound as e:
|
||||
failed[self.principal_failedattr][
|
||||
self.principal_attr].append((name, unicode(e)))
|
||||
continue
|
||||
try:
|
||||
if name not in entry_attrs.get(self.principal_attr, []):
|
||||
members.append(name)
|
||||
# normalize principal as set in krbPrincipalName attribute
|
||||
mprinc = None
|
||||
for p in e_attrs.get('krbprincipalname'):
|
||||
p = unicode(p)
|
||||
if p.lower() == princ.lower():
|
||||
mprinc = p
|
||||
if mprinc not in entry_attrs.get(self.principal_attr, []):
|
||||
members.append(mprinc)
|
||||
else:
|
||||
raise errors.AlreadyGroupMember()
|
||||
except errors.PublicError as e:
|
||||
@ -314,10 +349,10 @@ class servicedelegation_remove_member(LDAPRemoveMember):
|
||||
for name in names:
|
||||
if not name:
|
||||
continue
|
||||
name = normalize_principal(name)
|
||||
princ = normalize_principal_name(name, self.api.env.realm)
|
||||
try:
|
||||
if name in entry_attrs.get(self.principal_attr, []):
|
||||
entry_attrs[self.principal_attr].remove(name)
|
||||
if princ in entry_attrs.get(self.principal_attr, []):
|
||||
entry_attrs[self.principal_attr].remove(princ)
|
||||
else:
|
||||
raise errors.NotGroupMember()
|
||||
except errors.PublicError as e:
|
||||
|
@ -17,6 +17,8 @@ target1 = u'test1-targets'
|
||||
target2 = u'test2-targets'
|
||||
princ1 = u'HTTP/%s@%s' % (api.env.host, api.env.realm)
|
||||
princ2 = u'ldap/%s@%s' % (api.env.host, api.env.realm)
|
||||
princ3 = u'host/%s@%s' % (api.env.host, api.env.realm)
|
||||
host3 = api.env.host
|
||||
|
||||
|
||||
def get_servicedelegation_dn(cn):
|
||||
@ -435,7 +437,7 @@ class test_servicedelegation(Declarative):
|
||||
failed_memberprincipal=dict(
|
||||
memberprincipal=[
|
||||
[u'HTTP/notfound@%s' % api.env.realm,
|
||||
u'no such entry']
|
||||
u'no matching entry found']
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -448,6 +450,50 @@ class test_servicedelegation(Declarative):
|
||||
),
|
||||
|
||||
|
||||
dict(
|
||||
desc='Add host as a member %r to %r' % (host3, rule1),
|
||||
command=(
|
||||
'servicedelegationrule_add_member', [rule1],
|
||||
dict(principal=princ3)
|
||||
),
|
||||
expected=dict(
|
||||
completed=1,
|
||||
failed=dict(
|
||||
failed_memberprincipal=dict(
|
||||
memberprincipal=tuple(),
|
||||
),
|
||||
),
|
||||
result={
|
||||
'dn': get_servicedelegation_dn(rule1),
|
||||
'memberprincipal': (princ1, princ3),
|
||||
'cn': [rule1],
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
dict(
|
||||
desc='Remove a host member %r from %r' % (host3, rule1),
|
||||
command=(
|
||||
'servicedelegationrule_remove_member', [rule1],
|
||||
dict(principal=host3)
|
||||
),
|
||||
expected=dict(
|
||||
completed=1,
|
||||
failed=dict(
|
||||
failed_memberprincipal=dict(
|
||||
memberprincipal=tuple(),
|
||||
),
|
||||
),
|
||||
result={
|
||||
'dn': get_servicedelegation_dn(rule1),
|
||||
'memberprincipal': (princ1,),
|
||||
'cn': [rule1],
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
dict(
|
||||
desc='Remove a member %r from %r' % (princ1, rule1),
|
||||
command=(
|
||||
@ -556,7 +602,7 @@ class test_servicedelegation(Declarative):
|
||||
failed_memberprincipal=dict(
|
||||
memberprincipal=[
|
||||
[u'HTTP/notfound@%s' % api.env.realm,
|
||||
u'no such entry']
|
||||
u'no matching entry found']
|
||||
],
|
||||
),
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user