test_trust: add tests for using AD users and groups in SUDO rules

Tests test_integration/test_trust.py::TestTrust::test_sudorules_ad_*
check that a user from a trusted AD domain can perform SUDO
authentication without a password for any command based on a direct user
reference or on indirect AD group reference. The test suite also ensures
an AD user and group can be used for runAsUser/runAsGroup settings.

Due to https://github.com/SSSD/sssd/issues/5475 anything added to
'ipaSudoRunAsExtUserGroup' attribute will be prefixed with '%' and thus
any relying on the value of this attribute displayed by 'sudo -l'
command will fail. The test only validates that a proper group name
appears in the 'sudo' output, so we handle both prefixes in the
corresponding test check. It is not possible to differ by the SSSD
version as a fix to the issue is only a patch on top of 2.4.0 in RHEL.

Fixes: https://pagure.io/freeipa/issue/3226
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
This commit is contained in:
Alexander Bokovoy authored and Rob Crittenden committed 2021-01-26 13:05:27 -05:00
1 parent 09e06e0564
commit 642b81e99f
2 files changed
+152 -2

No files matched your search

+150 -1
View File
@@ -1,9 +1,10 @@
# Copyright (C) 2019 FreeIPA Contributors see COPYING for license
# Copyright (C) 2019 FreeIPA Contributors see COPYING for license
from __future__ import absolute_import
import re
import textwrap
import time
import pytest
@@ -13,7 +14,11 @@ from ipaplatform.paths import paths
from ipatests.test_integration.base import IntegrationTest
from ipatests.pytest_ipa.integration import tasks
from ipapython.dn import DN
from collections import namedtuple
from contextlib import contextmanager
TestDataRule = namedtuple('TestDataRule',
['name', 'ruletype', 'user', 'subject'])
class BaseTestTrust(IntegrationTest):
num_clients = 1
@@ -246,6 +251,150 @@ class TestTrust(BaseTestTrust):
self.master.run_command(['kinit', '-C', '-E', self.upn_principal],
stdin_text=self.upn_password)
@contextmanager
def check_sudorules_for(self, object_type, object_name,
testuser, expected):
"""Verify trusted domain objects can be added to sudorules"""
# Create a SUDO rule that allows test user
# to run any command on any host as root without password
# and check that it is indeed possible to do so with sudo -l
hbacrule = 'hbacsudoers-' + object_type
sudorule = 'testrule-' + object_type
commands = [['ipa', 'hbacrule-add', hbacrule,
'--usercat=all', '--hostcat=all'],
['ipa', 'hbacrule-add-service', hbacrule,
'--hbacsvcs=sudo'],
['ipa', 'sudocmd-add', 'ALL'],
['ipa', 'sudorule-add', sudorule, '--hostcat=all'],
['ipa', 'sudorule-add-user', sudorule,
'--users', object_name],
['ipa', 'sudorule-add-option', sudorule,
'--sudooption', '!authenticate'],
['ipa', 'sudorule-add-allow-command', sudorule,
'--sudocmds', 'ALL']]
for c in commands:
self.master.run_command(c)
# allow additional configuration
yield TestDataRule(sudorule, 'sudo', object_name, testuser)
# Modify refresh_expired_interval to reduce time for refreshing
# expired entries in SSSD cache in order to avoid waiting at least
# 30 seconds before SSSD updates SUDO rules and undertermined time
# that takes to refresh the rules.
sssd_conf_backup = tasks.FileBackup(self.master, paths.SSSD_CONF)
try:
with tasks.remote_sssd_config(self.master) as sssd_conf:
sssd_conf.edit_domain(
self.master.domain, 'refresh_expired_interval', 1)
sssd_conf.edit_domain(
self.master.domain, 'entry_cache_timeout', 1)
tasks.clear_sssd_cache(self.master)
# Sleep some time so that SSSD settles down
# cache updates
time.sleep(10)
result = self.master.run_command(
['su', '-', testuser, '-c', 'sudo -l'])
if isinstance(expected, (tuple, list)):
assert any([x for x in expected if x in result.stdout_text])
else:
assert expected in result.stdout_text
finally:
sssd_conf_backup.restore()
tasks.clear_sssd_cache(self.master)
commands = [['ipa', 'sudorule-del', sudorule],
['ipa', 'sudocmd-del', 'ALL'],
['ipa', 'hbacrule-del', hbacrule]]
for c in commands:
self.master.run_command(c)
def test_sudorules_ad_users(self):
"""Verify trusted domain users can be added to sudorules"""
tasks.kdestroy_all(self.master)
tasks.kinit_admin(self.master)
testuser = '%s@%s' % (self.master.config.ad_admin_name, self.ad_domain)
expected = "(root) NOPASSWD: ALL"
with self.check_sudorules_for("user", testuser, testuser, expected):
# no additional configuration
pass
def test_sudorules_ad_groups(self):
"""Verify trusted domain groups can be added to sudorules"""
tasks.kdestroy_all(self.master)
tasks.kinit_admin(self.master)
testuser = '%s@%s' % (self.master.config.ad_admin_name, self.ad_domain)
testgroup = 'Enterprise Admins@%s' % self.ad_domain
expected = "(root) NOPASSWD: ALL"
with self.check_sudorules_for("group", testuser, testuser,
expected) as sudorule:
# Remove the user and instead add a group
self.master.run_command(['ipa',
'sudorule-remove-user', sudorule.name,
'--users', sudorule.user])
self.master.run_command(['ipa', 'sudorule-add-user', sudorule.name,
'--groups', testgroup])
def test_sudorules_ad_runasuser(self):
"""Verify trusted domain users can be added to runAsUser"""
tasks.kdestroy_all(self.master)
tasks.kinit_admin(self.master)
testuser = '%s@%s' % (self.master.config.ad_admin_name, self.ad_domain)
expected = "(%s) NOPASSWD: ALL" % (testuser.lower())
with self.check_sudorules_for("user", testuser, testuser,
expected) as sudorule:
# Add runAsUser with the same user
self.master.run_command(['ipa',
'sudorule-add-runasuser', sudorule.name,
'--users', sudorule.subject])
def test_sudorules_ad_runasuser_group(self):
"""Verify trusted domain groups can be added to runAsUser"""
tasks.kdestroy_all(self.master)
tasks.kinit_admin(self.master)
testuser = '%s@%s' % (self.master.config.ad_admin_name, self.ad_domain)
testgroup = 'Enterprise Admins@%s' % self.ad_domain
expected1 = '("%%%s") NOPASSWD: ALL' % testgroup.lower()
expected2 = '("%%%%%s") NOPASSWD: ALL' % testgroup.lower()
with self.check_sudorules_for("group", testuser, testuser,
[expected1, expected2]) as sudorule:
# Add runAsUser with the same user
self.master.run_command(['ipa',
'sudorule-add-runasuser',
sudorule.name,
'--groups', testgroup])
def test_sudorules_ad_runasgroup(self):
"""Verify trusted domain groups can be added to runAsGroup"""
tasks.kdestroy_all(self.master)
tasks.kinit_admin(self.master)
testuser = '%s@%s' % (self.master.config.ad_admin_name, self.ad_domain)
testgroup = 'Enterprise Admins@%s' % self.ad_domain
expected = '(%s : "%%%s") NOPASSWD: ALL' % (testuser.lower(),
testgroup.lower())
with self.check_sudorules_for("group", testuser, testuser,
expected) as sudorule:
# Add runAsGroup with the same user
self.master.run_command(['ipa',
'sudorule-add-runasgroup',
sudorule.name,
'--groups', testgroup])
def test_remove_nonposix_trust(self):
self.remove_trust(self.ad)
tasks.unconfigure_dns_for_trust(self.master, self.ad)
+2 -1
View File
@@ -723,7 +723,8 @@ class test_sudorule(XMLRPC_test):
self.rule_name, ipasudorunasusercategory=u'all'
)
finally:
api.Command['sudorule_remove_runasuser'](self.rule_name, user=self.test_user)
api.Command['sudorule_remove_runasuser'](self.rule_name,
user=self.test_user)
def test_j_2_sudorule_referential_integrity(self):
"""