freeipa/ipatests/test_integration/test_crlgen_manage.py

310 lines
12 KiB
Python
Raw Normal View History

#
# Copyright (C) 2018 FreeIPA Contributors see COPYING for license
#
"""
Module provides tests for the ipa-crlgen-manage command.
"""
from __future__ import absolute_import
import os
from cryptography.hazmat.backends import default_backend
from cryptography import x509
from ipaplatform.paths import paths
from ipatests.pytest_ipa.integration import tasks
from ipatests.test_integration.base import IntegrationTest
CRLGEN_STATUS_ENABLED = 'enabled'
CRLGEN_STATUS_DISABLED = 'disabled'
CRL_FILENAME = os.path.join(paths.PKI_CA_PUBLISH_DIR, 'MasterCRL.bin')
def check_crlgen_status(host, rc=0, msg=None, enabled=True, check_crl=False):
"""Checks that CRLGen is configured as expected
:param host: The host where ;ipa-crlgen-manage status' command is run
:param rc: the expected result code
:param msg: the expected msg in stderr
:param enabled: the expected status
:param check_crl: if True we expect a Master.bin CRL file
If enabled:
ipa-crlgen-manage status must return 'CRL generation: enabled'
and print the last CRL update date and number if crl_present=True.
If disabled:
ipa-crlgen-manage status must return 'CRL generation: disabled'
"""
result = host.run_command(['ipa-crlgen-manage', 'status'],
raiseonerr=False)
assert result.returncode == rc
if msg:
assert msg in result.stderr_text
if rc == 0:
status = CRLGEN_STATUS_ENABLED if enabled else CRLGEN_STATUS_DISABLED
assert 'CRL generation: {}'.format(status) in result.stdout_text
if check_crl and enabled:
# We expect CRL generation to be enabled and need to check for
# MasterCRL.bin
crl_content = host.get_file_contents(CRL_FILENAME)
crl = x509.load_der_x509_crl(crl_content, default_backend())
last_update_msg = 'Last CRL update: {}'.format(crl.last_update)
assert last_update_msg in result.stdout_text
for ext in crl.extensions:
if ext.oid == x509.oid.ExtensionOID.CRL_NUMBER:
number_msg = "Last CRL Number: {}".format(
ext.value.crl_number)
assert number_msg in result.stdout_text
def check_crlgen_enable(host, rc=0, msg=None, check_crl=False):
"""Check ipa-crlgen-manage enable command
Launch ipa-crlgen-manage command and check the result code and output
"""
result = host.run_command(['ipa-crlgen-manage', 'enable'],
raiseonerr=False)
assert result.returncode == rc
if msg:
assert msg in result.stderr_text
if rc == 0:
# check ipa-crlgen-manage status is consistent
check_crlgen_status(host, enabled=True, check_crl=check_crl)
def check_crlgen_disable(host, rc=0, msg=None):
"""Check ipa-crlgen-manage disable command
Launch ipa-crlgen-manage command and check the result code and output
"""
result = host.run_command(['ipa-crlgen-manage', 'disable'],
raiseonerr=False)
assert result.returncode == rc
if msg:
assert msg in result.stderr_text
if rc == 0:
# check ipa-crlgen-manage status is consistent
check_crlgen_status(host, enabled=False)
def break_crlgen_with_rewriterule(host):
"""Create an inconsistent configuration on a CRL master
In the file /etc/httpd/conf.d/ipa-pki-proxy.conf, add a RewriteRule that
should be present only on non-CRL master"""
content = host.get_file_contents(paths.HTTPD_IPA_PKI_PROXY_CONF,
encoding='utf-8')
new_content = content + "\nRewriteRule ^/ipa/crl/MasterCRL.bin " \
"https://{}/ca/ee/ca/getCRL?op=getCRL&crlIssuingPoint=MasterCRL " \
"[L,R=301,NC]".format(host.hostname)
host.put_file_contents(paths.HTTPD_IPA_PKI_PROXY_CONF, new_content)
check_crlgen_status(host, rc=1, msg="Configuration is inconsistent")
def break_crlgen_with_CS_cfg(host):
"""Create an inconsistent configuration on a CRL master
Add a enableCRLUpdates=false directive that should be present only on
non-CRL master"""
content = host.get_file_contents(paths.CA_CS_CFG_PATH,
encoding='utf-8')
new_lines = []
for line in content.split('\n'):
if line.startswith('ca.crl.MasterCRL.enableCRLCache'):
new_lines.append("ca.crl.MasterCRL.enableCRLCache=false")
else:
new_lines.append(line)
host.put_file_contents(paths.CA_CS_CFG_PATH, '\n'.join(new_lines))
check_crlgen_status(host, rc=1, msg="Configuration is inconsistent")
class TestCRLGenManage(IntegrationTest):
"""Tests the ipa-crlgen-manage command.
ipa-crlgen-manage can be used to enable, disable or check
the status of CRL generation.
"""
num_replicas = 1
@classmethod
def install(cls, mh):
# Install a master and check CRL status (=enabled)
tasks.install_master(cls.master)
# We don't check for MasterCRL.bin presence because it may not
# be generated right after the install
check_crlgen_status(cls.master, enabled=True)
def test_master_enable_crlgen_already_enabled(self):
"""Test ipa-crlgen-manage enable on an already enabled instance"""
# We don't check for MasterCRL.bin presence because it may not
# be generated right after the install
check_crlgen_enable(
self.master, rc=0,
msg="Nothing to do, CRL generation already enabled")
def test_master_disable_crlgen(self):
"""Test ipa-crlgen-manage disable on an enabled instance"""
check_crlgen_disable(
self.master, rc=0,
msg="make sure to configure CRL generation on another master")
def test_master_disable_crlgen_already_disabled(self):
"""Test ipa-crlgen-manage disable on an enabled instance"""
check_crlgen_disable(
self.master, rc=0,
msg="Nothing to do, CRL generation already disabled")
def test_master_enable_crlgen(self):
"""Test ipa-crlgen-manage enable on a disabled instance"""
# This time we check that MasterCRL.bin is present
check_crlgen_enable(
self.master, rc=0,
msg="make sure to have only a single CRL generation master",
check_crl=True)
def test_crlgen_status_on_replica(self):
"""Test crlgen status on a replica without CA
Install a replica without CA
then call ipa-crlgen-manage status.
"""
tasks.install_replica(self.master, self.replicas[0], setup_ca=False)
check_crlgen_status(self.replicas[0], enabled=False)
def test_crlgen_disable_on_caless_replica(self):
"""Test crlgen disable on a replica without CA"""
check_crlgen_disable(
self.replicas[0], rc=0,
msg="Warning: Dogtag CA is not installed on this server")
def test_crlgen_enable_on_caless_replica(self):
"""Test crlgen enable on a replica without CA"""
check_crlgen_enable(
self.replicas[0], rc=1,
msg="Dogtag CA is not installed. Please install a CA first")
def test_crlgen_enable_on_ca_replica(self):
"""Test crlgen enable on a replica with CA
Install a CA clone and enable CRLgen"""
tasks.install_ca(self.replicas[0])
check_crlgen_enable(
self.replicas[0], rc=0,
msg="make sure to have only a single CRL generation master",
check_crl=True)
def test_crlgen_enable_on_broken_master(self):
"""Test crlgen enable on master with inconsistent config
Break the (enabled) master config by setting the rewriterule
and call enable"""
# Make sure the config is enabled
check_crlgen_enable(self.master)
# Break the config with RewriteRule
break_crlgen_with_rewriterule(self.master)
# Call enable to repair
check_crlgen_enable(
self.master, rc=0,
msg="CRL generation is partially enabled, repairing...",
check_crl=True)
def test_crlgen_disable_on_broken_master(self):
"""Test crlgen disable on master with inconsistent config
Break the (enabled) master config by setting the rewriterule
and call disable"""
# Make sure the config is enabled
check_crlgen_enable(self.master)
# Break the config with RewriteRule
break_crlgen_with_rewriterule(self.master)
# Call disable to repair
check_crlgen_disable(
self.master, rc=0,
msg="CRL generation is partially enabled, repairing...")
def test_crlgen_enable_on_broken_replica(self):
"""Test crlgen enable on replica with inconsistent config
Break the (enabled) replica config by setting enableCRLUpdates=false
and call enable"""
# Make sure the config is enabled
check_crlgen_enable(self.replicas[0])
# Break the config with RewriteRule
break_crlgen_with_CS_cfg(self.replicas[0])
# Call enable to repair
check_crlgen_enable(
self.replicas[0], rc=0,
msg="CRL generation is partially enabled, repairing...",
check_crl=True)
def test_crlgen_disable_on_broken_replica(self):
"""Test crlgen disable on replica with inconsistent config
Break the (enabled) replica config by setting enableCRLUpdates=false
and call disable"""
# Make sure the config is enabled
check_crlgen_enable(self.replicas[0])
# Break the config with RewriteRule
break_crlgen_with_CS_cfg(self.replicas[0])
# Call disable to repair
check_crlgen_disable(
self.replicas[0], rc=0,
msg="CRL generation is partially enabled, repairing...")
def test_uninstall_without_ignore_last_of_role(self):
"""Test uninstallation of the CRL generation master
If --ignore-last-of-role is not provided, uninstall prints a msg
and exits on error.
"""
# Make sure CRL gen is enabled on the master
check_crlgen_enable(self.master)
# call uninstall without --ignore-last-of-role, should be refused
result = self.master.run_command(
['ipa-server-install', '--uninstall', '-U'], raiseonerr=False)
assert result.returncode == 1
expected_msg = "Deleting this server will leave your installation " \
"without a CRL generation master"
assert expected_msg in result.stdout_text
def test_uninstall_with_ignore_last_of_role(self):
"""Test uninstallation of the CRL generation master
When --ignore-last-of-role is provided, uninstall prints a msg but
gets executed.
"""
# Make sure CRL gen is enabled on the master
check_crlgen_enable(self.master)
# call uninstall with --ignore-last-of-role, should be OK
result = self.master.run_command(
['ipa-server-install', '--uninstall', '-U',
'--ignore-last-of-role'])
expected_msg = "Deleting this server will leave your installation " \
"without a CRL generation master"
assert expected_msg in result.stdout_text
tasks.run_server_del(
self.replicas[0], self.master.hostname, force=True,
ignore_topology_disconnect=True,
ignore_last_of_role=True)
def test_uninstall_last_master_does_not_require_ignore_last_of_role(self):
"""Test uninstallation of the last master
Even if the host is CRL generation master, uninstall must proceed
even without --ignore-last-of-role because we are removing the last
master.
"""
# Make sure CRL gen is enabled on the replica
check_crlgen_enable(self.replicas[0])
# call uninstall without --ignore-last-of-role, should be OK
self.replicas[0].run_command(
['ipa-server-install', '--uninstall', '-U'])