mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Support delegating RBAC roles to service principals
https://fedorahosted.org/freeipa/ticket/3164 Reviewed-By: Martin Kosek <mkosek@redhat.com>
This commit is contained in:
parent
27128bd8f5
commit
8fabd6dde1
6
API.txt
6
API.txt
@ -2908,7 +2908,7 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
|
||||
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
||||
output: PrimaryKey('value', None, None)
|
||||
command: role_add_member
|
||||
args: 1,8,3
|
||||
args: 1,9,3
|
||||
arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
|
||||
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
|
||||
option: Str('group*', alwaysask=True, cli_name='groups', csv=True)
|
||||
@ -2916,6 +2916,7 @@ option: Str('host*', alwaysask=True, cli_name='hosts', csv=True)
|
||||
option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True)
|
||||
option: Flag('no_members', autofill=True, default=False, exclude='webui')
|
||||
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
|
||||
option: Str('service*', alwaysask=True, cli_name='services', csv=True)
|
||||
option: Str('user*', alwaysask=True, cli_name='users', csv=True)
|
||||
option: Str('version?', exclude='webui')
|
||||
output: Output('completed', <type 'int'>, None)
|
||||
@ -2973,7 +2974,7 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
|
||||
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
||||
output: PrimaryKey('value', None, None)
|
||||
command: role_remove_member
|
||||
args: 1,8,3
|
||||
args: 1,9,3
|
||||
arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
|
||||
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
|
||||
option: Str('group*', alwaysask=True, cli_name='groups', csv=True)
|
||||
@ -2981,6 +2982,7 @@ option: Str('host*', alwaysask=True, cli_name='hosts', csv=True)
|
||||
option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True)
|
||||
option: Flag('no_members', autofill=True, default=False, exclude='webui')
|
||||
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
|
||||
option: Str('service*', alwaysask=True, cli_name='services', csv=True)
|
||||
option: Str('user*', alwaysask=True, cli_name='users', csv=True)
|
||||
option: Str('version?', exclude='webui')
|
||||
output: Output('completed', <type 'int'>, None)
|
||||
|
4
VERSION
4
VERSION
@ -89,5 +89,5 @@ IPA_DATA_VERSION=20100614120000
|
||||
# #
|
||||
########################################################
|
||||
IPA_API_VERSION_MAJOR=2
|
||||
IPA_API_VERSION_MINOR=101
|
||||
# Last change: mbasti - Allow '/' in permission name
|
||||
IPA_API_VERSION_MINOR=102
|
||||
# Last change: pviktori - allow adding services to roles
|
||||
|
@ -75,7 +75,7 @@ class role(LDAPObject):
|
||||
'memberindirect', 'memberofindirect',
|
||||
]
|
||||
attribute_members = {
|
||||
'member': ['user', 'group', 'host', 'hostgroup'],
|
||||
'member': ['user', 'group', 'host', 'hostgroup', 'service'],
|
||||
'memberof': ['privilege'],
|
||||
}
|
||||
reverse_members = {
|
||||
|
@ -306,10 +306,11 @@ class service(LDAPObject):
|
||||
permission_filter_objectclasses = ['ipaservice']
|
||||
search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata']
|
||||
default_attributes = ['krbprincipalname', 'usercertificate', 'managedby',
|
||||
'ipakrbauthzdata',]
|
||||
'ipakrbauthzdata', 'memberof']
|
||||
uuid_attribute = 'ipauniqueid'
|
||||
attribute_members = {
|
||||
'managedby': ['host'],
|
||||
'memberof': ['role'],
|
||||
}
|
||||
bindable = True
|
||||
relationships = {
|
||||
|
82
ipatests/test_integration/test_service_permissions.py
Normal file
82
ipatests/test_integration/test_service_permissions.py
Normal file
@ -0,0 +1,82 @@
|
||||
# Authors:
|
||||
# Petr Viktorin <pviktori@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2014 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
|
||||
from ipatests.test_integration.base import IntegrationTest
|
||||
from ipatests.test_integration import tasks
|
||||
|
||||
|
||||
class TestServicePermissions(IntegrationTest):
|
||||
topology = 'star'
|
||||
|
||||
def test_service_as_user_admin(self):
|
||||
"""Test that a service in User Administrator role can manage users"""
|
||||
|
||||
service_name = 'testservice/%s@%s' % (self.master.hostname,
|
||||
self.master.domain.realm)
|
||||
keytab_file = os.path.join(self.master.config.test_dir,
|
||||
'testservice_keytab')
|
||||
|
||||
# Prepare a service
|
||||
|
||||
self.master.run_command(['ipa', 'service-add', service_name])
|
||||
|
||||
self.master.run_command(['ipa-getkeytab',
|
||||
'-p', service_name,
|
||||
'-k', keytab_file,
|
||||
'-s', self.master.hostname])
|
||||
|
||||
# Check that the service cannot add a user
|
||||
|
||||
self.master.run_command(['kdestroy'])
|
||||
self.master.run_command(['kinit', '-k', service_name,
|
||||
'-t', keytab_file])
|
||||
|
||||
result = self.master.run_command(['ipa', 'role-add-member',
|
||||
'User Administrator',
|
||||
'--service', service_name],
|
||||
raiseonerr=False)
|
||||
assert result.returncode > 0
|
||||
|
||||
# Add service to User Administrator role
|
||||
|
||||
self.master.run_command(['kdestroy'])
|
||||
tasks.kinit_admin(self.master)
|
||||
|
||||
self.master.run_command(['ipa', 'role-add-member',
|
||||
'User Administrator',
|
||||
'--service', service_name])
|
||||
|
||||
# Check that the service now can add a user
|
||||
|
||||
self.master.run_command(['kdestroy'])
|
||||
self.master.run_command(['kinit', '-k', service_name,
|
||||
'-t', keytab_file])
|
||||
|
||||
self.master.run_command(['ipa', 'user-add', 'tuser',
|
||||
'--first', 'a', '--last', 'b', '--random'])
|
||||
|
||||
# Clean up
|
||||
|
||||
self.master.run_command(['kdestroy'])
|
||||
tasks.kinit_admin(self.master)
|
||||
|
||||
self.master.run_command(['ipa', 'service-del', service_name])
|
||||
self.master.run_command(['ipa', 'user-del', 'tuser'])
|
@ -257,6 +257,7 @@ class test_role(Declarative):
|
||||
group=[],
|
||||
host=[],
|
||||
hostgroup=[],
|
||||
service=[],
|
||||
),
|
||||
),
|
||||
result={
|
||||
@ -436,6 +437,7 @@ class test_role(Declarative):
|
||||
group=[],
|
||||
host=[],
|
||||
hostgroup=[],
|
||||
service=[],
|
||||
),
|
||||
),
|
||||
result={
|
||||
|
@ -40,6 +40,8 @@ host1dn = DN(('fqdn',fqdn1),('cn','computers'),('cn','accounts'),api.env.basedn)
|
||||
host2dn = DN(('fqdn',fqdn2),('cn','computers'),('cn','accounts'),api.env.basedn)
|
||||
host3dn = DN(('fqdn',fqdn3),('cn','computers'),('cn','accounts'),api.env.basedn)
|
||||
|
||||
role1 = u'Test Role'
|
||||
role1_dn = DN(('cn', role1), api.env.container_rolegroup, api.env.basedn)
|
||||
|
||||
badservercert = 'MIICbzCCAdigAwIBAgICA/4wDQYJKoZIhvcNAQEFBQAwKTEnMCUGA1UEAxMeSVBBIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDgwOTE1MDIyN1oXDTIwMDgwOTE1MDIyN1owKTEMMAoGA1UEChMDSVBBMRkwFwYDVQQDExBwdW1hLmdyZXlvYWsuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwYbfEOQPgGenPn9vt1JFKvWm/Je3y2tawGWA3LXDuqfFJyYtZ8ib3TcBUOnLk9WK5g2qCwHaNlei7bj8ggIfr5hegAVe10cun+wYErjnYo7hsHYd+57VZezeipWrXu+7NoNd4+c4A5lk4A/xJay9j3bYx2oOM8BEox4xWYoWge1ljPrc5JK46f0X7AGW4F2VhnKPnf8rwSuzI1U8VGjutyM9TWNy3m9KMWeScjyG/ggIpOjUDMV7HkJL0Di61lznR9jXubpiEC7gWGbTp84eGl/Nn9bgK1AwHfJ2lHwfoY4uiL7ge1gyP6EvuUlHoBzdb7pekiX28iePjW3iEG9IawIDAQABoyIwIDARBglghkgBhvhCAQEEBAMCBkAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEBBQUAA4GBACRESLemRV9BPxfEgbALuxH5oE8jQm8WZ3pm2pALbpDlAd9wQc3yVf6RtkfVthyDnM18bg7IhxKpd77/p3H8eCnS8w5MLVRda6ktUC6tGhFTS4QKAf0WyDGTcIgkXbeDw0OPAoNHivoXbIXIIRxlw/XgaSaMzJQDBG8iROsN4kCv'
|
||||
|
||||
@ -626,3 +628,125 @@ class test_service(Declarative):
|
||||
|
||||
|
||||
]
|
||||
|
||||
|
||||
class test_service_in_role(Declarative):
|
||||
cleanup_commands = [
|
||||
('host_del', [fqdn1], {}),
|
||||
('service_del', [service1], {}),
|
||||
('role_del', [role1], {}),
|
||||
]
|
||||
|
||||
tests = [
|
||||
dict(
|
||||
desc='Create %r' % fqdn1,
|
||||
command=('host_add', [fqdn1],
|
||||
dict(
|
||||
description=u'Test host 1',
|
||||
l=u'Undisclosed location 1',
|
||||
force=True,
|
||||
),
|
||||
),
|
||||
expected=dict(
|
||||
value=fqdn1,
|
||||
summary=u'Added host "%s"' % fqdn1,
|
||||
result=dict(
|
||||
dn=host1dn,
|
||||
fqdn=[fqdn1],
|
||||
description=[u'Test host 1'],
|
||||
l=[u'Undisclosed location 1'],
|
||||
krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
|
||||
objectclass=objectclasses.host,
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
managedby_host=[u'%s' % fqdn1],
|
||||
has_keytab=False,
|
||||
has_password=False,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
dict(
|
||||
desc='Create %r' % service1,
|
||||
command=('service_add', [service1], dict(force=True)),
|
||||
expected=dict(
|
||||
value=service1,
|
||||
summary=u'Added service "%s"' % service1,
|
||||
result=dict(
|
||||
dn=service1dn,
|
||||
krbprincipalname=[service1],
|
||||
objectclass=objectclasses.service,
|
||||
ipauniqueid=[fuzzy_uuid],
|
||||
managedby_host=[fqdn1],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
dict(
|
||||
desc='Create %r' % role1,
|
||||
command=('role_add', [role1], dict(description=u'role desc 1')),
|
||||
expected=dict(
|
||||
value=role1,
|
||||
summary=u'Added role "%s"' % role1,
|
||||
result=dict(
|
||||
dn=role1_dn,
|
||||
cn=[role1],
|
||||
description=[u'role desc 1'],
|
||||
objectclass=objectclasses.role,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
dict(
|
||||
desc='Add %r to %r' % (service1, role1),
|
||||
command=('role_add_member', [role1], dict(service=service1)),
|
||||
expected=dict(
|
||||
failed=dict(
|
||||
member=dict(
|
||||
host=[],
|
||||
group=[],
|
||||
hostgroup=[],
|
||||
service=[],
|
||||
user=[],
|
||||
),
|
||||
),
|
||||
completed=1,
|
||||
result=dict(
|
||||
dn=role1_dn,
|
||||
cn=[role1],
|
||||
description=[u'role desc 1'],
|
||||
member_service=[service1],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
dict(
|
||||
desc='Verify %r is member of %r' % (service1, role1),
|
||||
command=('service_show', [service1], {}),
|
||||
expected=dict(
|
||||
value=service1,
|
||||
summary=None,
|
||||
result=dict(
|
||||
dn=service1dn,
|
||||
krbprincipalname=[service1],
|
||||
managedby_host=[fqdn1],
|
||||
memberof_role=[role1.lower()],
|
||||
has_keytab=False,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
dict(
|
||||
desc='Verify %r has member %r' % (role1, service1),
|
||||
command=('role_show', [role1], {}),
|
||||
expected=dict(
|
||||
value=role1,
|
||||
summary=None,
|
||||
result=dict(
|
||||
dn=role1_dn,
|
||||
cn=[role1],
|
||||
description=[u'role desc 1'],
|
||||
member_service=[service1],
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user