freeipa/ipatests/test_integration/test_krbtpolicy.py
Alexander Bokovoy 517ae594e1 test_krbtpolicy: skip SPAKE-related tests in FIPS mode
SPAKE is based on the crypto primitives which are not FIPS compliant
yet. This means that in FIPS mode use of 'hardened' authentication
indicator is not possible. Skip corresponding tests in FIPS mode.

Related: https://pagure.io/freeipa/issue/9119

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
2022-03-16 11:14:35 +02:00

317 lines
12 KiB
Python

#
# Copyright (C) 2019,2020 FreeIPA Contributors see COPYING for license
#
"""
Module provides tests for Kerberos ticket policy options
"""
from __future__ import absolute_import
import pytest
import time
from datetime import datetime
from ipalib.constants import IPAAPI_USER
from ipaplatform.paths import paths
from ipatests.test_integration.base import IntegrationTest
from ipatests.test_integration.test_otp import add_otptoken, del_otptoken
from ipatests.pytest_ipa.integration import tasks
PASSWORD = "Secret123"
USER1 = "testuser1"
USER2 = "testuser2"
MAXLIFE = 86400
def maxlife_within_policy(input, maxlife, slush=3600):
"""Given klist output of the TGT verify that it is within policy
Ensure that the validity period is somewhere within the
absolute maxlife and a slush value, maxlife - slush.
Returns True if within policy.
Input should be a string like:
11/19/2019 16:37:40 11/20/2019 16:37:39 krbtgt/...
slush defaults to 1 * 60 * 60 matching the jitter window.
"""
data = input.split()
start = datetime.strptime(data[0] + ' ' + data[1], '%m/%d/%Y %H:%M:%S')
end = datetime.strptime(data[2] + ' ' + data[3], '%m/%d/%Y %H:%M:%S')
diff = int((end - start).total_seconds())
return maxlife >= diff >= maxlife - slush
@pytest.fixture
def reset_to_default_policy():
"""Reset default user authentication and user authentication type"""
state = dict()
def _reset_to_default_policy(host, user=None):
state['host'] = host
state['user'] = user
yield _reset_to_default_policy
host = state['host']
user = state['user']
tasks.kinit_admin(host)
host.run_command(['ipa', 'krbtpolicy-reset'])
if user:
host.run_command(['ipa', 'user-mod', user, '--user-auth-type='])
host.run_command(['ipa', 'krbtpolicy-reset', user])
def kinit_check_life(master, user):
"""Acquire a TGT and check if it's within the lifetime window"""
master.run_command(["kinit", user], stdin_text=f"{PASSWORD}\n")
result = master.run_command("klist | grep krbtgt")
assert maxlife_within_policy(result.stdout_text, MAXLIFE) is True
class TestPWPolicy(IntegrationTest):
"""Tests password custom and default password policies.
"""
num_replicas = 0
@classmethod
def install(cls, mh):
tasks.install_master(cls.master)
tasks.create_active_user(cls.master, USER1, PASSWORD)
tasks.create_active_user(cls.master, USER2, PASSWORD)
@pytest.fixture(autouse=True, scope="function")
def with_admin(self):
tasks.kinit_admin(self.master)
yield
tasks.kdestroy_all(self.master)
def test_krbtpolicy_default(self):
"""Test the default kerberos ticket policy 24-hr tickets"""
master = self.master
master.run_command(['ipa', 'krbtpolicy-mod', USER1,
'--maxlife', str(MAXLIFE)])
tasks.kdestroy_all(master)
master.run_command(['kinit', USER1],
stdin_text=PASSWORD + '\n')
result = master.run_command('klist | grep krbtgt')
assert maxlife_within_policy(result.stdout_text, MAXLIFE) is True
def test_krbtpolicy_password_and_hardended(self):
"""Test a pwd and hardened kerberos ticket policy with 10min tickets"""
if self.master.is_fips_mode:
pytest.skip("SPAKE pre-auth is not compatible with FIPS mode")
master = self.master
master.run_command(['ipa', 'user-mod', USER1,
'--user-auth-type', 'password',
'--user-auth-type', 'hardened'])
master.run_command(['ipa', 'config-mod',
'--user-auth-type', 'password',
'--user-auth-type', 'hardened'])
master.run_command(['ipa', 'krbtpolicy-mod', USER1,
'--hardened-maxlife', '600'])
tasks.kdestroy_all(master)
master.run_command(['kinit', USER1],
stdin_text=PASSWORD + '\n')
result = master.run_command('klist | grep krbtgt')
assert maxlife_within_policy(result.stdout_text, 600,
slush=600) is True
tasks.kdestroy_all(master)
# Verify that the short policy only applies to USER1
master.run_command(['kinit', USER2],
stdin_text=PASSWORD + '\n')
result = master.run_command('klist | grep krbtgt')
assert maxlife_within_policy(result.stdout_text, MAXLIFE) is True
def test_krbtpolicy_hardended(self):
"""Test a hardened kerberos ticket policy with 30min tickets"""
if self.master.is_fips_mode:
pytest.skip("SPAKE pre-auth is not compatible with FIPS mode")
master = self.master
master.run_command(['ipa', 'user-mod', USER1,
'--user-auth-type', 'hardened'])
master.run_command(['ipa', 'config-mod',
'--user-auth-type', 'hardened'])
master.run_command(['ipa', 'krbtpolicy-mod', USER1,
'--hardened-maxlife', '1800'])
tasks.kdestroy_all(master)
master.run_command(['kinit', USER1],
stdin_text=PASSWORD + '\n')
result = master.run_command('klist | grep krbtgt')
assert maxlife_within_policy(result.stdout_text, 1800,
slush=1800) is True
tasks.kdestroy_all(master)
# Verify that the short policy only applies to USER1
master.run_command(['kinit', USER2],
stdin_text=PASSWORD + '\n')
result = master.run_command('klist | grep krbtgt')
assert maxlife_within_policy(result.stdout_text, MAXLIFE) is True
def test_krbtpolicy_password(self):
"""Test the kerberos ticket policy which issues 20 min tickets"""
master = self.master
master.run_command(['ipa', 'krbtpolicy-mod', USER2,
'--maxlife', '1200'])
tasks.kdestroy_all(master)
master.run_command(['kinit', USER2],
stdin_text=PASSWORD + '\n')
result = master.run_command('klist | grep krbtgt')
assert maxlife_within_policy(result.stdout_text, 1200,
slush=1200) is True
def test_krbtpolicy_reset(self):
"""Test a hardened kerberos ticket policy reset"""
master = self.master
master.run_command(['ipa', 'krbtpolicy-reset', USER2])
master.run_command(['kinit', USER2],
stdin_text=PASSWORD + '\n')
result = master.run_command('klist | grep krbtgt')
assert maxlife_within_policy(result.stdout_text, MAXLIFE) is True
def test_krbtpolicy_otp(self, reset_to_default_policy):
"""Test otp ticket policy"""
master = self.master
master.run_command(['ipa', 'user-mod', USER1,
'--user-auth-type', 'otp'])
master.run_command(['ipa', 'config-mod',
'--user-auth-type', 'otp'])
master.run_command(['ipa', 'krbtpolicy-mod', USER1,
'--otp-maxrenew=90', '--otp-maxlife=60'])
armor = tasks.create_temp_file(self.master, create_file=False)
otpuid, totp = add_otptoken(master, USER1, otptype="totp")
otpvalue = totp.generate(int(time.time())).decode("ascii")
reset_to_default_policy(master, USER1)
try:
tasks.kdestroy_all(master)
# create armor for FAST
master.run_command(['kinit', '-n', '-c', armor])
# expect ticket expire in otp-maxlife=60 seconds
master.run_command(
['kinit', '-T', armor, USER1, '-r', '90'],
stdin_text='{0}{1}\n'.format(PASSWORD, otpvalue))
master.run_command(['ipa', 'user-find', USER1])
time.sleep(30)
# when user kerberos ticket expired but still within renew time,
# kinit -R should give user new life
master.run_command(['kinit', '-R', USER1])
master.run_command(['ipa', 'user-find', USER1])
time.sleep(60)
# when renew time expires, kinit -R should fail
result1 = master.run_command(['kinit', '-R', USER1],
raiseonerr=False)
tasks.assert_error(
result1,
"kinit: Ticket expired while renewing credentials", 1)
master.run_command(['ipa', 'user-find', USER1],
ok_returncode=1)
finally:
del_otptoken(master, otpuid)
self.master.run_command(['rm', '-f', armor])
master.run_command(['ipa', 'config-mod', '--user-auth-type='])
def test_krbtpolicy_jitter(self):
"""Test jitter lifetime with no auth indicators"""
kinit_check_life(self.master, USER1)
def test_krbtpolicy_jitter_otp(self, reset_to_default_policy):
"""Test jitter lifetime with OTP"""
reset_to_default_policy(self.master, USER1)
self.master.run_command(["ipa", "user-mod", USER1,
"--user-auth-type", "otp"])
kinit_check_life(self.master, USER1)
def test_ccache_sweep_expired(self, reset_to_default_policy):
"""Test that the ccache sweeper works on expired ccaches
- Force wipe all existing ccaches
- Set the ticket policy to a short value, 20 seconds.
- Do a series of kinit, ipa command, kdestroy to generate ccaches
- sleep() for expiration
- Run the sweeper
- Verify that all expired ccaches are gone
"""
MAXLIFE = 20
reset_to_default_policy(self.master) # this will reset at END of test
tasks.kinit_admin(self.master)
self.master.run_command(
['ipa', 'krbtpolicy-mod', '--maxlife', str(MAXLIFE)]
)
tasks.kdestroy_all(self.master)
self.master.run_command(
['find', paths.IPA_CCACHES, '-type', 'f', '-delete']
)
for _i in range(5):
tasks.kinit_admin(self.master)
self.master.run_command(['ipa', 'user-show', 'admin'])
tasks.kdestroy_all(self.master)
result = self.master.run_command(
"ls -1 {0} | wc -l".format(paths.IPA_CCACHES)
)
assert int(result.stdout_text.strip()) == 5
# let ccache expire
time.sleep(MAXLIFE)
ccache_sweep_cmd = ["/usr/libexec/ipa/ipa-ccache-sweeper", "-m", "0"]
# should be run as ipaapi for GSSProxy
self.master.run_command(
["runuser", "-u", IPAAPI_USER, "--"] + ccache_sweep_cmd
)
result = self.master.run_command(
"ls -1 {0} | wc -l".format(paths.IPA_CCACHES)
)
assert int(result.stdout_text.strip()) == 0
def test_ccache_sweep_valid(self):
"""Test that the ccache sweeper doesn't remove valid ccaches
- Force wipe all existing ccaches
- Run the sweeper
- Verify that all valid ccaches weren't removed
Note: assumed that ccache expiration doesn't happen during test
"""
tasks.kdestroy_all(self.master)
self.master.run_command(
["find", paths.IPA_CCACHES, "-type", "f", "-delete"]
)
for _i in range(5):
tasks.kinit_admin(self.master)
self.master.run_command(["ipa", "user-show", "admin"])
tasks.kdestroy_all(self.master)
result = self.master.run_command(
"ls -1 {0} | wc -l".format(paths.IPA_CCACHES)
)
assert int(result.stdout_text.strip()) == 5
ccache_sweep_cmd = ["/usr/libexec/ipa/ipa-ccache-sweeper", "-m", "0"]
# should be run as ipaapi for GSSProxy
self.master.run_command(
["runuser", "-u", IPAAPI_USER, "--"] + ccache_sweep_cmd
)
result = self.master.run_command(
"ls -1 {0} | wc -l".format(paths.IPA_CCACHES)
)
assert int(result.stdout_text.strip()) == 5