mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-23 15:40:01 -06:00
1f82d281cc
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>
666 lines
20 KiB
Python
666 lines
20 KiB
Python
#
|
|
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
|
#
|
|
"""
|
|
Test the `ipaserver/plugins/serviceconstraint.py` module.
|
|
"""
|
|
|
|
from ipalib import api, errors
|
|
from ipatests.test_xmlrpc import objectclasses
|
|
from ipatests.test_xmlrpc.xmlrpc_test import Declarative
|
|
from ipapython.dn import DN
|
|
import pytest
|
|
|
|
rule1 = u'test1'
|
|
rule2 = u'test rule two'
|
|
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):
|
|
return DN(('cn', cn), api.env.container_s4u2proxy, api.env.basedn)
|
|
|
|
|
|
@pytest.mark.tier1
|
|
class test_servicedelegation(Declarative):
|
|
cleanup_commands = [
|
|
('servicedelegationrule_del', [rule1], {}),
|
|
('servicedelegationrule_del', [rule2], {}),
|
|
('servicedelegationtarget_del', [target1], {}),
|
|
('servicedelegationtarget_del', [target2], {}),
|
|
]
|
|
|
|
tests = [
|
|
|
|
################
|
|
# create rule1:
|
|
dict(
|
|
desc='Try to retrieve non-existent %r' % rule1,
|
|
command=('servicedelegationrule_show', [rule1], {}),
|
|
expected=errors.NotFound(
|
|
reason=u'%s: service delegation rule not found' % rule1
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Try to delete non-existent %r' % rule1,
|
|
command=('servicedelegationrule_del', [rule1], {}),
|
|
expected=errors.NotFound(
|
|
reason=u'%s: service delegation rule not found' % rule1
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Create %r' % rule1,
|
|
command=(
|
|
'servicedelegationrule_add', [rule1], {}
|
|
),
|
|
expected=dict(
|
|
value=rule1,
|
|
summary=u'Added service delegation rule "%s"' % rule1,
|
|
result=dict(
|
|
cn=[rule1],
|
|
objectclass=objectclasses.servicedelegationrule,
|
|
dn=get_servicedelegation_dn(rule1),
|
|
),
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Try to create duplicate %r' % rule1,
|
|
command=(
|
|
'servicedelegationrule_add', [rule1], {}
|
|
),
|
|
expected=errors.DuplicateEntry(
|
|
message=u'service delegation rule with name "%s" '
|
|
'already exists' % rule1),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Retrieve %r' % rule1,
|
|
command=('servicedelegationrule_show', [rule1], {}),
|
|
expected=dict(
|
|
value=rule1,
|
|
summary=None,
|
|
result=dict(
|
|
cn=[rule1],
|
|
dn=get_servicedelegation_dn(rule1),
|
|
),
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Search for %r' % rule1,
|
|
command=('servicedelegationrule_find', [], dict(cn=rule1)),
|
|
expected=dict(
|
|
count=1,
|
|
truncated=False,
|
|
result=[
|
|
dict(
|
|
dn=get_servicedelegation_dn(rule1),
|
|
cn=[rule1],
|
|
),
|
|
],
|
|
summary=u'1 service delegation rule matched',
|
|
),
|
|
),
|
|
|
|
|
|
|
|
################
|
|
# create rule2:
|
|
dict(
|
|
desc='Create %r' % rule2,
|
|
command=(
|
|
'servicedelegationrule_add', [rule2], {}
|
|
),
|
|
expected=dict(
|
|
value=rule2,
|
|
summary=u'Added service delegation rule "%s"' % rule2,
|
|
result=dict(
|
|
cn=[rule2],
|
|
objectclass=objectclasses.servicedelegationrule,
|
|
dn=get_servicedelegation_dn(rule2),
|
|
),
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Search for all rules with members',
|
|
command=('servicedelegationrule_find', [], {'no_members': False}),
|
|
expected=dict(
|
|
summary=u'3 service delegation rules matched',
|
|
count=3,
|
|
truncated=False,
|
|
result=[
|
|
{
|
|
'dn': get_servicedelegation_dn(u'ipa-http-delegation'),
|
|
'cn': [u'ipa-http-delegation'],
|
|
'memberprincipal': [princ1],
|
|
'ipaallowedtarget_servicedelegationtarget':
|
|
[u'ipa-ldap-delegation-targets',
|
|
u'ipa-cifs-delegation-targets']
|
|
},
|
|
dict(
|
|
dn=get_servicedelegation_dn(rule2),
|
|
cn=[rule2],
|
|
),
|
|
dict(
|
|
dn=get_servicedelegation_dn(rule1),
|
|
cn=[rule1],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Search for all rules',
|
|
command=('servicedelegationrule_find', [], {}),
|
|
expected=dict(
|
|
summary=u'3 service delegation rules matched',
|
|
count=3,
|
|
truncated=False,
|
|
result=[
|
|
{
|
|
'dn': get_servicedelegation_dn(u'ipa-http-delegation'),
|
|
'cn': [u'ipa-http-delegation'],
|
|
'memberprincipal': [princ1],
|
|
},
|
|
dict(
|
|
dn=get_servicedelegation_dn(rule2),
|
|
cn=[rule2],
|
|
),
|
|
dict(
|
|
dn=get_servicedelegation_dn(rule1),
|
|
cn=[rule1],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Create target %r' % target1,
|
|
command=(
|
|
'servicedelegationtarget_add', [target1], {}
|
|
),
|
|
expected=dict(
|
|
value=target1,
|
|
summary=u'Added service delegation target "%s"' % target1,
|
|
result=dict(
|
|
cn=[target1],
|
|
objectclass=objectclasses.servicedelegationtarget,
|
|
dn=get_servicedelegation_dn(target1),
|
|
),
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Create target %r' % target2,
|
|
command=(
|
|
'servicedelegationtarget_add', [target2], {}
|
|
),
|
|
expected=dict(
|
|
value=target2,
|
|
summary=u'Added service delegation target "%s"' % target2,
|
|
result=dict(
|
|
cn=[target2],
|
|
objectclass=objectclasses.servicedelegationtarget,
|
|
dn=get_servicedelegation_dn(target2),
|
|
),
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Search for all targets',
|
|
command=('servicedelegationtarget_find', [], {}),
|
|
expected=dict(
|
|
summary=u'4 service delegation targets matched',
|
|
count=4,
|
|
truncated=False,
|
|
result=[
|
|
{
|
|
'dn': get_servicedelegation_dn(
|
|
u'ipa-cifs-delegation-targets'),
|
|
'cn': [u'ipa-cifs-delegation-targets'],
|
|
},
|
|
{
|
|
'dn': get_servicedelegation_dn(
|
|
u'ipa-ldap-delegation-targets'
|
|
),
|
|
'cn': [u'ipa-ldap-delegation-targets'],
|
|
'memberprincipal': [princ2],
|
|
},
|
|
dict(
|
|
dn=get_servicedelegation_dn(target1),
|
|
cn=[target1],
|
|
),
|
|
dict(
|
|
dn=get_servicedelegation_dn(target2),
|
|
cn=[target2],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
|
|
###############
|
|
# member stuff:
|
|
dict(
|
|
desc='Add member %r to %r' % (target1, rule1),
|
|
command=(
|
|
'servicedelegationrule_add_target', [rule1],
|
|
dict(servicedelegationtarget=target1)
|
|
),
|
|
expected=dict(
|
|
completed=1,
|
|
failed=dict(
|
|
ipaallowedtarget=dict(
|
|
servicedelegationtarget=tuple(),
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(rule1),
|
|
'ipaallowedtarget_servicedelegationtarget': (target1,),
|
|
'cn': [rule1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Add duplicate target %r to %r' % (target1, rule1),
|
|
command=(
|
|
'servicedelegationrule_add_target', [rule1],
|
|
dict(servicedelegationtarget=target1)
|
|
),
|
|
expected=dict(
|
|
completed=0,
|
|
failed=dict(
|
|
ipaallowedtarget=dict(
|
|
servicedelegationtarget=[
|
|
[target1, u'This entry is already a member']
|
|
],
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(rule1),
|
|
'ipaallowedtarget_servicedelegationtarget': (target1,),
|
|
'cn': [rule1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Add non-existent target %r to %r' % (u'notfound', rule1),
|
|
command=(
|
|
'servicedelegationrule_add_target', [rule1],
|
|
dict(servicedelegationtarget=u'notfound')
|
|
),
|
|
expected=dict(
|
|
completed=0,
|
|
failed=dict(
|
|
ipaallowedtarget=dict(
|
|
servicedelegationtarget=[
|
|
[u'notfound', u'no such entry']
|
|
],
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(rule1),
|
|
'ipaallowedtarget_servicedelegationtarget': (target1,),
|
|
'cn': [rule1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Remove a target %r from %r' % (target1, rule1),
|
|
command=(
|
|
'servicedelegationrule_remove_target', [rule1],
|
|
dict(servicedelegationtarget=target1)
|
|
),
|
|
expected=dict(
|
|
completed=1,
|
|
failed=dict(
|
|
ipaallowedtarget=dict(
|
|
servicedelegationtarget=tuple(),
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(rule1),
|
|
'cn': [rule1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Remove non-existent target %r from %r' % (
|
|
u'notfound', rule1
|
|
),
|
|
command=(
|
|
'servicedelegationrule_remove_target', [rule1],
|
|
dict(servicedelegationtarget=u'notfound')
|
|
),
|
|
expected=dict(
|
|
completed=0,
|
|
failed=dict(
|
|
ipaallowedtarget=dict(
|
|
servicedelegationtarget=[
|
|
[u'notfound', u'This entry is not a member']
|
|
],
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(rule1),
|
|
'cn': [rule1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
###############
|
|
# memberprincipal member stuff:
|
|
dict(
|
|
desc='Add memberprinc %r to %r' % (princ1, rule1),
|
|
command=(
|
|
'servicedelegationrule_add_member', [rule1],
|
|
dict(principal=princ1)
|
|
),
|
|
expected=dict(
|
|
completed=1,
|
|
failed=dict(
|
|
failed_memberprincipal=dict(
|
|
memberprincipal=tuple(),
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(rule1),
|
|
'memberprincipal': (princ1,),
|
|
'cn': [rule1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Add duplicate member %r to %r' % (princ1, rule1),
|
|
command=(
|
|
'servicedelegationrule_add_member', [rule1],
|
|
dict(principal=princ1)
|
|
),
|
|
expected=dict(
|
|
completed=0,
|
|
failed=dict(
|
|
failed_memberprincipal=dict(
|
|
memberprincipal=[
|
|
[princ1, u'This entry is already a member']
|
|
],
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(rule1),
|
|
'memberprincipal': (princ1,),
|
|
'cn': [rule1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Add non-existent member %r to %r' % (
|
|
u'HTTP/notfound', rule1
|
|
),
|
|
command=(
|
|
'servicedelegationrule_add_member', [rule1],
|
|
dict(principal=u'HTTP/notfound@%s' % api.env.realm)
|
|
),
|
|
expected=dict(
|
|
completed=0,
|
|
failed=dict(
|
|
failed_memberprincipal=dict(
|
|
memberprincipal=[
|
|
[u'HTTP/notfound@%s' % api.env.realm,
|
|
u'no matching entry found']
|
|
],
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(rule1),
|
|
'memberprincipal': (princ1,),
|
|
'cn': [rule1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
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=(
|
|
'servicedelegationrule_remove_member', [rule1],
|
|
dict(principal=princ1)
|
|
),
|
|
expected=dict(
|
|
completed=1,
|
|
failed=dict(
|
|
failed_memberprincipal=dict(
|
|
memberprincipal=tuple(),
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(rule1),
|
|
'memberprincipal': [],
|
|
'cn': [rule1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Remove non-existent member %r from %r' % (
|
|
u'HTTP/notfound', rule1
|
|
),
|
|
command=(
|
|
'servicedelegationrule_remove_member', [rule1],
|
|
dict(principal=u'HTTP/notfound@%s' % api.env.realm)
|
|
),
|
|
expected=dict(
|
|
completed=0,
|
|
failed=dict(
|
|
failed_memberprincipal=dict(
|
|
memberprincipal=[
|
|
[u'HTTP/notfound@%s' % api.env.realm,
|
|
u'This entry is not a member']
|
|
],
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(rule1),
|
|
'cn': [rule1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Add memberprinc %r to %r' % (princ1, target1),
|
|
command=(
|
|
'servicedelegationtarget_add_member', [target1],
|
|
dict(principal=princ1)
|
|
),
|
|
expected=dict(
|
|
completed=1,
|
|
failed=dict(
|
|
failed_memberprincipal=dict(
|
|
memberprincipal=tuple(),
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(target1),
|
|
'memberprincipal': (princ1,),
|
|
'cn': [target1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Add duplicate member %r to %r' % (princ1, target1),
|
|
command=(
|
|
'servicedelegationtarget_add_member', [target1],
|
|
dict(principal=princ1)
|
|
),
|
|
expected=dict(
|
|
completed=0,
|
|
failed=dict(
|
|
failed_memberprincipal=dict(
|
|
memberprincipal=[
|
|
[princ1, u'This entry is already a member']
|
|
],
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(target1),
|
|
'memberprincipal': (princ1,),
|
|
'cn': [target1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Add non-existent member %r to %r' % (
|
|
u'HTTP/notfound', target1
|
|
),
|
|
command=(
|
|
'servicedelegationtarget_add_member', [target1],
|
|
dict(principal=u'HTTP/notfound@%s' % api.env.realm)
|
|
),
|
|
expected=dict(
|
|
completed=0,
|
|
failed=dict(
|
|
failed_memberprincipal=dict(
|
|
memberprincipal=[
|
|
[u'HTTP/notfound@%s' % api.env.realm,
|
|
u'no matching entry found']
|
|
],
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(target1),
|
|
'memberprincipal': (princ1,),
|
|
'cn': [target1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Remove a member %r from %r' % (princ1, target1),
|
|
command=(
|
|
'servicedelegationtarget_remove_member', [target1],
|
|
dict(principal=princ1)
|
|
),
|
|
expected=dict(
|
|
completed=1,
|
|
failed=dict(
|
|
failed_memberprincipal=dict(
|
|
memberprincipal=tuple(),
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(target1),
|
|
'memberprincipal': [],
|
|
'cn': [target1],
|
|
},
|
|
),
|
|
),
|
|
|
|
|
|
dict(
|
|
desc='Remove non-existent member %r from %r' % (
|
|
u'HTTP/notfound', target1
|
|
),
|
|
command=(
|
|
'servicedelegationtarget_remove_member', [target1],
|
|
dict(principal=u'HTTP/notfound@%s' % api.env.realm)
|
|
),
|
|
expected=dict(
|
|
completed=0,
|
|
failed=dict(
|
|
failed_memberprincipal=dict(
|
|
memberprincipal=[
|
|
[u'HTTP/notfound@%s' % api.env.realm,
|
|
u'This entry is not a member']
|
|
],
|
|
),
|
|
),
|
|
result={
|
|
'dn': get_servicedelegation_dn(target1),
|
|
'cn': [target1],
|
|
},
|
|
),
|
|
),
|
|
|
|
]
|