Reformat everything with black.

I had to undo the u string prefix removals to not drop Python 2 compatibility.
That's why black isn't enabled in antsibull-nox.toml yet.
This commit is contained in:
Felix Fontein
2025-04-28 09:51:33 +02:00
parent 04a0d38e3b
commit aec1826c34
118 changed files with 11780 additions and 7565 deletions

View File

@@ -25,60 +25,60 @@ from ..test_time import TIMEZONES, cartesian_product
def load_fixture(name):
with open(os.path.join(os.path.dirname(__file__), 'fixtures', name)) as f:
with open(os.path.join(os.path.dirname(__file__), "fixtures", name)) as f:
return f.read()
TEST_PEM_DERS = [
(
load_fixture('privatekey_1.pem'),
base64.b64decode('MHcCAQEEIDWajU0PyhYKeulfy/luNtkAve7DkwQ01bXJ97zbxB66oAo'
'GCCqGSM49AwEHoUQDQgAEAJz0yAAXAwEmOhTRkjXxwgedbWO6gobYM3'
'lWszrS68G8QSzhXR6AmQ3IzZDimnTTXO7XhVylDT8SLzE44/Epmw==')
load_fixture("privatekey_1.pem"),
base64.b64decode(
"MHcCAQEEIDWajU0PyhYKeulfy/luNtkAve7DkwQ01bXJ97zbxB66oAo"
"GCCqGSM49AwEHoUQDQgAEAJz0yAAXAwEmOhTRkjXxwgedbWO6gobYM3"
"lWszrS68G8QSzhXR6AmQ3IzZDimnTTXO7XhVylDT8SLzE44/Epmw=="
),
)
]
TEST_KEYS = [
(
load_fixture('privatekey_1.pem'),
load_fixture("privatekey_1.pem"),
{
'alg': 'ES256',
'hash': 'sha256',
'jwk': {
'crv': 'P-256',
'kty': 'EC',
'x': 'AJz0yAAXAwEmOhTRkjXxwgedbWO6gobYM3lWszrS68E',
'y': 'vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs',
"alg": "ES256",
"hash": "sha256",
"jwk": {
"crv": "P-256",
"kty": "EC",
"x": "AJz0yAAXAwEmOhTRkjXxwgedbWO6gobYM3lWszrS68E",
"y": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
},
'point_size': 32,
'type': 'ec',
"point_size": 32,
"type": "ec",
},
load_fixture('privatekey_1.txt'),
load_fixture("privatekey_1.txt"),
)
]
TEST_CSRS = [
(
load_fixture('csr_1.pem'),
set([
('dns', 'ansible.com'),
('dns', 'example.com'),
('dns', 'example.org')
]),
load_fixture('csr_1.txt'),
load_fixture("csr_1.pem"),
set([("dns", "ansible.com"), ("dns", "example.com"), ("dns", "example.org")]),
load_fixture("csr_1.txt"),
),
(
load_fixture('csr_2.pem'),
set([
('dns', 'ansible.com'),
('ip', '127.0.0.1'),
('ip', '::1'),
('ip', '2001:d88:ac10:fe01::'),
('ip', '2001:1234:5678:abcd:9876:5432:10fe:dcba')
]),
load_fixture('csr_2.txt'),
load_fixture("csr_2.pem"),
set(
[
("dns", "ansible.com"),
("ip", "127.0.0.1"),
("ip", "::1"),
("ip", "2001:d88:ac10:fe01::"),
("ip", "2001:1234:5678:abcd:9876:5432:10fe:dcba"),
]
),
load_fixture("csr_2.txt"),
),
]
@@ -92,18 +92,21 @@ TEST_CERT_OPENSSL_OUTPUT_2 = load_fixture("cert_2.txt") # OpenSSL 3.3.0 output
TEST_CERT_OPENSSL_OUTPUT_2B = load_fixture("cert_2-b.txt") # OpenSSL 1.1.1f output
TEST_CERT_DAYS = cartesian_product(TIMEZONES, [
(datetime.datetime(2018, 11, 15, 1, 2, 3), 11),
(datetime.datetime(2018, 11, 25, 15, 20, 0), 1),
(datetime.datetime(2018, 11, 25, 15, 30, 0), 0),
])
TEST_CERT_DAYS = cartesian_product(
TIMEZONES,
[
(datetime.datetime(2018, 11, 15, 1, 2, 3), 11),
(datetime.datetime(2018, 11, 25, 15, 20, 0), 1),
(datetime.datetime(2018, 11, 25, 15, 30, 0), 0),
],
)
TEST_CERT_INFO = CertificateInformation(
not_valid_after=datetime.datetime(2018, 11, 26, 15, 28, 24),
not_valid_before=datetime.datetime(2018, 11, 25, 15, 28, 23),
serial_number=1,
subject_key_identifier=b'\x98\xD2\xFD\x3C\xCC\xCD\x69\x45\xFB\xE2\x8C\x30\x2C\x54\x62\x18\x34\xB7\x07\x73',
subject_key_identifier=b"\x98\xd2\xfd\x3c\xcc\xcd\x69\x45\xfb\xe2\x8c\x30\x2c\x54\x62\x18\x34\xb7\x07\x73",
authority_key_identifier=None,
)
@@ -112,8 +115,8 @@ TEST_CERT_INFO_2 = CertificateInformation(
not_valid_before=datetime.datetime(2024, 5, 4, 20, 42, 21),
not_valid_after=datetime.datetime(2029, 5, 4, 20, 42, 20),
serial_number=4218235397573492796,
subject_key_identifier=b'\x17\xE5\x83\x22\x14\xEF\x74\xD3\xBE\x7E\x30\x76\x56\x1F\x51\x74\x65\x1F\xE9\xF0',
authority_key_identifier=b'\x13\xC3\x4C\x3E\x59\x45\xDD\xE3\x63\x51\xA3\x46\x80\xC4\x08\xC7\x14\xC0\x64\x4E',
subject_key_identifier=b"\x17\xe5\x83\x22\x14\xef\x74\xd3\xbe\x7e\x30\x76\x56\x1f\x51\x74\x65\x1f\xe9\xf0",
authority_key_identifier=b"\x13\xc3\x4c\x3e\x59\x45\xdd\xe3\x63\x51\xa3\x46\x80\xc4\x08\xc7\x14\xc0\x64\x4e",
)
@@ -124,77 +127,112 @@ TEST_CERT_INFO = [
]
TEST_PARSE_ACME_TIMESTAMP = cartesian_product(TIMEZONES, [
(
'2024-01-01T00:11:22Z',
dict(year=2024, month=1, day=1, hour=0, minute=11, second=22),
),
(
'2024-01-01T00:11:22.123Z',
dict(year=2024, month=1, day=1, hour=0, minute=11, second=22, microsecond=123000),
),
(
'2024-04-17T06:54:13.333333334Z',
dict(year=2024, month=4, day=17, hour=6, minute=54, second=13, microsecond=333333),
),
])
TEST_PARSE_ACME_TIMESTAMP = cartesian_product(
TIMEZONES,
[
(
"2024-01-01T00:11:22Z",
dict(year=2024, month=1, day=1, hour=0, minute=11, second=22),
),
(
"2024-01-01T00:11:22.123Z",
dict(
year=2024,
month=1,
day=1,
hour=0,
minute=11,
second=22,
microsecond=123000,
),
),
(
"2024-04-17T06:54:13.333333334Z",
dict(
year=2024,
month=4,
day=17,
hour=6,
minute=54,
second=13,
microsecond=333333,
),
),
],
)
if sys.version_info >= (3, 5):
TEST_PARSE_ACME_TIMESTAMP.extend(cartesian_product(TIMEZONES, [
(
'2024-01-01T00:11:22+0100',
dict(year=2023, month=12, day=31, hour=23, minute=11, second=22),
),
(
'2024-01-01T00:11:22.123+0100',
dict(year=2023, month=12, day=31, hour=23, minute=11, second=22, microsecond=123000),
),
]))
TEST_PARSE_ACME_TIMESTAMP.extend(
cartesian_product(
TIMEZONES,
[
(
"2024-01-01T00:11:22+0100",
dict(year=2023, month=12, day=31, hour=23, minute=11, second=22),
),
(
"2024-01-01T00:11:22.123+0100",
dict(
year=2023,
month=12,
day=31,
hour=23,
minute=11,
second=22,
microsecond=123000,
),
),
],
)
)
TEST_INTERPOLATE_TIMESTAMP = cartesian_product(TIMEZONES, [
(
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
0.0,
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
),
(
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
0.5,
dict(year=2024, month=1, day=1, hour=0, minute=30, second=0),
),
(
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
1.0,
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
),
])
TEST_INTERPOLATE_TIMESTAMP = cartesian_product(
TIMEZONES,
[
(
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
0.0,
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
),
(
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
0.5,
dict(year=2024, month=1, day=1, hour=0, minute=30, second=0),
),
(
dict(year=2024, month=1, day=1, hour=0, minute=0, second=0),
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
1.0,
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
),
],
)
class FakeBackend(CryptoBackend):
def parse_key(self, key_file=None, key_content=None, passphrase=None):
raise BackendException('Not implemented in fake backend')
raise BackendException("Not implemented in fake backend")
def sign(self, payload64, protected64, key_data):
raise BackendException('Not implemented in fake backend')
raise BackendException("Not implemented in fake backend")
def create_mac_key(self, alg, key):
raise BackendException('Not implemented in fake backend')
raise BackendException("Not implemented in fake backend")
def get_ordered_csr_identifiers(self, csr_filename=None, csr_content=None):
raise BackendException('Not implemented in fake backend')
raise BackendException("Not implemented in fake backend")
def get_csr_identifiers(self, csr_filename=None, csr_content=None):
raise BackendException('Not implemented in fake backend')
raise BackendException("Not implemented in fake backend")
def get_cert_days(self, cert_filename=None, cert_content=None, now=None):
raise BackendException('Not implemented in fake backend')
raise BackendException("Not implemented in fake backend")
def create_chain_matcher(self, criterium):
raise BackendException('Not implemented in fake backend')
raise BackendException("Not implemented in fake backend")
def get_cert_information(self, cert_filename=None, cert_content=None):
raise BackendException('Not implemented in fake backend')
raise BackendException("Not implemented in fake backend")

View File

@@ -39,26 +39,26 @@ from .backend_data import (
if not HAS_CURRENT_CRYPTOGRAPHY:
pytest.skip('cryptography not found')
pytest.skip("cryptography not found")
@pytest.mark.parametrize("pem, result, dummy", TEST_KEYS)
def test_eckeyparse_cryptography(pem, result, dummy, tmpdir):
fn = tmpdir / 'test.pem'
fn = tmpdir / "test.pem"
fn.write(pem)
module = MagicMock()
backend = CryptographyBackend(module)
key = backend.parse_key(key_file=str(fn))
key.pop('key_obj')
key.pop("key_obj")
assert key == result
key = backend.parse_key(key_content=pem)
key.pop('key_obj')
key.pop("key_obj")
assert key == result
@pytest.mark.parametrize("csr, result, openssl_output", TEST_CSRS)
def test_csridentifiers_cryptography(csr, result, openssl_output, tmpdir):
fn = tmpdir / 'test.csr'
fn = tmpdir / "test.csr"
fn.write(csr)
module = MagicMock()
backend = CryptographyBackend(module)
@@ -71,7 +71,7 @@ def test_csridentifiers_cryptography(csr, result, openssl_output, tmpdir):
@pytest.mark.parametrize("timezone, now, expected_days", TEST_CERT_DAYS)
def test_certdays_cryptography(timezone, now, expected_days, tmpdir):
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
fn = tmpdir / 'test-cert.pem'
fn = tmpdir / "test-cert.pem"
fn.write(TEST_CERT)
module = MagicMock()
backend = CryptographyBackend(module)
@@ -81,9 +81,11 @@ def test_certdays_cryptography(timezone, now, expected_days, tmpdir):
assert days == expected_days
@pytest.mark.parametrize("cert_content, expected_cert_info, openssl_output", TEST_CERT_INFO)
@pytest.mark.parametrize(
"cert_content, expected_cert_info, openssl_output", TEST_CERT_INFO
)
def test_get_cert_information(cert_content, expected_cert_info, openssl_output, tmpdir):
fn = tmpdir / 'test-cert.pem'
fn = tmpdir / "test-cert.pem"
fn.write(cert_content)
module = MagicMock()
backend = CryptographyBackend(module)
@@ -103,7 +105,9 @@ def test_get_cert_information(cert_content, expected_cert_info, openssl_output,
# @pytest.mark.parametrize("timezone", TIMEZONES)
# Due to a bug in freezegun (https://github.com/spulec/freezegun/issues/348, https://github.com/spulec/freezegun/issues/553)
# this only works with timezone = UTC if CRYPTOGRAPHY_TIMEZONE is truish
@pytest.mark.parametrize("timezone", [datetime.timedelta(hours=0)] if CRYPTOGRAPHY_TIMEZONE else TIMEZONES)
@pytest.mark.parametrize(
"timezone", [datetime.timedelta(hours=0)] if CRYPTOGRAPHY_TIMEZONE else TIMEZONES
)
def test_now(timezone):
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
module = MagicMock()
@@ -127,7 +131,9 @@ def test_parse_acme_timestamp(timezone, input, expected):
assert ts_expected == timestamp
@pytest.mark.parametrize("timezone, start, end, percentage, expected", TEST_INTERPOLATE_TIMESTAMP)
@pytest.mark.parametrize(
"timezone, start, end, percentage, expected", TEST_INTERPOLATE_TIMESTAMP
)
def test_interpolate_timestamp(timezone, start, end, percentage, expected):
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
module = MagicMock()

View File

@@ -51,23 +51,23 @@ TEST_IPS = [
@pytest.mark.parametrize("pem, result, openssl_output", TEST_KEYS)
def test_eckeyparse_openssl(pem, result, openssl_output, tmpdir):
fn = tmpdir / 'test.key'
fn = tmpdir / "test.key"
fn.write(pem)
module = MagicMock()
module.run_command = MagicMock(return_value=(0, openssl_output, 0))
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
backend = OpenSSLCLIBackend(module, openssl_binary="openssl")
key = backend.parse_key(key_file=str(fn))
key.pop('key_file')
key.pop("key_file")
assert key == result
@pytest.mark.parametrize("csr, result, openssl_output", TEST_CSRS)
def test_csridentifiers_openssl(csr, result, openssl_output, tmpdir):
fn = tmpdir / 'test.csr'
fn = tmpdir / "test.csr"
fn.write(csr)
module = MagicMock()
module.run_command = MagicMock(return_value=(0, openssl_output, 0))
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
backend = OpenSSLCLIBackend(module, openssl_binary="openssl")
identifiers = backend.get_csr_identifiers(str(fn))
assert identifiers == result
@@ -75,31 +75,33 @@ def test_csridentifiers_openssl(csr, result, openssl_output, tmpdir):
@pytest.mark.parametrize("ip, result", TEST_IPS)
def test_normalize_ip(ip, result):
module = MagicMock()
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
backend = OpenSSLCLIBackend(module, openssl_binary="openssl")
assert backend._normalize_ip(ip) == result
@pytest.mark.parametrize("timezone, now, expected_days", TEST_CERT_DAYS)
def test_certdays_cryptography(timezone, now, expected_days, tmpdir):
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
fn = tmpdir / 'test-cert.pem'
fn = tmpdir / "test-cert.pem"
fn.write(TEST_CERT)
module = MagicMock()
module.run_command = MagicMock(return_value=(0, TEST_CERT_OPENSSL_OUTPUT, 0))
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
backend = OpenSSLCLIBackend(module, openssl_binary="openssl")
days = backend.get_cert_days(cert_filename=str(fn), now=now)
assert days == expected_days
days = backend.get_cert_days(cert_content=TEST_CERT, now=now)
assert days == expected_days
@pytest.mark.parametrize("cert_content, expected_cert_info, openssl_output", TEST_CERT_INFO)
@pytest.mark.parametrize(
"cert_content, expected_cert_info, openssl_output", TEST_CERT_INFO
)
def test_get_cert_information(cert_content, expected_cert_info, openssl_output, tmpdir):
fn = tmpdir / 'test-cert.pem'
fn = tmpdir / "test-cert.pem"
fn.write(cert_content)
module = MagicMock()
module.run_command = MagicMock(return_value=(0, openssl_output, 0))
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
backend = OpenSSLCLIBackend(module, openssl_binary="openssl")
expected_cert_info = expected_cert_info._replace(
not_valid_after=ensure_utc_timezone(expected_cert_info.not_valid_after),
@@ -119,7 +121,7 @@ def test_get_cert_information(cert_content, expected_cert_info, openssl_output,
def test_now(timezone):
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
module = MagicMock()
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
backend = OpenSSLCLIBackend(module, openssl_binary="openssl")
now = backend.get_now()
assert now.tzinfo is not None
assert now == datetime.datetime(2024, 2, 3, 4, 5, 6, tzinfo=UTC)
@@ -129,17 +131,19 @@ def test_now(timezone):
def test_parse_acme_timestamp(timezone, input, expected):
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
module = MagicMock()
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
backend = OpenSSLCLIBackend(module, openssl_binary="openssl")
ts_expected = backend.get_utc_datetime(**expected)
timestamp = backend.parse_acme_timestamp(input)
assert ts_expected == timestamp
@pytest.mark.parametrize("timezone, start, end, percentage, expected", TEST_INTERPOLATE_TIMESTAMP)
@pytest.mark.parametrize(
"timezone, start, end, percentage, expected", TEST_INTERPOLATE_TIMESTAMP
)
def test_interpolate_timestamp(timezone, start, end, percentage, expected):
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
module = MagicMock()
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
backend = OpenSSLCLIBackend(module, openssl_binary="openssl")
ts_start = backend.get_utc_datetime(**start)
ts_end = backend.get_utc_datetime(**end)
ts_expected = backend.get_utc_datetime(**expected)

View File

@@ -25,16 +25,16 @@ from ansible_collections.community.internal_test_tools.tests.unit.compat.mock im
def test_combine_identifier():
assert combine_identifier('', '') == ':'
assert combine_identifier('a', 'b') == 'a:b'
assert combine_identifier("", "") == ":"
assert combine_identifier("a", "b") == "a:b"
def test_split_identifier():
assert split_identifier(':') == ['', '']
assert split_identifier('a:b') == ['a', 'b']
assert split_identifier('a:b:c') == ['a', 'b:c']
assert split_identifier(":") == ["", ""]
assert split_identifier("a:b") == ["a", "b"]
assert split_identifier("a:b:c") == ["a", "b:c"]
with pytest.raises(ModuleFailException) as exc:
split_identifier('a')
split_identifier("a")
assert exc.value.msg == 'Identifier "a" is not of the form <type>:<identifier>'
@@ -42,43 +42,43 @@ def test_challenge_from_to_json():
client = MagicMock()
data = {
'url': 'xxx',
'type': 'type',
'status': 'valid',
"url": "xxx",
"type": "type",
"status": "valid",
}
client.version = 2
challenge = Challenge.from_json(client, data)
assert challenge.data == data
assert challenge.type == 'type'
assert challenge.url == 'xxx'
assert challenge.status == 'valid'
assert challenge.type == "type"
assert challenge.url == "xxx"
assert challenge.status == "valid"
assert challenge.token is None
assert challenge.to_json() == data
data = {
'type': 'type',
'status': 'valid',
'token': 'foo',
"type": "type",
"status": "valid",
"token": "foo",
}
challenge = Challenge.from_json(None, data, url='xxx')
challenge = Challenge.from_json(None, data, url="xxx")
assert challenge.data == data
assert challenge.type == 'type'
assert challenge.url == 'xxx'
assert challenge.status == 'valid'
assert challenge.token == 'foo'
assert challenge.type == "type"
assert challenge.url == "xxx"
assert challenge.status == "valid"
assert challenge.token == "foo"
assert challenge.to_json() == data
data = {
'uri': 'xxx',
'type': 'type',
'status': 'valid',
"uri": "xxx",
"type": "type",
"status": "valid",
}
client.version = 1
challenge = Challenge.from_json(client, data)
assert challenge.data == data
assert challenge.type == 'type'
assert challenge.url == 'xxx'
assert challenge.status == 'valid'
assert challenge.type == "type"
assert challenge.url == "xxx"
assert challenge.status == "valid"
assert challenge.token is None
assert challenge.to_json() == data
@@ -88,93 +88,93 @@ def test_authorization_from_to_json():
client.version = 2
data = {
'challenges': [],
'status': 'valid',
'identifier': {
'type': 'dns',
'value': 'example.com',
"challenges": [],
"status": "valid",
"identifier": {
"type": "dns",
"value": "example.com",
},
}
authz = Authorization.from_json(client, data, 'xxx')
assert authz.url == 'xxx'
assert authz.status == 'valid'
assert authz.identifier == 'example.com'
assert authz.identifier_type == 'dns'
authz = Authorization.from_json(client, data, "xxx")
assert authz.url == "xxx"
assert authz.status == "valid"
assert authz.identifier == "example.com"
assert authz.identifier_type == "dns"
assert authz.challenges == []
assert authz.to_json() == {
'uri': 'xxx',
'challenges': [],
'status': 'valid',
'identifier': {
'type': 'dns',
'value': 'example.com',
"uri": "xxx",
"challenges": [],
"status": "valid",
"identifier": {
"type": "dns",
"value": "example.com",
},
}
data = {
'challenges': [
"challenges": [
{
'url': 'xxxyyy',
'type': 'type',
'status': 'valid',
"url": "xxxyyy",
"type": "type",
"status": "valid",
}
],
'status': 'valid',
'identifier': {
'type': 'dns',
'value': 'example.com',
"status": "valid",
"identifier": {
"type": "dns",
"value": "example.com",
},
'wildcard': True,
"wildcard": True,
}
authz = Authorization.from_json(client, data, 'xxx')
assert authz.url == 'xxx'
assert authz.status == 'valid'
assert authz.identifier == '*.example.com'
assert authz.identifier_type == 'dns'
authz = Authorization.from_json(client, data, "xxx")
assert authz.url == "xxx"
assert authz.status == "valid"
assert authz.identifier == "*.example.com"
assert authz.identifier_type == "dns"
assert len(authz.challenges) == 1
assert authz.challenges[0].data == {
'url': 'xxxyyy',
'type': 'type',
'status': 'valid',
"url": "xxxyyy",
"type": "type",
"status": "valid",
}
assert authz.to_json() == {
'uri': 'xxx',
'challenges': [
"uri": "xxx",
"challenges": [
{
'url': 'xxxyyy',
'type': 'type',
'status': 'valid',
"url": "xxxyyy",
"type": "type",
"status": "valid",
}
],
'status': 'valid',
'identifier': {
'type': 'dns',
'value': 'example.com',
"status": "valid",
"identifier": {
"type": "dns",
"value": "example.com",
},
'wildcard': True,
"wildcard": True,
}
client.version = 1
data = {
'challenges': [],
'identifier': {
'type': 'dns',
'value': 'example.com',
"challenges": [],
"identifier": {
"type": "dns",
"value": "example.com",
},
}
authz = Authorization.from_json(client, data, 'xxx')
assert authz.url == 'xxx'
assert authz.status == 'pending'
assert authz.identifier == 'example.com'
assert authz.identifier_type == 'dns'
authz = Authorization.from_json(client, data, "xxx")
assert authz.url == "xxx"
assert authz.status == "pending"
assert authz.identifier == "example.com"
assert authz.identifier_type == "dns"
assert authz.challenges == []
assert authz.to_json() == {
'uri': 'xxx',
'challenges': [],
'identifier': {
'type': 'dns',
'value': 'example.com',
"uri": "xxx",
"challenges": [],
"identifier": {
"type": "dns",
"value": "example.com",
},
}
@@ -184,60 +184,60 @@ def test_authorization_create_error():
client.version = 2
client.directory.directory = {}
with pytest.raises(ACMEProtocolException) as exc:
Authorization.create(client, 'dns', 'example.com')
Authorization.create(client, "dns", "example.com")
assert exc.value.msg == 'ACME endpoint does not support pre-authorization.'
assert exc.value.msg == "ACME endpoint does not support pre-authorization."
def test_wait_for_validation_error():
client = MagicMock()
client.version = 2
data = {
'challenges': [
"challenges": [
{
'url': 'xxxyyy1',
'type': 'dns-01',
'status': 'invalid',
'error': {
'type': 'dns-failed',
'subproblems': [
"url": "xxxyyy1",
"type": "dns-01",
"status": "invalid",
"error": {
"type": "dns-failed",
"subproblems": [
{
'type': 'subproblem',
'detail': 'example.com DNS-01 validation failed',
"type": "subproblem",
"detail": "example.com DNS-01 validation failed",
},
]
],
},
},
{
'url': 'xxxyyy2',
'type': 'http-01',
'status': 'invalid',
'error': {
'type': 'http-failed',
'subproblems': [
"url": "xxxyyy2",
"type": "http-01",
"status": "invalid",
"error": {
"type": "http-failed",
"subproblems": [
{
'type': 'subproblem',
'detail': 'example.com HTTP-01 validation failed',
"type": "subproblem",
"detail": "example.com HTTP-01 validation failed",
},
]
],
},
},
{
'url': 'xxxyyy3',
'type': 'something-else',
'status': 'valid',
"url": "xxxyyy3",
"type": "something-else",
"status": "valid",
},
],
'status': 'invalid',
'identifier': {
'type': 'dns',
'value': 'example.com',
"status": "invalid",
"identifier": {
"type": "dns",
"value": "example.com",
},
}
client.get_request = MagicMock(return_value=(data, {}))
authz = Authorization.from_json(client, data, 'xxx')
authz = Authorization.from_json(client, data, "xxx")
with pytest.raises(ACMEProtocolException) as exc:
authz.wait_for_validation(client, 'dns')
authz.wait_for_validation(client, "dns")
assert exc.value.msg == (
'Failed to validate challenge for dns:example.com: Status is "invalid". Challenge dns-01: Error dns-failed Subproblems:\n'
@@ -245,8 +245,8 @@ def test_wait_for_validation_error():
'(http-01.0) Error subproblem: "example.com HTTP-01 validation failed".'
)
data = data.copy()
data['uri'] = 'xxx'
data["uri"] = "xxx"
assert exc.value.module_fail_args == {
'identifier': 'dns:example.com',
'authorization': data,
"identifier": "dns:example.com",
"authorization": data,
}

View File

@@ -21,97 +21,78 @@ from ansible_collections.community.internal_test_tools.tests.unit.compat.mock im
TEST_FORMAT_ERROR_PROBLEM = [
(
{
'type': 'foo',
"type": "foo",
},
'',
'Error foo'
"",
"Error foo",
),
({"type": "foo", "title": "bar"}, "", 'Error "bar" (foo)'),
({"type": "foo", "detail": "bar baz"}, "", 'Error foo: "bar baz"'),
({"type": "foo", "subproblems": []}, "", "Error foo Subproblems:"),
(
{
'type': 'foo',
'title': 'bar'
},
'',
'Error "bar" (foo)'
),
(
{
'type': 'foo',
'detail': 'bar baz'
},
'',
'Error foo: "bar baz"'
),
(
{
'type': 'foo',
'subproblems': []
},
'',
'Error foo Subproblems:'
),
(
{
'type': 'foo',
'subproblems': [
"type": "foo",
"subproblems": [
{
'type': 'bar',
"type": "bar",
},
]
],
},
'',
'Error foo Subproblems:\n(0) Error bar'
"",
"Error foo Subproblems:\n(0) Error bar",
),
(
{
'type': 'foo',
'subproblems': [
"type": "foo",
"subproblems": [
{
'type': 'bar',
'subproblems': [
"type": "bar",
"subproblems": [
{
'type': 'baz',
"type": "baz",
},
]
],
},
]
],
},
'',
'Error foo Subproblems:\n(0) Error bar Subproblems:\n(0.0) Error baz'
"",
"Error foo Subproblems:\n(0) Error bar Subproblems:\n(0.0) Error baz",
),
(
{
'type': 'foo',
'title': 'Foo Error',
'detail': 'Foo went wrong',
'subproblems': [
"type": "foo",
"title": "Foo Error",
"detail": "Foo went wrong",
"subproblems": [
{
'type': 'bar',
'detail': 'Bar went wrong',
'subproblems': [
"type": "bar",
"detail": "Bar went wrong",
"subproblems": [
{
'type': 'baz',
'title': 'Baz Error',
"type": "baz",
"title": "Baz Error",
},
]
],
},
{
'type': 'bar2',
'title': 'Bar 2 Error',
'detail': 'Bar really went wrong'
"type": "bar2",
"title": "Bar 2 Error",
"detail": "Bar really went wrong",
},
]
],
},
'X.',
"X.",
'Error "Foo Error" (foo): "Foo went wrong" Subproblems:\n'
'(X.0) Error bar: "Bar went wrong" Subproblems:\n'
'(X.0.0) Error "Baz Error" (baz)\n'
'(X.1) Error "Bar 2 Error" (bar2): "Bar really went wrong"'
'(X.1) Error "Bar 2 Error" (bar2): "Bar really went wrong"',
),
]
@pytest.mark.parametrize("problem, subproblem_prefix, result", TEST_FORMAT_ERROR_PROBLEM)
@pytest.mark.parametrize(
"problem, subproblem_prefix, result", TEST_FORMAT_ERROR_PROBLEM
)
def test_format_error_problem(problem, subproblem_prefix, result):
res = format_error_problem(problem, subproblem_prefix)
assert res == result
@@ -119,14 +100,14 @@ def test_format_error_problem(problem, subproblem_prefix, result):
def create_regular_response(response_text):
response = MagicMock()
response.read = MagicMock(return_value=response_text.encode('utf-8'))
response.read = MagicMock(return_value=response_text.encode("utf-8"))
response.closed = False
return response
def create_error_response():
response = MagicMock()
response.read = MagicMock(side_effect=AttributeError('read'))
response.read = MagicMock(side_effect=AttributeError("read"))
response.closed = True
return response
@@ -142,220 +123,219 @@ TEST_ACME_PROTOCOL_EXCEPTION = [
(
{},
None,
'ACME request failed.',
{
},
"ACME request failed.",
{},
),
(
{
'msg': 'Foo',
'extras': {
'foo': 'bar',
"msg": "Foo",
"extras": {
"foo": "bar",
},
},
None,
'Foo.',
"Foo.",
{
'foo': 'bar',
"foo": "bar",
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 201,
"info": {
"url": "https://ca.example.com/foo",
"status": 201,
},
},
None,
'ACME request failed for https://ca.example.com/foo with HTTP status 201 Created.',
"ACME request failed for https://ca.example.com/foo with HTTP status 201 Created.",
{
'http_url': 'https://ca.example.com/foo',
'http_status': 201,
"http_url": "https://ca.example.com/foo",
"http_status": 201,
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 201,
"info": {
"url": "https://ca.example.com/foo",
"status": 201,
},
'response': create_regular_response('xxx'),
},
None,
'ACME request failed for https://ca.example.com/foo with HTTP status 201 Created. The raw error result: xxx',
{
'http_url': 'https://ca.example.com/foo',
'http_status': 201,
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 201,
},
'response': create_regular_response('xxx'),
},
create_decode_error('yyy'),
'ACME request failed for https://ca.example.com/foo with HTTP status 201 Created. The raw error result: xxx',
{
'http_url': 'https://ca.example.com/foo',
'http_status': 201,
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 201,
},
'response': create_regular_response('xxx'),
},
lambda content: dict(foo='bar'),
"ACME request failed for https://ca.example.com/foo with HTTP status 201 Created. The JSON error result: {'foo': 'bar'}",
{
'http_url': 'https://ca.example.com/foo',
'http_status': 201,
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 201,
},
'response': create_error_response(),
},
None,
'ACME request failed for https://ca.example.com/foo with HTTP status 201 Created.',
{
'http_url': 'https://ca.example.com/foo',
'http_status': 201,
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 201,
'body': 'xxx',
},
'response': create_error_response(),
},
lambda content: dict(foo='bar'),
"ACME request failed for https://ca.example.com/foo with HTTP status 201 Created. The JSON error result: {'foo': 'bar'}",
{
'http_url': 'https://ca.example.com/foo',
'http_status': 201,
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 201,
},
'content': 'xxx',
"response": create_regular_response("xxx"),
},
None,
"ACME request failed for https://ca.example.com/foo with HTTP status 201 Created. The raw error result: xxx",
{
'http_url': 'https://ca.example.com/foo',
'http_status': 201,
"http_url": "https://ca.example.com/foo",
"http_status": 201,
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 400,
"info": {
"url": "https://ca.example.com/foo",
"status": 201,
},
'content_json': {
'foo': 'bar',
"response": create_regular_response("xxx"),
},
create_decode_error("yyy"),
"ACME request failed for https://ca.example.com/foo with HTTP status 201 Created. The raw error result: xxx",
{
"http_url": "https://ca.example.com/foo",
"http_status": 201,
},
),
(
{
"info": {
"url": "https://ca.example.com/foo",
"status": 201,
},
"response": create_regular_response("xxx"),
},
lambda content: dict(foo="bar"),
"ACME request failed for https://ca.example.com/foo with HTTP status 201 Created. The JSON error result: {'foo': 'bar'}",
{
"http_url": "https://ca.example.com/foo",
"http_status": 201,
},
),
(
{
"info": {
"url": "https://ca.example.com/foo",
"status": 201,
},
"response": create_error_response(),
},
None,
"ACME request failed for https://ca.example.com/foo with HTTP status 201 Created.",
{
"http_url": "https://ca.example.com/foo",
"http_status": 201,
},
),
(
{
"info": {
"url": "https://ca.example.com/foo",
"status": 201,
"body": "xxx",
},
"response": create_error_response(),
},
lambda content: dict(foo="bar"),
"ACME request failed for https://ca.example.com/foo with HTTP status 201 Created. The JSON error result: {'foo': 'bar'}",
{
"http_url": "https://ca.example.com/foo",
"http_status": 201,
},
),
(
{
"info": {
"url": "https://ca.example.com/foo",
"status": 201,
},
"content": "xxx",
},
None,
"ACME request failed for https://ca.example.com/foo with HTTP status 201 Created. The raw error result: xxx",
{
"http_url": "https://ca.example.com/foo",
"http_status": 201,
},
),
(
{
"info": {
"url": "https://ca.example.com/foo",
"status": 400,
},
"content_json": {
"foo": "bar",
},
"extras": {
"bar": "baz",
},
'extras': {
'bar': 'baz',
}
},
None,
"ACME request failed for https://ca.example.com/foo with HTTP status 400 Bad Request. The JSON error result: {'foo': 'bar'}",
{
'http_url': 'https://ca.example.com/foo',
'http_status': 400,
'bar': 'baz',
"http_url": "https://ca.example.com/foo",
"http_status": 400,
"bar": "baz",
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 201,
"info": {
"url": "https://ca.example.com/foo",
"status": 201,
},
'content_json': {
'type': 'foo',
"content_json": {
"type": "foo",
},
},
None,
"ACME request failed for https://ca.example.com/foo with HTTP status 201 Created. The JSON error result: {'type': 'foo'}",
{
'http_url': 'https://ca.example.com/foo',
'http_status': 201,
"http_url": "https://ca.example.com/foo",
"http_status": 201,
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 400,
"info": {
"url": "https://ca.example.com/foo",
"status": 400,
},
'content_json': {
'type': 'foo',
"content_json": {
"type": "foo",
},
},
None,
"ACME request failed for https://ca.example.com/foo with status 400 Bad Request. Error foo.",
{
'http_url': 'https://ca.example.com/foo',
'http_status': 400,
'problem': {
'type': 'foo',
"http_url": "https://ca.example.com/foo",
"http_status": 400,
"problem": {
"type": "foo",
},
'subproblems': [],
"subproblems": [],
},
),
(
{
'info': {
'url': 'https://ca.example.com/foo',
'status': 400,
"info": {
"url": "https://ca.example.com/foo",
"status": 400,
},
'content_json': {
'type': 'foo',
'title': 'Foo Error',
'subproblems': [
"content_json": {
"type": "foo",
"title": "Foo Error",
"subproblems": [
{
'type': 'bar',
'detail': 'This is a bar error',
'details': 'Details.',
"type": "bar",
"detail": "This is a bar error",
"details": "Details.",
},
],
},
},
None,
"ACME request failed for https://ca.example.com/foo with status 400 Bad Request. Error \"Foo Error\" (foo). Subproblems:\n"
"(0) Error bar: \"This is a bar error\".",
'ACME request failed for https://ca.example.com/foo with status 400 Bad Request. Error "Foo Error" (foo). Subproblems:\n'
'(0) Error bar: "This is a bar error".',
{
'http_url': 'https://ca.example.com/foo',
'http_status': 400,
'problem': {
'type': 'foo',
'title': 'Foo Error',
"http_url": "https://ca.example.com/foo",
"http_status": 400,
"problem": {
"type": "foo",
"title": "Foo Error",
},
'subproblems': [
"subproblems": [
{
'type': 'bar',
'detail': 'This is a bar error',
'details': 'Details.',
"type": "bar",
"detail": "This is a bar error",
"details": "Details.",
},
],
},

View File

@@ -22,14 +22,14 @@ TEST_TEXT = r"""1234
def test_read_file(tmpdir):
fn = tmpdir / 'test.txt'
fn = tmpdir / "test.txt"
fn.write(TEST_TEXT)
assert read_file(str(fn), 't') == TEST_TEXT
assert read_file(str(fn), 'b') == TEST_TEXT.encode('utf-8')
assert read_file(str(fn), "t") == TEST_TEXT
assert read_file(str(fn), "b") == TEST_TEXT.encode("utf-8")
def test_write_file(tmpdir):
fn = tmpdir / 'test.txt'
fn = tmpdir / "test.txt"
module = MagicMock()
write_file(module, str(fn), TEST_TEXT.encode('utf-8'))
write_file(module, str(fn), TEST_TEXT.encode("utf-8"))
assert fn.read() == TEST_TEXT

View File

@@ -22,15 +22,15 @@ def test_order_from_json():
client = MagicMock()
data = {
'status': 'valid',
'identifiers': [],
'authorizations': [],
"status": "valid",
"identifiers": [],
"authorizations": [],
}
client.version = 2
order = Order.from_json(client, data, 'xxx')
order = Order.from_json(client, data, "xxx")
assert order.data == data
assert order.url == 'xxx'
assert order.status == 'valid'
assert order.url == "xxx"
assert order.status == "valid"
assert order.identifiers == []
assert order.finalize_uri is None
assert order.certificate_uri is None
@@ -43,15 +43,17 @@ def test_wait_for_finalization_error():
client.version = 2
data = {
'status': 'invalid',
'identifiers': [],
'authorizations': [],
"status": "invalid",
"identifiers": [],
"authorizations": [],
}
order = Order.from_json(client, data, 'xxx')
order = Order.from_json(client, data, "xxx")
client.get_request = MagicMock(return_value=(data, {}))
with pytest.raises(ACMEProtocolException) as exc:
order.wait_for_finalization(client)
assert exc.value.msg.startswith('Failed to wait for order to complete; got status "invalid". The JSON result: ')
assert exc.value.msg.startswith(
'Failed to wait for order to complete; got status "invalid". The JSON result: '
)
assert exc.value.module_fail_args == {}

View File

@@ -39,38 +39,34 @@ TEST_LINKS_HEADER = [
[],
),
(
{
'link': '<foo>; rel="bar"'
},
{"link": '<foo>; rel="bar"'},
[
('foo', 'bar'),
("foo", "bar"),
],
),
(
{"link": '<foo>; rel="bar", <baz>; rel="bam"'},
[
("foo", "bar"),
("baz", "bam"),
],
),
(
{
'link': '<foo>; rel="bar", <baz>; rel="bam"'
"link": '<https://one.example.com>; rel="preconnect", <https://two.example.com>; rel="preconnect", <https://three.example.com>; rel="preconnect"'
},
[
('foo', 'bar'),
('baz', 'bam'),
],
),
(
{
'link': '<https://one.example.com>; rel="preconnect", <https://two.example.com>; rel="preconnect", <https://three.example.com>; rel="preconnect"'
},
[
('https://one.example.com', 'preconnect'),
('https://two.example.com', 'preconnect'),
('https://three.example.com', 'preconnect'),
("https://one.example.com", "preconnect"),
("https://two.example.com", "preconnect"),
("https://three.example.com", "preconnect"),
],
),
]
TEST_RETRY_AFTER_HEADER = [
('120', datetime.datetime(2024, 4, 29, 0, 2, 0)),
('Wed, 21 Oct 2015 07:28:00 GMT', datetime.datetime(2015, 10, 21, 7, 28, 0)),
("120", datetime.datetime(2024, 4, 29, 0, 2, 0)),
("Wed, 21 Oct 2015 07:28:00 GMT", datetime.datetime(2015, 10, 21, 7, 28, 0)),
]
@@ -81,9 +77,9 @@ TEST_COMPUTE_CERT_ID = [
not_valid_before=datetime.datetime(2018, 11, 25, 15, 28, 23),
serial_number=1,
subject_key_identifier=None,
authority_key_identifier=b'\x00\xff',
authority_key_identifier=b"\x00\xff",
),
'AP8.AQ',
"AP8.AQ",
),
(
# AKI, serial number, and expected result taken from
@@ -93,21 +89,21 @@ TEST_COMPUTE_CERT_ID = [
not_valid_before=datetime.datetime(2018, 11, 25, 15, 28, 23),
serial_number=0x87654321,
subject_key_identifier=None,
authority_key_identifier=b'\x69\x88\x5B\x6B\x87\x46\x40\x41\xE1\xB3\x7B\x84\x7B\xA0\xAE\x2C\xDE\x01\xC8\xD4',
authority_key_identifier=b"\x69\x88\x5b\x6b\x87\x46\x40\x41\xe1\xb3\x7b\x84\x7b\xa0\xae\x2c\xde\x01\xc8\xd4",
),
'aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE',
"aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE",
),
]
@pytest.mark.parametrize("value, result", NOPAD_B64)
def test_nopad_b64(value, result):
assert nopad_b64(value.encode('utf-8')) == result
assert nopad_b64(value.encode("utf-8")) == result
@pytest.mark.parametrize("pem, der", TEST_PEM_DERS)
def test_pem_to_der(pem, der, tmpdir):
fn = tmpdir / 'test.pem'
fn = tmpdir / "test.pem"
fn.write(pem)
assert pem_to_der(str(fn)) == der
@@ -126,7 +122,9 @@ def test_process_links(value, expected_result):
@pytest.mark.parametrize("value, expected_result", TEST_RETRY_AFTER_HEADER)
def test_parse_retry_after(value, expected_result):
assert expected_result == parse_retry_after(value, now=datetime.datetime(2024, 4, 29, 0, 0, 0))
assert expected_result == parse_retry_after(
value, now=datetime.datetime(2024, 4, 29, 0, 0, 0)
)
@pytest.mark.parametrize("cert_info, expected_result", TEST_COMPUTE_CERT_ID)

View File

@@ -21,52 +21,89 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto._asn1 impo
TEST_CASES = [
('UTF8:Hello World', b'\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('EXPLICIT:10,UTF8:Hello World', b'\xaa\x0d\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('EXPLICIT:12U,UTF8:Hello World', b'\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('EXPLICIT:10A,UTF8:Hello World', b'\x6a\x0d\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('EXPLICIT:10P,UTF8:Hello World', b'\xea\x0d\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('EXPLICIT:10C,UTF8:Hello World', b'\xaa\x0d\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('EXPLICIT:1024P,UTF8:Hello World', b'\xff\x88\x00\x0d\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('IMPLICIT:10,UTF8:Hello World', b'\x8a\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('IMPLICIT:12U,UTF8:Hello World', b'\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('IMPLICIT:10A,UTF8:Hello World', b'\x4a\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('IMPLICIT:10P,UTF8:Hello World', b'\xca\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('IMPLICIT:10C,UTF8:Hello World', b'\x8a\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
('IMPLICIT:1024P,UTF8:Hello World', b'\xdf\x88\x00\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64'),
("UTF8:Hello World", b"\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64"),
(
"EXPLICIT:10,UTF8:Hello World",
b"\xaa\x0d\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"EXPLICIT:12U,UTF8:Hello World",
b"\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"EXPLICIT:10A,UTF8:Hello World",
b"\x6a\x0d\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"EXPLICIT:10P,UTF8:Hello World",
b"\xea\x0d\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"EXPLICIT:10C,UTF8:Hello World",
b"\xaa\x0d\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"EXPLICIT:1024P,UTF8:Hello World",
b"\xff\x88\x00\x0d\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"IMPLICIT:10,UTF8:Hello World",
b"\x8a\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"IMPLICIT:12U,UTF8:Hello World",
b"\x0c\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"IMPLICIT:10A,UTF8:Hello World",
b"\x4a\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"IMPLICIT:10P,UTF8:Hello World",
b"\xca\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"IMPLICIT:10C,UTF8:Hello World",
b"\x8a\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
(
"IMPLICIT:1024P,UTF8:Hello World",
b"\xdf\x88\x00\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64",
),
# Tests large data lengths, special logic for the length octet encoding.
('UTF8:' + ('A' * 600), b'\x0c\x82\x02\x58' + (b'\x41' * 600)),
("UTF8:" + ("A" * 600), b"\x0c\x82\x02\x58" + (b"\x41" * 600)),
# This isn't valid with openssl asn1parse but has been validated against an ASN.1 parser. OpenSSL seems to read the
# data u"café" encoded as UTF-8 bytes b"caf\xc3\xa9", decodes that internally with latin-1 (or similar variant) as
# u"café" then encodes that to UTF-8 b"caf\xc3\x83\xc2\xa9" for the UTF8String. Ultimately openssl is wrong here
# so we keep our assertion happening.
(u'UTF8:café', b'\x0c\x05\x63\x61\x66\xc3\xa9'),
(u"UTF8:café", b"\x0c\x05\x63\x61\x66\xc3\xa9"),
]
@pytest.mark.parametrize('value, expected', TEST_CASES)
@pytest.mark.parametrize("value, expected", TEST_CASES)
def test_serialize_asn1_string_as_der(value, expected):
actual = serialize_asn1_string_as_der(value)
print("%s | %s" % (value, base64.b16encode(actual).decode()))
assert actual == expected
@pytest.mark.parametrize('value', [
'invalid',
'EXPLICIT,UTF:value',
])
@pytest.mark.parametrize(
"value",
[
"invalid",
"EXPLICIT,UTF:value",
],
)
def test_serialize_asn1_string_as_der_invalid_format(value):
expected = "The ASN.1 serialized string must be in the format [modifier,]type[:value]"
expected = (
"The ASN.1 serialized string must be in the format [modifier,]type[:value]"
)
with pytest.raises(ValueError, match=re.escape(expected)):
serialize_asn1_string_as_der(value)
def test_serialize_asn1_string_as_der_invalid_type():
expected = "The ASN.1 serialized string is not a known type \"OID\", only UTF8 types are supported"
expected = 'The ASN.1 serialized string is not a known type "OID", only UTF8 types are supported'
with pytest.raises(ValueError, match=re.escape(expected)):
serialize_asn1_string_as_der("OID:1.2.3.4")
@@ -77,17 +114,23 @@ def test_pack_asn_invalid_class():
@pytest.mark.skip() # This is to just to build the test case assertions and shouldn't run normally.
@pytest.mark.parametrize('value, expected', TEST_CASES)
@pytest.mark.parametrize("value, expected", TEST_CASES)
def test_test_cases(value, expected, tmp_path):
test_file = tmp_path / 'test.der'
subprocess.run(['openssl', 'asn1parse', '-genstr', value, '-noout', '-out', test_file], check=True)
test_file = tmp_path / "test.der"
subprocess.run(
["openssl", "asn1parse", "-genstr", value, "-noout", "-out", test_file],
check=True,
)
with open(test_file, mode='rb') as fd:
with open(test_file, mode="rb") as fd:
b_data = fd.read()
hex_str = base64.b16encode(b_data).decode().lower()
print("%s | \\x%s" % (value, "\\x".join([hex_str[i:i + 2] for i in range(0, len(hex_str), 2)])))
print(
"%s | \\x%s"
% (value, "\\x".join([hex_str[i : i + 2] for i in range(0, len(hex_str), 2)]))
)
# This is a know edge case where openssl asn1parse does not work properly.
if value != u'UTF8:café':
if value != u"UTF8:café":
assert b_data == expected

View File

@@ -28,100 +28,147 @@ from ansible_collections.community.crypto.plugins.module_utils.version import (
from cryptography.x509 import NameAttribute, oid
@pytest.mark.parametrize('unicode, idna, cycled_unicode', [
(u'..', u'..', None),
(u'foo.com', u'foo.com', None),
(u'.foo.com.', u'.foo.com.', None),
(u'*.foo.com', u'*.foo.com', None),
(u'straße', u'xn--strae-oqa', None),
(u'ffóò.ḃâŗ.çøṁ', u'xn--ff-3jad.xn--2ca8uh37e.xn--7ca8a981n', u'ffóò.ḃâŗ.çøṁ'),
(u'*.☺.', u'*.xn--74h.', None),
])
@pytest.mark.parametrize(
"unicode, idna, cycled_unicode",
[
(u"..", u"..", None),
(u"foo.com", u"foo.com", None),
(u".foo.com.", u".foo.com.", None),
(u"*.foo.com", u"*.foo.com", None),
(u"straße", u"xn--strae-oqa", None),
(u"ffóò.ḃâŗ.çøṁ", u"xn--ff-3jad.xn--2ca8uh37e.xn--7ca8a981n", u"ffóò.ḃâŗ.çøṁ"),
(u"*.☺.", u"*.xn--74h.", None),
],
)
def test_adjust_idn(unicode, idna, cycled_unicode):
if cycled_unicode is None:
cycled_unicode = unicode
result = _adjust_idn(unicode, 'ignore')
result = _adjust_idn(unicode, "ignore")
print(result, unicode)
assert result == unicode
result = _adjust_idn(idna, 'ignore')
result = _adjust_idn(idna, "ignore")
print(result, idna)
assert result == idna
result = _adjust_idn(unicode, 'unicode')
result = _adjust_idn(unicode, "unicode")
print(result, unicode)
assert result == unicode
result = _adjust_idn(idna, 'unicode')
result = _adjust_idn(idna, "unicode")
print(result, cycled_unicode)
assert result == cycled_unicode
result = _adjust_idn(unicode, 'idna')
result = _adjust_idn(unicode, "idna")
print(result, idna)
assert result == idna
result = _adjust_idn(idna, 'idna')
result = _adjust_idn(idna, "idna")
print(result, idna)
assert result == idna
@pytest.mark.parametrize('value, idn_rewrite, message', [
(u'bar', 'foo', re.escape(u'Invalid value for idn_rewrite: "foo"')),
])
@pytest.mark.parametrize(
"value, idn_rewrite, message",
[
(u"bar", "foo", re.escape(u'Invalid value for idn_rewrite: "foo"')),
],
)
def test_adjust_idn_fail_valueerror(value, idn_rewrite, message):
with pytest.raises(ValueError, match=message):
_adjust_idn(value, idn_rewrite)
@pytest.mark.parametrize('value, idn_rewrite, message', [
(
u'xn--a',
'unicode',
u'''^Error while transforming part u?"xn\\-\\-a" of IDNA DNS name u?"xn\\-\\-a" to Unicode\\.'''
u''' IDNA2008 transformation resulted in "Codepoint U\\+0080 at position 1 of u?'\\\\x80' not allowed",'''
u''' IDNA2003 transformation resulted in "(decoding with 'idna' codec failed'''
u''' \\(UnicodeError: |'idna' codec can't decode byte 0x78 in position 0: )?Invalid character u?'\\\\x80'\\)?"\\.$'''
),
])
@pytest.mark.parametrize(
"value, idn_rewrite, message",
[
(
u"xn--a",
"unicode",
u"""^Error while transforming part u?"xn\\-\\-a" of IDNA DNS name u?"xn\\-\\-a" to Unicode\\."""
u""" IDNA2008 transformation resulted in "Codepoint U\\+0080 at position 1 of u?'\\\\x80' not allowed","""
u""" IDNA2003 transformation resulted in "(decoding with 'idna' codec failed"""
u""" \\(UnicodeError: |'idna' codec can't decode byte 0x78 in position 0: )?Invalid character u?'\\\\x80'\\)?"\\.$""",
),
],
)
def test_adjust_idn_fail_user_error(value, idn_rewrite, message):
with pytest.raises(OpenSSLObjectError, match=message):
_adjust_idn(value, idn_rewrite)
def test_cryptography_get_name_invalid_prefix():
with pytest.raises(OpenSSLObjectError, match="^Cannot parse Subject Alternative Name"):
cryptography_get_name('fake:value')
with pytest.raises(
OpenSSLObjectError, match="^Cannot parse Subject Alternative Name"
):
cryptography_get_name("fake:value")
def test_cryptography_get_name_other_name_no_oid():
with pytest.raises(OpenSSLObjectError, match="Cannot parse Subject Alternative Name otherName"):
cryptography_get_name('otherName:value')
with pytest.raises(
OpenSSLObjectError, match="Cannot parse Subject Alternative Name otherName"
):
cryptography_get_name("otherName:value")
def test_cryptography_get_name_other_name_utfstring():
actual = cryptography_get_name('otherName:1.3.6.1.4.1.311.20.2.3;UTF8:Hello World')
assert actual.type_id.dotted_string == '1.3.6.1.4.1.311.20.2.3'
assert actual.value == b'\x0c\x0bHello World'
actual = cryptography_get_name("otherName:1.3.6.1.4.1.311.20.2.3;UTF8:Hello World")
assert actual.type_id.dotted_string == "1.3.6.1.4.1.311.20.2.3"
assert actual.value == b"\x0c\x0bHello World"
@pytest.mark.parametrize('name, options, expected', [
(b'CN=x ', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u'x '), b'')),
(b'CN=\\ ', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u' '), b'')),
(b'CN=\\#', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u'#'), b'')),
(b'CN=#402032', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u'@ 2'), b'')),
(b'CN = x ', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u'x '), b'')),
(b'CN = x\\, ', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u'x, '), b'')),
(b'CN = x\\40 ', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u'x@ '), b'')),
(b'CN = \\ , / ', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u' '), b', / ')),
(b'CN = \\ , / ', {'sep': b'/'}, (NameAttribute(oid.NameOID.COMMON_NAME, u' , '), b'/ ')),
(b'CN = \\ , / ', {'decode_remainder': False}, (NameAttribute(oid.NameOID.COMMON_NAME, u'\\ , / '), b'')),
# Some examples from https://datatracker.ietf.org/doc/html/rfc4514#section-4:
(b'CN=James \\"Jim\\" Smith\\, III', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u'James "Jim" Smith, III'), b'')),
(b'CN=Before\\0dAfter', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u'Before\x0dAfter'), b'')),
(b'1.3.6.1.4.1.1466.0=#04024869', {}, (NameAttribute(oid.ObjectIdentifier(u'1.3.6.1.4.1.1466.0'), u'\x04\x02Hi'), b'')),
(b'CN=Lu\\C4\\8Di\\C4\\87', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u'Lučić'), b'')),
])
@pytest.mark.parametrize(
"name, options, expected",
[
(b"CN=x ", {}, (NameAttribute(oid.NameOID.COMMON_NAME, u"x "), b"")),
(b"CN=\\ ", {}, (NameAttribute(oid.NameOID.COMMON_NAME, u" "), b"")),
(b"CN=\\#", {}, (NameAttribute(oid.NameOID.COMMON_NAME, u"#"), b"")),
(b"CN=#402032", {}, (NameAttribute(oid.NameOID.COMMON_NAME, u"@ 2"), b"")),
(b"CN = x ", {}, (NameAttribute(oid.NameOID.COMMON_NAME, u"x "), b"")),
(b"CN = x\\, ", {}, (NameAttribute(oid.NameOID.COMMON_NAME, u"x, "), b"")),
(b"CN = x\\40 ", {}, (NameAttribute(oid.NameOID.COMMON_NAME, u"x@ "), b"")),
(
b"CN = \\ , / ",
{},
(NameAttribute(oid.NameOID.COMMON_NAME, u" "), b", / "),
),
(
b"CN = \\ , / ",
{"sep": b"/"},
(NameAttribute(oid.NameOID.COMMON_NAME, u" , "), b"/ "),
),
(
b"CN = \\ , / ",
{"decode_remainder": False},
(NameAttribute(oid.NameOID.COMMON_NAME, u"\\ , / "), b""),
),
# Some examples from https://datatracker.ietf.org/doc/html/rfc4514#section-4:
(
b'CN=James \\"Jim\\" Smith\\, III',
{},
(NameAttribute(oid.NameOID.COMMON_NAME, u'James "Jim" Smith, III'), b""),
),
(
b"CN=Before\\0dAfter",
{},
(NameAttribute(oid.NameOID.COMMON_NAME, u"Before\x0dAfter"), b""),
),
(
b"1.3.6.1.4.1.1466.0=#04024869",
{},
(
NameAttribute(oid.ObjectIdentifier("1.3.6.1.4.1.1466.0"), u"\x04\x02Hi"),
b"",
),
),
(
b"CN=Lu\\C4\\8Di\\C4\\87",
{},
(NameAttribute(oid.NameOID.COMMON_NAME, u"Lučić"), b""),
),
],
)
def test_parse_dn_component(name, options, expected):
result = _parse_dn_component(name, **options)
print(result, expected)
@@ -131,42 +178,77 @@ def test_parse_dn_component(name, options, expected):
# Cryptography < 2.9 does not allow empty strings
# (https://github.com/pyca/cryptography/commit/87b2749c52e688c809f1861e55d958c64147493c)
# Cryptoraphy 43.0.0+ also doesn't allow this anymore
if LooseVersion('2.9') <= LooseVersion(cryptography.__version__) < LooseVersion('43.0.0'):
@pytest.mark.parametrize('name, options, expected', [
(b'CN=', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u''), b'')),
(b'CN= ', {}, (NameAttribute(oid.NameOID.COMMON_NAME, u''), b'')),
])
if (
LooseVersion("2.9")
<= LooseVersion(cryptography.__version__)
< LooseVersion("43.0.0")
):
@pytest.mark.parametrize(
"name, options, expected",
[
(b"CN=", {}, (NameAttribute(oid.NameOID.COMMON_NAME, u""), b"")),
(b"CN= ", {}, (NameAttribute(oid.NameOID.COMMON_NAME, u""), b"")),
],
)
def test_parse_dn_component_not_py26(name, options, expected):
result = _parse_dn_component(name, **options)
print(result, expected)
assert result == expected
@pytest.mark.parametrize('name, options, message', [
(b'CN=\\0', {}, u'Hex escape sequence "\\0" incomplete at end of string'),
(b'CN=\\0,', {}, u'Hex escape sequence "\\0," has invalid second letter'),
(b'CN=#0,', {}, u'Invalid hex sequence entry "0,"'),
])
@pytest.mark.parametrize(
"name, options, message",
[
(b"CN=\\0", {}, u'Hex escape sequence "\\0" incomplete at end of string'),
(b"CN=\\0,", {}, u'Hex escape sequence "\\0," has invalid second letter'),
(b"CN=#0,", {}, u'Invalid hex sequence entry "0,"'),
],
)
def test_parse_dn_component_failure(name, options, message):
with pytest.raises(OpenSSLObjectError, match=u'^%s$' % re.escape(message)):
with pytest.raises(OpenSSLObjectError, match=u"^%s$" % re.escape(message)):
_parse_dn_component(name, **options)
@pytest.mark.parametrize('name, expected', [
(b'CN=foo', [NameAttribute(oid.NameOID.COMMON_NAME, u'foo')]),
(b'CN=foo,CN=bar', [NameAttribute(oid.NameOID.COMMON_NAME, u'foo'), NameAttribute(oid.NameOID.COMMON_NAME, u'bar')]),
(b'CN = foo , CN = bar', [NameAttribute(oid.NameOID.COMMON_NAME, u'foo '), NameAttribute(oid.NameOID.COMMON_NAME, u'bar')]),
])
@pytest.mark.parametrize(
"name, expected",
[
(b"CN=foo", [NameAttribute(oid.NameOID.COMMON_NAME, u"foo")]),
(
b"CN=foo,CN=bar",
[
NameAttribute(oid.NameOID.COMMON_NAME, u"foo"),
NameAttribute(oid.NameOID.COMMON_NAME, u"bar"),
],
),
(
b"CN = foo , CN = bar",
[
NameAttribute(oid.NameOID.COMMON_NAME, u"foo "),
NameAttribute(oid.NameOID.COMMON_NAME, u"bar"),
],
),
],
)
def test_parse_dn(name, expected):
result = _parse_dn(name)
print(result, expected)
assert result == expected
@pytest.mark.parametrize('name, message', [
(b'CN=\\0', u'Error while parsing distinguished name "CN=\\0": Hex escape sequence "\\0" incomplete at end of string'),
(b'CN=x,', u'Error while parsing distinguished name "CN=x,": unexpected end of string'),
])
@pytest.mark.parametrize(
"name, message",
[
(
b"CN=\\0",
u'Error while parsing distinguished name "CN=\\0": Hex escape sequence "\\0" incomplete at end of string',
),
(
b"CN=x,",
u'Error while parsing distinguished name "CN=x,": unexpected end of string',
),
],
)
def test_parse_dn_failure(name, message):
with pytest.raises(OpenSSLObjectError, match=u'^%s$' % re.escape(message)):
with pytest.raises(OpenSSLObjectError, match=u"^%s$" % re.escape(message)):
_parse_dn(name)

View File

@@ -20,98 +20,116 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.math impor
)
@pytest.mark.parametrize('f, e, m, result', [
(0, 0, 5, 1),
(0, 1, 5, 0),
(2, 1, 5, 2),
(2, 2, 5, 4),
(2, 3, 5, 3),
(2, 10, 5, 4),
])
@pytest.mark.parametrize(
"f, e, m, result",
[
(0, 0, 5, 1),
(0, 1, 5, 0),
(2, 1, 5, 2),
(2, 2, 5, 4),
(2, 3, 5, 3),
(2, 10, 5, 4),
],
)
def test_binary_exp_mod(f, e, m, result):
value = binary_exp_mod(f, e, m)
print(value)
assert value == result
@pytest.mark.parametrize('a, b, result', [
(0, -123, -123),
(0, 123, 123),
(-123, 0, -123),
(123, 0, 123),
(-123, 1, 1),
(123, 1, 1),
(1, -123, -1),
(1, 123, 1),
(1024, 10, 2),
])
@pytest.mark.parametrize(
"a, b, result",
[
(0, -123, -123),
(0, 123, 123),
(-123, 0, -123),
(123, 0, 123),
(-123, 1, 1),
(123, 1, 1),
(1, -123, -1),
(1, 123, 1),
(1024, 10, 2),
],
)
def test_simple_gcd(a, b, result):
value = simple_gcd(a, b)
print(value)
assert value == result
@pytest.mark.parametrize('n, result', [
(-2, True),
(0, True),
(1, True),
(2, False),
(3, False),
(4, True),
(5, False),
(6, True),
(7, False),
(8, True),
(9, True),
(10, True),
(211, False), # the smallest prime number >= 200
])
@pytest.mark.parametrize(
"n, result",
[
(-2, True),
(0, True),
(1, True),
(2, False),
(3, False),
(4, True),
(5, False),
(6, True),
(7, False),
(8, True),
(9, True),
(10, True),
(211, False), # the smallest prime number >= 200
],
)
def test_quick_is_not_prime(n, result):
value = quick_is_not_prime(n)
print(value)
assert value == result
@pytest.mark.parametrize('no, count, result', [
(0, None, b''),
(0, 1, b'\x00'),
(0, 2, b'\x00\x00'),
(1, None, b'\x01'),
(1, 2, b'\x00\x01'),
(255, None, b'\xff'),
(256, None, b'\x01\x00'),
])
@pytest.mark.parametrize(
"no, count, result",
[
(0, None, b""),
(0, 1, b"\x00"),
(0, 2, b"\x00\x00"),
(1, None, b"\x01"),
(1, 2, b"\x00\x01"),
(255, None, b"\xff"),
(256, None, b"\x01\x00"),
],
)
def test_convert_int_to_bytes(no, count, result):
value = convert_int_to_bytes(no, count=count)
print(value)
assert value == result
@pytest.mark.parametrize('no, digits, result', [
(0, None, '0'),
(1, None, '1'),
(16, None, '10'),
(1, 3, '001'),
(255, None, 'ff'),
(256, None, '100'),
(256, 2, '100'),
(256, 3, '100'),
(256, 4, '0100'),
])
@pytest.mark.parametrize(
"no, digits, result",
[
(0, None, "0"),
(1, None, "1"),
(16, None, "10"),
(1, 3, "001"),
(255, None, "ff"),
(256, None, "100"),
(256, 2, "100"),
(256, 3, "100"),
(256, 4, "0100"),
],
)
def test_convert_int_to_hex(no, digits, result):
value = convert_int_to_hex(no, digits=digits)
print(value)
assert value == result
@pytest.mark.parametrize('data, result', [
(b'', 0),
(b'\x00', 0),
(b'\x00\x01', 1),
(b'\x01', 1),
(b'\xff', 255),
(b'\x01\x00', 256),
])
@pytest.mark.parametrize(
"data, result",
[
(b"", 0),
(b"\x00", 0),
(b"\x00\x01", 1),
(b"\x01", 1),
(b"\xff", 255),
(b"\x01\x00", 256),
],
)
def test_convert_bytes_to_int(data, result):
value = convert_bytes_to_int(data)
print(value)

View File

@@ -19,48 +19,48 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.pem import
PEM_TEST_CASES = [
(b'', [], False, 'raw'),
(b'random stuff\nblabla', [], False, 'raw'),
(b'-----BEGIN PRIVATE KEY-----', [], False, 'raw'),
(b"", [], False, "raw"),
(b"random stuff\nblabla", [], False, "raw"),
(b"-----BEGIN PRIVATE KEY-----", [], False, "raw"),
(
b'-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----',
['-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----'],
b"-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----",
["-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"],
True,
'pkcs8',
"pkcs8",
),
(
b'foo=bar\n# random stuff\n-----BEGIN RSA PRIVATE KEY-----\nblabla\n-----END RSA PRIVATE KEY-----\nmore stuff\n',
['-----BEGIN RSA PRIVATE KEY-----\nblabla\n-----END RSA PRIVATE KEY-----\n'],
b"foo=bar\n# random stuff\n-----BEGIN RSA PRIVATE KEY-----\nblabla\n-----END RSA PRIVATE KEY-----\nmore stuff\n",
["-----BEGIN RSA PRIVATE KEY-----\nblabla\n-----END RSA PRIVATE KEY-----\n"],
True,
'pkcs1',
"pkcs1",
),
(
b'foo=bar\n# random stuff\n-----BEGIN CERTIFICATE-----\nblabla\n-----END CERTIFICATE-----\nmore stuff\n'
b'\n-----BEGIN CERTIFICATE-----\nfoobar\n-----END CERTIFICATE-----',
b"foo=bar\n# random stuff\n-----BEGIN CERTIFICATE-----\nblabla\n-----END CERTIFICATE-----\nmore stuff\n"
b"\n-----BEGIN CERTIFICATE-----\nfoobar\n-----END CERTIFICATE-----",
[
'-----BEGIN CERTIFICATE-----\nblabla\n-----END CERTIFICATE-----\n',
'-----BEGIN CERTIFICATE-----\nfoobar\n-----END CERTIFICATE-----',
"-----BEGIN CERTIFICATE-----\nblabla\n-----END CERTIFICATE-----\n",
"-----BEGIN CERTIFICATE-----\nfoobar\n-----END CERTIFICATE-----",
],
True,
'unknown-pem',
"unknown-pem",
),
(
b'-----BEGINCERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n-----BEGINCERTIFICATE-----\n-----END CERTIFICATE-----\n-----BEGINCERTIFICATE-----\n',
b"-----BEGINCERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n-----BEGINCERTIFICATE-----\n-----END CERTIFICATE-----\n-----BEGINCERTIFICATE-----\n",
[
'-----BEGIN CERTIFICATE-----\n-----BEGINCERTIFICATE-----\n-----END CERTIFICATE-----\n',
"-----BEGIN CERTIFICATE-----\n-----BEGINCERTIFICATE-----\n-----END CERTIFICATE-----\n",
],
True,
'unknown-pem',
"unknown-pem",
),
]
@pytest.mark.parametrize('data, pems, is_pem, private_key_type', PEM_TEST_CASES)
@pytest.mark.parametrize("data, pems, is_pem, private_key_type", PEM_TEST_CASES)
def test_pem_handling(data, pems, is_pem, private_key_type):
assert identify_pem_format(data) == is_pem
assert identify_private_key_format(data) == private_key_type
try:
text = data.decode('utf-8')
text = data.decode("utf-8")
assert split_pem_list(text) == pems
first_pem = pems[0] if pems else None
assert extract_first_pem(text) == first_pem

View File

@@ -33,22 +33,22 @@ from ansible_collections.community.crypto.plugins.module_utils.openssh.certifica
# permit-pty
# permit-user-rc
RSA_CERT_SIGNED_BY_DSA = (
b'ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgY9CvhGpyvBB611Lmx6hHPD+CmeJ0oW' +
b'SSK1q6K3h5CS4AAAADAQABAAABAQDKYIJtpFaWpTNNifmuV3DM9BBdngMG28jWPy4C/SoZg4EP7mkYUsG6hN+LgjOL17YEF7bKDEWPl9sQS' +
b'92iD+AuAPrjnHVQ9VG5hbTYiQAaicj6hxqBoNqGQWxDzhZL4B35MgqmoUOBGnzYA/fKgqhRVzOXbWFxKLtzSJzB+Z+kmeoBzq+4MazL4Bko' +
b'yPZMrIMnvxiluv+kqE9SWeJ/5e7WXdtbYTnSR4WN3gW/BMKEoKQk/UGwuPvCiRq+y8LorJP4B1Wfwlm/meqtbTidXyCcQPR9xWpce3rRjLL' +
b'T6cimUjWrbx7Q1SlsypdkclgPSTu9Jg457am8tnQUgnL7VdetAAAAAAAAAAAAAAABAAAABHRlc3QAAAAAAAAAAAAAAAD//////////wAAAA' +
b'AAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0L' +
b'WZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAGxAAAAB3NzaC1kc3MAAACBAPV/' +
b'b5FknU8e56TWAGLRQ0v3c3f5jAS0txcwqtYLHLulTqyMcLL0MyzWxXv77MpjTMwEjWXLbfNWdk/qmsjfBynzs2nSZ7clVsqt/ZOadcBFEhq' +
b'ZM0l+1ZCPkhQiqsD2aodGbkVcJgqL5Z5krzB5MTey7c8rlAAxKOjfs70Bg8MPAAAAFQCW466dSEu2Pf0u8AA5SHgH0i/xuwAAAIBc23gfmv' +
b'GC+oaUAXiak17kH6NvOSJXZBdk/8CyGK6yL+CHKrKyffe6BbiVXwC6sUIa9j4YsFeyYwPFGBtfLuNUmgyKYTJcCM2zJLBykmTIvjSdRaYGN' +
b'Rkyi8GnzVV2lWxQ+4m4UGeTPbPN/OG4B0NwDbBJGbVJv0xJPq2EBKoUdgAAAIAyrFxGDLtOZFZ2fgONVaKaapEpJ5f3qPhLDXxVQ/BKVUkU' +
b'RA4AHHyXF2AMiiOOiHLrO5xsEGUyW+OISFm+6m17cEPNixA7G1fBniLvyVv2woyYW3kaY4J9z266kAFzFWVNgwr+T7MY0hEvct8VFA97JMR' +
b'Q7c8c/tNDaL7uqV46QQAAADcAAAAHc3NoLWRzcwAAAChaQ94wqca+KhkHtbkLpjvGsfu0Gy03SAb0+o11Shk/BXnK7N/cwEVD ' +
b'ansible@ansible-host'
b"ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgY9CvhGpyvBB611Lmx6hHPD+CmeJ0oW"
+ b"SSK1q6K3h5CS4AAAADAQABAAABAQDKYIJtpFaWpTNNifmuV3DM9BBdngMG28jWPy4C/SoZg4EP7mkYUsG6hN+LgjOL17YEF7bKDEWPl9sQS"
+ b"92iD+AuAPrjnHVQ9VG5hbTYiQAaicj6hxqBoNqGQWxDzhZL4B35MgqmoUOBGnzYA/fKgqhRVzOXbWFxKLtzSJzB+Z+kmeoBzq+4MazL4Bko"
+ b"yPZMrIMnvxiluv+kqE9SWeJ/5e7WXdtbYTnSR4WN3gW/BMKEoKQk/UGwuPvCiRq+y8LorJP4B1Wfwlm/meqtbTidXyCcQPR9xWpce3rRjLL"
+ b"T6cimUjWrbx7Q1SlsypdkclgPSTu9Jg457am8tnQUgnL7VdetAAAAAAAAAAAAAAABAAAABHRlc3QAAAAAAAAAAAAAAAD//////////wAAAA"
+ b"AAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0L"
+ b"WZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAGxAAAAB3NzaC1kc3MAAACBAPV/"
+ b"b5FknU8e56TWAGLRQ0v3c3f5jAS0txcwqtYLHLulTqyMcLL0MyzWxXv77MpjTMwEjWXLbfNWdk/qmsjfBynzs2nSZ7clVsqt/ZOadcBFEhq"
+ b"ZM0l+1ZCPkhQiqsD2aodGbkVcJgqL5Z5krzB5MTey7c8rlAAxKOjfs70Bg8MPAAAAFQCW466dSEu2Pf0u8AA5SHgH0i/xuwAAAIBc23gfmv"
+ b"GC+oaUAXiak17kH6NvOSJXZBdk/8CyGK6yL+CHKrKyffe6BbiVXwC6sUIa9j4YsFeyYwPFGBtfLuNUmgyKYTJcCM2zJLBykmTIvjSdRaYGN"
+ b"Rkyi8GnzVV2lWxQ+4m4UGeTPbPN/OG4B0NwDbBJGbVJv0xJPq2EBKoUdgAAAIAyrFxGDLtOZFZ2fgONVaKaapEpJ5f3qPhLDXxVQ/BKVUkU"
+ b"RA4AHHyXF2AMiiOOiHLrO5xsEGUyW+OISFm+6m17cEPNixA7G1fBniLvyVv2woyYW3kaY4J9z266kAFzFWVNgwr+T7MY0hEvct8VFA97JMR"
+ b"Q7c8c/tNDaL7uqV46QQAAADcAAAAHc3NoLWRzcwAAAChaQ94wqca+KhkHtbkLpjvGsfu0Gy03SAb0+o11Shk/BXnK7N/cwEVD "
+ b"ansible@ansible-host"
)
RSA_FINGERPRINT = 'SHA256:SvUwwUer4AwsdePYseJR3LcZS8lnKi6BqiL51Dop030'
RSA_FINGERPRINT = "SHA256:SvUwwUer4AwsdePYseJR3LcZS8lnKi6BqiL51Dop030"
# Type: ssh-dss-cert-v01@openssh.com user certificate
# Public key: DSA-CERT SHA256:YCdJ2lYU+FSkWUud7zg1SJszprXoRGNU/GVcqXUjgC8
# Signing CA: ECDSA SHA256:w9lp4zGRJShhm4DzO3ulVm0BEcR0PMjrM6VanQo4C0w
@@ -59,18 +59,18 @@ RSA_FINGERPRINT = 'SHA256:SvUwwUer4AwsdePYseJR3LcZS8lnKi6BqiL51Dop030'
# Critical Options: (none)
# Extensions: (none)
DSA_CERT_SIGNED_BY_ECDSA_NO_OPTS = (
b'ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgsKvMxIv4viCNQX7z8K4/R5jronpZGf' +
b'ydpoBoh2Cx5dgAAACBAPV/b5FknU8e56TWAGLRQ0v3c3f5jAS0txcwqtYLHLulTqyMcLL0MyzWxXv77MpjTMwEjWXLbfNWdk/qmsjfBynzs' +
b'2nSZ7clVsqt/ZOadcBFEhqZM0l+1ZCPkhQiqsD2aodGbkVcJgqL5Z5krzB5MTey7c8rlAAxKOjfs70Bg8MPAAAAFQCW466dSEu2Pf0u8AA5' +
b'SHgH0i/xuwAAAIBc23gfmvGC+oaUAXiak17kH6NvOSJXZBdk/8CyGK6yL+CHKrKyffe6BbiVXwC6sUIa9j4YsFeyYwPFGBtfLuNUmgyKYTJ' +
b'cCM2zJLBykmTIvjSdRaYGNRkyi8GnzVV2lWxQ+4m4UGeTPbPN/OG4B0NwDbBJGbVJv0xJPq2EBKoUdgAAAIAyrFxGDLtOZFZ2fgONVaKaap' +
b'EpJ5f3qPhLDXxVQ/BKVUkURA4AHHyXF2AMiiOOiHLrO5xsEGUyW+OISFm+6m17cEPNixA7G1fBniLvyVv2woyYW3kaY4J9z266kAFzFWVNg' +
b'wr+T7MY0hEvct8VFA97JMRQ7c8c/tNDaL7uqV46QQAAAAAAAAAAAAAAAQAAAAR0ZXN0AAAAAAAAAAAAAAAA//////////8AAAAAAAAAAAAA' +
b'AAAAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOf55Wc0yzaJPtxXxBGZKmAUozbYXwxZGFS1c/FaJbwLpq/' +
b'wvanQKM01uU73swNIt+ZFra9kRSi21xjzgMPn7U0AAABkAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAABJAAAAIGmlKa/riG7+EpoW6dTJY6' +
b'0N8BrEcniKgOxdRM1EPJ2DAAAAIQDnK4stvbvS+Bn0/42Was7uOfJtnLYXs5EuB2L3uejPcQ== ansible@ansible-host'
b"ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgsKvMxIv4viCNQX7z8K4/R5jronpZGf"
+ b"ydpoBoh2Cx5dgAAACBAPV/b5FknU8e56TWAGLRQ0v3c3f5jAS0txcwqtYLHLulTqyMcLL0MyzWxXv77MpjTMwEjWXLbfNWdk/qmsjfBynzs"
+ b"2nSZ7clVsqt/ZOadcBFEhqZM0l+1ZCPkhQiqsD2aodGbkVcJgqL5Z5krzB5MTey7c8rlAAxKOjfs70Bg8MPAAAAFQCW466dSEu2Pf0u8AA5"
+ b"SHgH0i/xuwAAAIBc23gfmvGC+oaUAXiak17kH6NvOSJXZBdk/8CyGK6yL+CHKrKyffe6BbiVXwC6sUIa9j4YsFeyYwPFGBtfLuNUmgyKYTJ"
+ b"cCM2zJLBykmTIvjSdRaYGNRkyi8GnzVV2lWxQ+4m4UGeTPbPN/OG4B0NwDbBJGbVJv0xJPq2EBKoUdgAAAIAyrFxGDLtOZFZ2fgONVaKaap"
+ b"EpJ5f3qPhLDXxVQ/BKVUkURA4AHHyXF2AMiiOOiHLrO5xsEGUyW+OISFm+6m17cEPNixA7G1fBniLvyVv2woyYW3kaY4J9z266kAFzFWVNg"
+ b"wr+T7MY0hEvct8VFA97JMRQ7c8c/tNDaL7uqV46QQAAAAAAAAAAAAAAAQAAAAR0ZXN0AAAAAAAAAAAAAAAA//////////8AAAAAAAAAAAAA"
+ b"AAAAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOf55Wc0yzaJPtxXxBGZKmAUozbYXwxZGFS1c/FaJbwLpq/"
+ b"wvanQKM01uU73swNIt+ZFra9kRSi21xjzgMPn7U0AAABkAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAABJAAAAIGmlKa/riG7+EpoW6dTJY6"
+ b"0N8BrEcniKgOxdRM1EPJ2DAAAAIQDnK4stvbvS+Bn0/42Was7uOfJtnLYXs5EuB2L3uejPcQ== ansible@ansible-host"
)
DSA_FINGERPRINT = 'SHA256:YCdJ2lYU+FSkWUud7zg1SJszprXoRGNU/GVcqXUjgC8'
DSA_FINGERPRINT = "SHA256:YCdJ2lYU+FSkWUud7zg1SJszprXoRGNU/GVcqXUjgC8"
# Type: ecdsa-sha2-nistp256-cert-v01@openssh.com user certificate
# Public key: ECDSA-CERT SHA256:w9lp4zGRJShhm4DzO3ulVm0BEcR0PMjrM6VanQo4C0w
# Signing CA: ED25519 SHA256:NP4JdfkCopbjwMepq0aPrpMz13cNmEd+uDOxC/j9N40
@@ -87,16 +87,16 @@ DSA_FINGERPRINT = 'SHA256:YCdJ2lYU+FSkWUud7zg1SJszprXoRGNU/GVcqXUjgC8'
# permit-pty
# permit-user-rc
ECDSA_CERT_SIGNED_BY_ED25519_VALID_OPTS = (
b'ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgtC' +
b'ips7/sOOOTAgiawGlQhM6pb26t0FfQ1jG60m+tOg0AAAAIbmlzdHAyNTYAAABBBOf55Wc0yzaJPtxXxBGZKmAUozbYXwxZGFS1c/FaJbwLp' +
b'q/wvanQKM01uU73swNIt+ZFra9kRSi21xjzgMPn7U0AAAAAAAAAAAAAAAEAAAAEdGVzdAAAAAAAAAAAAAAAAP//////////AAAAJQAAAA1m' +
b'b3JjZS1jb21tYW5kAAAAEAAAAAwvdXNyL2Jpbi9jc2gAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW5' +
b'0LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLX' +
b'JjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAII3qYBforim0x87UXpaTDNFnhFTyb+TPCJVQpEAOHTL6AAAAUwAAAAtzc2gtZWQyN' +
b'TUxOQAAAEAdp3eOLRN5t2wW29TBWbz604uuXg88jH4RA4HDhbRupa/x2rN3j6iZQ4VXPLA4JtdfIslHFkH6HUlxU8XsoJwP ' +
b'ansible@ansible-host'
b"ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgtC"
+ b"ips7/sOOOTAgiawGlQhM6pb26t0FfQ1jG60m+tOg0AAAAIbmlzdHAyNTYAAABBBOf55Wc0yzaJPtxXxBGZKmAUozbYXwxZGFS1c/FaJbwLp"
+ b"q/wvanQKM01uU73swNIt+ZFra9kRSi21xjzgMPn7U0AAAAAAAAAAAAAAAEAAAAEdGVzdAAAAAAAAAAAAAAAAP//////////AAAAJQAAAA1m"
+ b"b3JjZS1jb21tYW5kAAAAEAAAAAwvdXNyL2Jpbi9jc2gAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW5"
+ b"0LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLX"
+ b"JjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAII3qYBforim0x87UXpaTDNFnhFTyb+TPCJVQpEAOHTL6AAAAUwAAAAtzc2gtZWQyN"
+ b"TUxOQAAAEAdp3eOLRN5t2wW29TBWbz604uuXg88jH4RA4HDhbRupa/x2rN3j6iZQ4VXPLA4JtdfIslHFkH6HUlxU8XsoJwP "
+ b"ansible@ansible-host"
)
ECDSA_FINGERPRINT = 'SHA256:w9lp4zGRJShhm4DzO3ulVm0BEcR0PMjrM6VanQo4C0w'
ECDSA_FINGERPRINT = "SHA256:w9lp4zGRJShhm4DzO3ulVm0BEcR0PMjrM6VanQo4C0w"
# Type: ssh-ed25519-cert-v01@openssh.com user certificate
# Public key: ED25519-CERT SHA256:NP4JdfkCopbjwMepq0aPrpMz13cNmEd+uDOxC/j9N40
# Signing CA: RSA SHA256:SvUwwUer4AwsdePYseJR3LcZS8lnKi6BqiL51Dop030
@@ -109,57 +109,123 @@ ECDSA_FINGERPRINT = 'SHA256:w9lp4zGRJShhm4DzO3ulVm0BEcR0PMjrM6VanQo4C0w'
# Extensions:
# test UNKNOWN OPTION (len 0)
ED25519_CERT_SIGNED_BY_RSA_INVALID_OPTS = (
b'ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIP034YpKn6BDcwxqFnVrKt' +
b'kNX7k6X7hxZ7lADp5LAxHrAAAAII3qYBforim0x87UXpaTDNFnhFTyb+TPCJVQpEAOHTL6AAAAAAAAAAAAAAABAAAABHRlc3QAAAAAAAAAA' +
b'AAAAAD//////////wAAABkAAAAEdGVzdAAAAA0AAAAJdW5kZWZpbmVkAAAADAAAAAR0ZXN0AAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAAD' +
b'AQABAAABAQDKYIJtpFaWpTNNifmuV3DM9BBdngMG28jWPy4C/SoZg4EP7mkYUsG6hN+LgjOL17YEF7bKDEWPl9sQS92iD+AuAPrjnHVQ9VG' +
b'5hbTYiQAaicj6hxqBoNqGQWxDzhZL4B35MgqmoUOBGnzYA/fKgqhRVzOXbWFxKLtzSJzB+Z+kmeoBzq+4MazL4BkoyPZMrIMnvxiluv+kqE' +
b'9SWeJ/5e7WXdtbYTnSR4WN3gW/BMKEoKQk/UGwuPvCiRq+y8LorJP4B1Wfwlm/meqtbTidXyCcQPR9xWpce3rRjLLT6cimUjWrbx7Q1Slsy' +
b'pdkclgPSTu9Jg457am8tnQUgnL7VdetAAABDwAAAAdzc2gtcnNhAAABAMZLNacwOMNexYUaFK1nU0JPQTv4fM73QDG3xURtDsIbI6DAcA1y' +
b'KkvgjJcxlZHx0APJ+i1lWNAvPeOmuPTioymjIEuwxi0VGuAoVKgjmIy6aXH2z3YMxy9cGOq6LNfI4c58iBHR5ejVHAzvIg3rowypVsCGugL' +
b'7WJpz3eypBJt4TglwRTJpp54IMN2CyDQm0N97x9ris8jQQHlCF2EgZp1u4aOiZJTSJ5d4hapO0uZwXOI9AIWy/lmx0/6jX07MWrs4iXpfiF' +
b'5T4s6kEn7YW4SaJ0Z7xGp3V0vDOxh+jwHZGD5GM449Il6QxQwDY5BSJq+iMR467yaIjw2g8Kt4ZiU= ansible@ansible-host'
b"ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIP034YpKn6BDcwxqFnVrKt"
+ b"kNX7k6X7hxZ7lADp5LAxHrAAAAII3qYBforim0x87UXpaTDNFnhFTyb+TPCJVQpEAOHTL6AAAAAAAAAAAAAAABAAAABHRlc3QAAAAAAAAAA"
+ b"AAAAAD//////////wAAABkAAAAEdGVzdAAAAA0AAAAJdW5kZWZpbmVkAAAADAAAAAR0ZXN0AAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAAD"
+ b"AQABAAABAQDKYIJtpFaWpTNNifmuV3DM9BBdngMG28jWPy4C/SoZg4EP7mkYUsG6hN+LgjOL17YEF7bKDEWPl9sQS92iD+AuAPrjnHVQ9VG"
+ b"5hbTYiQAaicj6hxqBoNqGQWxDzhZL4B35MgqmoUOBGnzYA/fKgqhRVzOXbWFxKLtzSJzB+Z+kmeoBzq+4MazL4BkoyPZMrIMnvxiluv+kqE"
+ b"9SWeJ/5e7WXdtbYTnSR4WN3gW/BMKEoKQk/UGwuPvCiRq+y8LorJP4B1Wfwlm/meqtbTidXyCcQPR9xWpce3rRjLLT6cimUjWrbx7Q1Slsy"
+ b"pdkclgPSTu9Jg457am8tnQUgnL7VdetAAABDwAAAAdzc2gtcnNhAAABAMZLNacwOMNexYUaFK1nU0JPQTv4fM73QDG3xURtDsIbI6DAcA1y"
+ b"KkvgjJcxlZHx0APJ+i1lWNAvPeOmuPTioymjIEuwxi0VGuAoVKgjmIy6aXH2z3YMxy9cGOq6LNfI4c58iBHR5ejVHAzvIg3rowypVsCGugL"
+ b"7WJpz3eypBJt4TglwRTJpp54IMN2CyDQm0N97x9ris8jQQHlCF2EgZp1u4aOiZJTSJ5d4hapO0uZwXOI9AIWy/lmx0/6jX07MWrs4iXpfiF"
+ b"5T4s6kEn7YW4SaJ0Z7xGp3V0vDOxh+jwHZGD5GM449Il6QxQwDY5BSJq+iMR467yaIjw2g8Kt4ZiU= ansible@ansible-host"
)
ED25519_FINGERPRINT = 'SHA256:NP4JdfkCopbjwMepq0aPrpMz13cNmEd+uDOxC/j9N40'
ED25519_FINGERPRINT = "SHA256:NP4JdfkCopbjwMepq0aPrpMz13cNmEd+uDOxC/j9N40"
# garbage
INVALID_DATA = b'yDspTN+BJzvIK2Q+CRD3qBDVSi+YqSxwyz432VEaHKlXbuLURirY0QpuBCqgR6tCtWW5vEGkXKZ3'
INVALID_DATA = (
b"yDspTN+BJzvIK2Q+CRD3qBDVSi+YqSxwyz432VEaHKlXbuLURirY0QpuBCqgR6tCtWW5vEGkXKZ3"
)
VALID_OPTS = [OpensshCertificateOption('critical', 'force-command', '/usr/bin/csh')]
INVALID_OPTS = [OpensshCertificateOption('critical', 'test', 'undefined')]
VALID_OPTS = [OpensshCertificateOption("critical", "force-command", "/usr/bin/csh")]
INVALID_OPTS = [OpensshCertificateOption("critical", "test", "undefined")]
VALID_EXTENSIONS = [
OpensshCertificateOption('extension', 'permit-x11-forwarding', ''),
OpensshCertificateOption('extension', 'permit-agent-forwarding', ''),
OpensshCertificateOption('extension', 'permit-port-forwarding', ''),
OpensshCertificateOption('extension', 'permit-pty', ''),
OpensshCertificateOption('extension', 'permit-user-rc', ''),
OpensshCertificateOption("extension", "permit-x11-forwarding", ""),
OpensshCertificateOption("extension", "permit-agent-forwarding", ""),
OpensshCertificateOption("extension", "permit-port-forwarding", ""),
OpensshCertificateOption("extension", "permit-pty", ""),
OpensshCertificateOption("extension", "permit-user-rc", ""),
]
INVALID_EXTENSIONS = [OpensshCertificateOption('extension', 'test', '')]
INVALID_EXTENSIONS = [OpensshCertificateOption("extension", "test", "")]
VALID_TIME_PARAMETERS = [
(0, "always", "always", 0,
0xFFFFFFFFFFFFFFFF, "forever", "forever", 253402300800,
""),
("always", "always", "always", 0,
"forever", "forever", "forever", 253402300800,
""),
(315532800, "1980-01-01T00:00:00", "19800101000000", 315532800,
631152000, "1990-01-01T00:00:00", "19900101000000", 631152000,
"19800101000000:19900101000000"),
("1980-01-01", "1980-01-01T00:00:00", "19800101000000", 315532800,
"1990-01-01", "1990-01-01T00:00:00", "19900101000000", 631152000,
"19800101000000:19900101000000"),
("1980-01-01 00:00:00", "1980-01-01T00:00:00", "19800101000000", 315532800,
"1990-01-01 00:00:00", "1990-01-01T00:00:00", "19900101000000", 631152000,
"19800101000000:19900101000000"),
("1980-01-01T00:00:00", "1980-01-01T00:00:00", "19800101000000", 315532800,
"1990-01-01T00:00:00", "1990-01-01T00:00:00", "19900101000000", 631152000,
"19800101000000:19900101000000"),
("always", "always", "always", 0,
"1990-01-01T00:00:00", "1990-01-01T00:00:00", "19900101000000", 631152000,
"always:19900101000000"),
("1980-01-01", "1980-01-01T00:00:00", "19800101000000", 315532800,
"forever", "forever", "forever", 253402300800,
"19800101000000:forever"),
(
0,
"always",
"always",
0,
0xFFFFFFFFFFFFFFFF,
"forever",
"forever",
253402300800,
"",
),
(
"always",
"always",
"always",
0,
"forever",
"forever",
"forever",
253402300800,
"",
),
(
315532800,
"1980-01-01T00:00:00",
"19800101000000",
315532800,
631152000,
"1990-01-01T00:00:00",
"19900101000000",
631152000,
"19800101000000:19900101000000",
),
(
"1980-01-01",
"1980-01-01T00:00:00",
"19800101000000",
315532800,
"1990-01-01",
"1990-01-01T00:00:00",
"19900101000000",
631152000,
"19800101000000:19900101000000",
),
(
"1980-01-01 00:00:00",
"1980-01-01T00:00:00",
"19800101000000",
315532800,
"1990-01-01 00:00:00",
"1990-01-01T00:00:00",
"19900101000000",
631152000,
"19800101000000:19900101000000",
),
(
"1980-01-01T00:00:00",
"1980-01-01T00:00:00",
"19800101000000",
315532800,
"1990-01-01T00:00:00",
"1990-01-01T00:00:00",
"19900101000000",
631152000,
"19800101000000:19900101000000",
),
(
"always",
"always",
"always",
0,
"1990-01-01T00:00:00",
"1990-01-01T00:00:00",
"19900101000000",
631152000,
"always:19900101000000",
),
(
"1980-01-01",
"1980-01-01T00:00:00",
"19800101000000",
315532800,
"forever",
"forever",
"forever",
253402300800,
"19800101000000:forever",
),
]
INVALID_TIME_PARAMETERS = [
@@ -184,41 +250,53 @@ INVALID_VALIDITY_TEST = [
]
VALID_OPTIONS = [
("force-command=/usr/bin/csh", OpensshCertificateOption('critical', 'force-command', '/usr/bin/csh')),
("Force-Command=/Usr/Bin/Csh", OpensshCertificateOption('critical', 'force-command', '/Usr/Bin/Csh')),
("permit-x11-forwarding", OpensshCertificateOption('extension', 'permit-x11-forwarding', '')),
("permit-X11-forwarding", OpensshCertificateOption('extension', 'permit-x11-forwarding', '')),
("critical:foo=bar", OpensshCertificateOption('critical', 'foo', 'bar')),
("extension:foo", OpensshCertificateOption('extension', 'foo', '')),
(
"force-command=/usr/bin/csh",
OpensshCertificateOption("critical", "force-command", "/usr/bin/csh"),
),
(
"Force-Command=/Usr/Bin/Csh",
OpensshCertificateOption("critical", "force-command", "/Usr/Bin/Csh"),
),
(
"permit-x11-forwarding",
OpensshCertificateOption("extension", "permit-x11-forwarding", ""),
),
(
"permit-X11-forwarding",
OpensshCertificateOption("extension", "permit-x11-forwarding", ""),
),
("critical:foo=bar", OpensshCertificateOption("critical", "foo", "bar")),
("extension:foo", OpensshCertificateOption("extension", "foo", "")),
]
INVALID_OPTIONS = [
"foobar",
"foo=bar",
'foo:bar=baz',
"foo:bar=baz",
[],
]
def test_rsa_certificate(tmpdir):
cert_file = tmpdir / 'id_rsa-cert.pub'
cert_file.write(RSA_CERT_SIGNED_BY_DSA, mode='wb')
cert_file = tmpdir / "id_rsa-cert.pub"
cert_file.write(RSA_CERT_SIGNED_BY_DSA, mode="wb")
cert = OpensshCertificate.load(str(cert_file))
assert cert.key_id == 'test'
assert cert.key_id == "test"
assert cert.serial == 0
assert cert.type_string == 'ssh-rsa-cert-v01@openssh.com'
assert cert.type_string == "ssh-rsa-cert-v01@openssh.com"
assert cert.public_key == RSA_FINGERPRINT
assert cert.signing_key == DSA_FINGERPRINT
def test_dsa_certificate(tmpdir):
cert_file = tmpdir / 'id_dsa-cert.pub'
cert_file = tmpdir / "id_dsa-cert.pub"
cert_file.write(DSA_CERT_SIGNED_BY_ECDSA_NO_OPTS)
cert = OpensshCertificate.load(str(cert_file))
assert cert.type_string == 'ssh-dss-cert-v01@openssh.com'
assert cert.type_string == "ssh-dss-cert-v01@openssh.com"
assert cert.public_key == DSA_FINGERPRINT
assert cert.signing_key == ECDSA_FINGERPRINT
assert cert.critical_options == []
@@ -226,11 +304,11 @@ def test_dsa_certificate(tmpdir):
def test_ecdsa_certificate(tmpdir):
cert_file = tmpdir / 'id_ecdsa-cert.pub'
cert_file = tmpdir / "id_ecdsa-cert.pub"
cert_file.write(ECDSA_CERT_SIGNED_BY_ED25519_VALID_OPTS)
cert = OpensshCertificate.load(str(cert_file))
assert cert.type_string == 'ecdsa-sha2-nistp256-cert-v01@openssh.com'
assert cert.type_string == "ecdsa-sha2-nistp256-cert-v01@openssh.com"
assert cert.public_key == ECDSA_FINGERPRINT
assert cert.signing_key == ED25519_FINGERPRINT
assert cert.critical_options == VALID_OPTS
@@ -238,11 +316,11 @@ def test_ecdsa_certificate(tmpdir):
def test_ed25519_certificate(tmpdir):
cert_file = tmpdir / 'id_ed25519-cert.pub'
cert_file = tmpdir / "id_ed25519-cert.pub"
cert_file.write(ED25519_CERT_SIGNED_BY_RSA_INVALID_OPTS)
cert = OpensshCertificate.load(str(cert_file))
assert cert.type_string == 'ssh-ed25519-cert-v01@openssh.com'
assert cert.type_string == "ssh-ed25519-cert-v01@openssh.com"
assert cert.public_key == ED25519_FINGERPRINT
assert cert.signing_key == RSA_FINGERPRINT
assert cert.critical_options == INVALID_OPTS
@@ -251,7 +329,7 @@ def test_ed25519_certificate(tmpdir):
def test_invalid_data(tmpdir):
result = False
cert_file = tmpdir / 'invalid-cert.pub'
cert_file = tmpdir / "invalid-cert.pub"
cert_file.write(INVALID_DATA)
try:
@@ -262,17 +340,24 @@ def test_invalid_data(tmpdir):
@pytest.mark.parametrize(
"valid_from,valid_from_hr,valid_from_openssh,valid_from_timestamp," +
"valid_to,valid_to_hr,valid_to_openssh,valid_to_timestamp," +
"validity_string",
VALID_TIME_PARAMETERS
"valid_from,valid_from_hr,valid_from_openssh,valid_from_timestamp,"
+ "valid_to,valid_to_hr,valid_to_openssh,valid_to_timestamp,"
+ "validity_string",
VALID_TIME_PARAMETERS,
)
def test_valid_time_parameters(valid_from, valid_from_hr, valid_from_openssh, valid_from_timestamp,
valid_to, valid_to_hr, valid_to_openssh, valid_to_timestamp,
validity_string):
def test_valid_time_parameters(
valid_from,
valid_from_hr,
valid_from_openssh,
valid_from_timestamp,
valid_to,
valid_to_hr,
valid_to_openssh,
valid_to_timestamp,
validity_string,
):
time_parameters = OpensshCertificateTimeParameters(
valid_from=valid_from,
valid_to=valid_to
valid_from=valid_from, valid_to=valid_to
)
assert time_parameters.valid_from(date_format="human_readable") == valid_from_hr
assert time_parameters.valid_from(date_format="openssh") == valid_from_openssh
@@ -296,7 +381,9 @@ def test_valid_validity_test(valid_from, valid_to, valid_at):
@pytest.mark.parametrize("valid_from,valid_to,valid_at", INVALID_VALIDITY_TEST)
def test_invalid_validity_test(valid_from, valid_to, valid_at):
assert not OpensshCertificateTimeParameters(valid_from, valid_to).within_range(valid_at)
assert not OpensshCertificateTimeParameters(valid_from, valid_to).within_range(
valid_at
)
@pytest.mark.parametrize("option_string,option_object", VALID_OPTIONS)
@@ -311,18 +398,18 @@ def test_invalid_options(option_string):
def test_parse_option_list():
critical_options, extensions = parse_option_list(['force-command=/usr/bin/csh'])
critical_options, extensions = parse_option_list(["force-command=/usr/bin/csh"])
critical_option_objects = [
OpensshCertificateOption.from_string('force-command=/usr/bin/csh'),
OpensshCertificateOption.from_string("force-command=/usr/bin/csh"),
]
extension_objects = [
OpensshCertificateOption.from_string('permit-x11-forwarding'),
OpensshCertificateOption.from_string('permit-agent-forwarding'),
OpensshCertificateOption.from_string('permit-port-forwarding'),
OpensshCertificateOption.from_string('permit-user-rc'),
OpensshCertificateOption.from_string('permit-pty'),
OpensshCertificateOption.from_string("permit-x11-forwarding"),
OpensshCertificateOption.from_string("permit-agent-forwarding"),
OpensshCertificateOption.from_string("permit-port-forwarding"),
OpensshCertificateOption.from_string("permit-user-rc"),
OpensshCertificateOption.from_string("permit-pty"),
]
assert set(critical_options) == set(critical_option_objects)
@@ -330,11 +417,13 @@ def test_parse_option_list():
def test_parse_option_list_with_directives():
critical_options, extensions = parse_option_list(['clear', 'no-pty', 'permit-pty', 'permit-user-rc'])
critical_options, extensions = parse_option_list(
["clear", "no-pty", "permit-pty", "permit-user-rc"]
)
extension_objects = [
OpensshCertificateOption.from_string('permit-user-rc'),
OpensshCertificateOption.from_string('permit-pty'),
OpensshCertificateOption.from_string("permit-user-rc"),
OpensshCertificateOption.from_string("permit-pty"),
]
assert set(critical_options) == set()
@@ -342,10 +431,12 @@ def test_parse_option_list_with_directives():
def test_parse_option_list_case_sensitivity():
critical_options, extensions = parse_option_list(['CLEAR', 'no-X11-forwarding', 'permit-X11-forwarding'])
critical_options, extensions = parse_option_list(
["CLEAR", "no-X11-forwarding", "permit-X11-forwarding"]
)
extension_objects = [
OpensshCertificateOption.from_string('permit-x11-forwarding'),
OpensshCertificateOption.from_string("permit-x11-forwarding"),
]
assert set(critical_options) == set()

View File

@@ -30,25 +30,25 @@ from ansible_collections.community.crypto.plugins.module_utils.openssh.cryptogra
DEFAULT_KEY_PARAMS = [
(
'rsa',
"rsa",
None,
None,
None,
),
(
'dsa',
"dsa",
None,
None,
None,
),
(
'ecdsa',
"ecdsa",
None,
None,
None,
),
(
'ed25519',
"ed25519",
None,
None,
None,
@@ -57,46 +57,46 @@ DEFAULT_KEY_PARAMS = [
VALID_USER_KEY_PARAMS = [
(
'rsa',
"rsa",
8192,
'change_me'.encode('UTF-8'),
'comment',
"change_me".encode("UTF-8"),
"comment",
),
(
'dsa',
"dsa",
1024,
'change_me'.encode('UTF-8'),
'comment',
"change_me".encode("UTF-8"),
"comment",
),
(
'ecdsa',
"ecdsa",
521,
'change_me'.encode('UTF-8'),
'comment',
"change_me".encode("UTF-8"),
"comment",
),
(
'ed25519',
"ed25519",
256,
'change_me'.encode('UTF-8'),
'comment',
"change_me".encode("UTF-8"),
"comment",
),
]
INVALID_USER_KEY_PARAMS = [
(
'dne',
"dne",
None,
None,
None,
),
(
'rsa',
"rsa",
None,
[1, 2, 3],
'comment',
"comment",
),
(
'ecdsa',
"ecdsa",
None,
None,
[1, 2, 3],
@@ -105,31 +105,31 @@ INVALID_USER_KEY_PARAMS = [
INVALID_KEY_SIZES = [
(
'rsa',
"rsa",
1023,
None,
None,
),
(
'rsa',
"rsa",
16385,
None,
None,
),
(
'dsa',
"dsa",
256,
None,
None,
),
(
'ecdsa',
"ecdsa",
1024,
None,
None,
),
(
'ed25519',
"ed25519",
1024,
None,
None,
@@ -143,16 +143,20 @@ def test_default_key_params(keytype, size, passphrase, comment):
result = True
default_sizes = {
'rsa': 2048,
'dsa': 1024,
'ecdsa': 256,
'ed25519': 256,
"rsa": 2048,
"dsa": 1024,
"ecdsa": 256,
"ed25519": 256,
}
default_comment = "%s@%s" % (getuser(), gethostname())
pair = OpensshKeypair.generate(keytype=keytype, size=size, passphrase=passphrase, comment=comment)
pair = OpensshKeypair.generate(
keytype=keytype, size=size, passphrase=passphrase, comment=comment
)
try:
pair = OpensshKeypair.generate(keytype=keytype, size=size, passphrase=passphrase, comment=comment)
pair = OpensshKeypair.generate(
keytype=keytype, size=size, passphrase=passphrase, comment=comment
)
if pair.size != default_sizes[pair.key_type] or pair.comment != default_comment:
result = False
except Exception as e:
@@ -168,7 +172,9 @@ def test_valid_user_key_params(keytype, size, passphrase, comment):
result = True
try:
pair = OpensshKeypair.generate(keytype=keytype, size=size, passphrase=passphrase, comment=comment)
pair = OpensshKeypair.generate(
keytype=keytype, size=size, passphrase=passphrase, comment=comment
)
if pair.key_type != keytype or pair.size != size or pair.comment != comment:
result = False
except Exception as e:
@@ -184,7 +190,9 @@ def test_invalid_user_key_params(keytype, size, passphrase, comment):
result = False
try:
OpensshKeypair.generate(keytype=keytype, size=size, passphrase=passphrase, comment=comment)
OpensshKeypair.generate(
keytype=keytype, size=size, passphrase=passphrase, comment=comment
)
except (InvalidCommentError, InvalidKeyTypeError, InvalidPassphraseError):
result = True
except Exception as e:
@@ -200,7 +208,9 @@ def test_invalid_key_sizes(keytype, size, passphrase, comment):
result = False
try:
OpensshKeypair.generate(keytype=keytype, size=size, passphrase=passphrase, comment=comment)
OpensshKeypair.generate(
keytype=keytype, size=size, passphrase=passphrase, comment=comment
)
except InvalidKeySizeError:
result = True
except Exception as e:
@@ -221,7 +231,10 @@ def test_valid_comment_update():
print(e)
pass
assert pair.comment == new_comment and pair.public_key.split(b' ', 2)[2].decode() == new_comment
assert (
pair.comment == new_comment
and pair.public_key.split(b" ", 2)[2].decode() == new_comment
)
@pytest.mark.skipif(not HAS_OPENSSH_SUPPORT, reason="requires cryptography")
@@ -242,7 +255,7 @@ def test_invalid_comment_update():
def test_valid_passphrase_update():
result = False
passphrase = "change_me".encode('UTF-8')
passphrase = "change_me".encode("UTF-8")
try:
tmpdir = mkdtemp()
@@ -254,7 +267,7 @@ def test_valid_passphrase_update():
with open(keyfilename, "w+b") as keyfile:
keyfile.write(pair1.private_key)
with open(keyfilename + '.pub', "w+b") as pubkeyfile:
with open(keyfilename + ".pub", "w+b") as pubkeyfile:
pubkeyfile.write(pair1.public_key)
pair2 = OpensshKeypair.load(path=keyfilename, passphrase=passphrase)
@@ -264,8 +277,8 @@ def test_valid_passphrase_update():
finally:
if os.path.exists(keyfilename):
remove(keyfilename)
if os.path.exists(keyfilename + '.pub'):
remove(keyfilename + '.pub')
if os.path.exists(keyfilename + ".pub"):
remove(keyfilename + ".pub")
if os.path.exists(tmpdir):
rmdir(tmpdir)
@@ -299,7 +312,7 @@ def test_invalid_privatekey():
with open(keyfilename, "w+b") as keyfile:
keyfile.write(pair.private_key[1:])
with open(keyfilename + '.pub', "w+b") as pubkeyfile:
with open(keyfilename + ".pub", "w+b") as pubkeyfile:
pubkeyfile.write(pair.public_key)
OpensshKeypair.load(path=keyfilename)
@@ -308,8 +321,8 @@ def test_invalid_privatekey():
finally:
if os.path.exists(keyfilename):
remove(keyfilename)
if os.path.exists(keyfilename + '.pub'):
remove(keyfilename + '.pub')
if os.path.exists(keyfilename + ".pub"):
remove(keyfilename + ".pub")
if os.path.exists(tmpdir):
rmdir(tmpdir)
@@ -330,7 +343,7 @@ def test_mismatched_keypair():
with open(keyfilename, "w+b") as keyfile:
keyfile.write(pair1.private_key)
with open(keyfilename + '.pub', "w+b") as pubkeyfile:
with open(keyfilename + ".pub", "w+b") as pubkeyfile:
pubkeyfile.write(pair2.public_key)
OpensshKeypair.load(path=keyfilename)
@@ -339,8 +352,8 @@ def test_mismatched_keypair():
finally:
if os.path.exists(keyfilename):
remove(keyfilename)
if os.path.exists(keyfilename + '.pub'):
remove(keyfilename + '.pub')
if os.path.exists(keyfilename + ".pub"):
remove(keyfilename + ".pub")
if os.path.exists(tmpdir):
rmdir(tmpdir)
@@ -350,54 +363,62 @@ def test_mismatched_keypair():
@pytest.mark.skipif(not HAS_OPENSSH_SUPPORT, reason="requires cryptography")
def test_keypair_comparison():
assert OpensshKeypair.generate() != OpensshKeypair.generate()
assert OpensshKeypair.generate() != OpensshKeypair.generate(keytype='dsa')
assert OpensshKeypair.generate() != OpensshKeypair.generate(keytype='ed25519')
assert OpensshKeypair.generate(keytype='ed25519') != OpensshKeypair.generate(keytype='ed25519')
assert OpensshKeypair.generate() != OpensshKeypair.generate(keytype="dsa")
assert OpensshKeypair.generate() != OpensshKeypair.generate(keytype="ed25519")
assert OpensshKeypair.generate(keytype="ed25519") != OpensshKeypair.generate(
keytype="ed25519"
)
try:
tmpdir = mkdtemp()
keys = {
'rsa': {
'pair': OpensshKeypair.generate(),
'filename': os.path.join(tmpdir, "id_rsa"),
"rsa": {
"pair": OpensshKeypair.generate(),
"filename": os.path.join(tmpdir, "id_rsa"),
},
'dsa': {
'pair': OpensshKeypair.generate(keytype='dsa', passphrase='change_me'.encode('UTF-8')),
'filename': os.path.join(tmpdir, "id_dsa"),
"dsa": {
"pair": OpensshKeypair.generate(
keytype="dsa", passphrase="change_me".encode("UTF-8")
),
"filename": os.path.join(tmpdir, "id_dsa"),
},
"ed25519": {
"pair": OpensshKeypair.generate(keytype="ed25519"),
"filename": os.path.join(tmpdir, "id_ed25519"),
},
'ed25519': {
'pair': OpensshKeypair.generate(keytype='ed25519'),
'filename': os.path.join(tmpdir, "id_ed25519"),
}
}
for v in keys.values():
with open(v['filename'], "w+b") as keyfile:
keyfile.write(v['pair'].private_key)
with open(v['filename'] + '.pub', "w+b") as pubkeyfile:
pubkeyfile.write(v['pair'].public_key)
with open(v["filename"], "w+b") as keyfile:
keyfile.write(v["pair"].private_key)
with open(v["filename"] + ".pub", "w+b") as pubkeyfile:
pubkeyfile.write(v["pair"].public_key)
assert keys['rsa']['pair'] == OpensshKeypair.load(path=keys['rsa']['filename'])
assert keys["rsa"]["pair"] == OpensshKeypair.load(path=keys["rsa"]["filename"])
loaded_dsa_key = OpensshKeypair.load(path=keys['dsa']['filename'], passphrase='change_me'.encode('UTF-8'))
assert keys['dsa']['pair'] == loaded_dsa_key
loaded_dsa_key = OpensshKeypair.load(
path=keys["dsa"]["filename"], passphrase="change_me".encode("UTF-8")
)
assert keys["dsa"]["pair"] == loaded_dsa_key
loaded_dsa_key.update_passphrase('change_me_again'.encode('UTF-8'))
assert keys['dsa']['pair'] != loaded_dsa_key
loaded_dsa_key.update_passphrase("change_me_again".encode("UTF-8"))
assert keys["dsa"]["pair"] != loaded_dsa_key
loaded_dsa_key.update_passphrase('change_me'.encode('UTF-8'))
assert keys['dsa']['pair'] == loaded_dsa_key
loaded_dsa_key.update_passphrase("change_me".encode("UTF-8"))
assert keys["dsa"]["pair"] == loaded_dsa_key
loaded_dsa_key.comment = "comment"
assert keys['dsa']['pair'] != loaded_dsa_key
assert keys["dsa"]["pair"] != loaded_dsa_key
assert keys['ed25519']['pair'] == OpensshKeypair.load(path=keys['ed25519']['filename'])
assert keys["ed25519"]["pair"] == OpensshKeypair.load(
path=keys["ed25519"]["filename"]
)
finally:
for v in keys.values():
if os.path.exists(v['filename']):
remove(v['filename'])
if os.path.exists(v['filename'] + '.pub'):
remove(v['filename'] + '.pub')
if os.path.exists(v["filename"]):
remove(v["filename"])
if os.path.exists(v["filename"] + ".pub"):
remove(v["filename"] + ".pub")
if os.path.exists(tmpdir):
rmdir(tmpdir)
assert OpensshKeypair.generate() != []

View File

@@ -20,13 +20,8 @@ from ansible_collections.community.crypto.plugins.module_utils.openssh.utils imp
SSH_VERSION_STRING = "OpenSSH_7.9p1, OpenSSL 1.1.0i-fips 14 Aug 2018"
SSH_VERSION_NUMBER = "7.9"
VALID_BOOLEAN = [
True,
False
]
INVALID_BOOLEAN = [
0x02
]
VALID_BOOLEAN = [True, False]
INVALID_BOOLEAN = [0x02]
VALID_UINT32 = [
0x00,
0x01,
@@ -48,7 +43,7 @@ INVALID_UINT64 = [
-1,
]
VALID_STRING = [
b'test string',
b"test string",
]
INVALID_STRING = [
[],
@@ -56,10 +51,10 @@ INVALID_STRING = [
# See https://datatracker.ietf.org/doc/html/rfc4251#section-5 for examples source
VALID_MPINT = [
0x00,
0x9a378f9b2e332a7,
0x9A378F9B2E332A7,
0x80,
-0x1234,
-0xdeadbeef,
-0xDEADBEEF,
# Additional large int test
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
]
@@ -107,7 +102,10 @@ def test_invalid_uint64(uint64):
@pytest.mark.parametrize("ssh_string", VALID_STRING)
def test_valid_string(ssh_string):
assert OpensshParser(_OpensshWriter().string(ssh_string).bytes()).string() == ssh_string
assert (
OpensshParser(_OpensshWriter().string(ssh_string).bytes()).string()
== ssh_string
)
@pytest.mark.parametrize("ssh_string", INVALID_STRING)
@@ -128,7 +126,7 @@ def test_invalid_mpint(mpint):
def test_valid_seek():
buffer = bytearray(b'buffer')
buffer = bytearray(b"buffer")
parser = OpensshParser(buffer)
parser.seek(len(buffer))
assert parser.remaining_bytes() == 0
@@ -137,7 +135,7 @@ def test_valid_seek():
def test_invalid_seek():
buffer = b'buffer'
buffer = b"buffer"
parser = OpensshParser(buffer)
with pytest.raises(ValueError):
@@ -148,5 +146,5 @@ def test_invalid_seek():
def test_writer_bytes():
buffer = bytearray(b'buffer')
buffer = bytearray(b"buffer")
assert _OpensshWriter(buffer).bytes() == buffer

View File

@@ -39,259 +39,319 @@ def cartesian_product(list1, list2):
result = []
for item1 in list1:
if not is_sequence(item1):
item1 = (item1, )
item1 = (item1,)
elif not isinstance(item1, tuple):
item1 = tuple(item1)
for item2 in list2:
if not is_sequence(item2):
item2 = (item2, )
item2 = (item2,)
elif not isinstance(item2, tuple):
item2 = tuple(item2)
result.append(item1 + item2)
return result
TEST_REMOVE_TIMEZONE = cartesian_product(TIMEZONES, [
(
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
datetime.datetime(2024, 1, 1, 0, 1, 2),
),
(
datetime.datetime(2024, 1, 1, 0, 1, 2),
datetime.datetime(2024, 1, 1, 0, 1, 2),
),
])
TEST_REMOVE_TIMEZONE = cartesian_product(
TIMEZONES,
[
(
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
datetime.datetime(2024, 1, 1, 0, 1, 2),
),
(
datetime.datetime(2024, 1, 1, 0, 1, 2),
datetime.datetime(2024, 1, 1, 0, 1, 2),
),
],
)
TEST_UTC_TIMEZONE = cartesian_product(TIMEZONES, [
(
datetime.datetime(2024, 1, 1, 0, 1, 2),
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
),
(
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
),
])
TEST_UTC_TIMEZONE = cartesian_product(
TIMEZONES,
[
(
datetime.datetime(2024, 1, 1, 0, 1, 2),
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
),
(
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
),
],
)
TEST_EPOCH_SECONDS = cartesian_product(TIMEZONES, [
(0, dict(year=1970, day=1, month=1, hour=0, minute=0, second=0, microsecond=0)),
(1E-6, dict(year=1970, day=1, month=1, hour=0, minute=0, second=0, microsecond=1)),
(1E-3, dict(year=1970, day=1, month=1, hour=0, minute=0, second=0, microsecond=1000)),
(3691.2, dict(year=1970, day=1, month=1, hour=1, minute=1, second=31, microsecond=200000)),
])
TEST_EPOCH_SECONDS = cartesian_product(
TIMEZONES,
[
(0, dict(year=1970, day=1, month=1, hour=0, minute=0, second=0, microsecond=0)),
(
1e-6,
dict(year=1970, day=1, month=1, hour=0, minute=0, second=0, microsecond=1),
),
(
1e-3,
dict(
year=1970, day=1, month=1, hour=0, minute=0, second=0, microsecond=1000
),
),
(
3691.2,
dict(
year=1970,
day=1,
month=1,
hour=1,
minute=1,
second=31,
microsecond=200000,
),
),
],
)
TEST_EPOCH_TO_SECONDS = cartesian_product(TIMEZONES, [
(datetime.datetime(1970, 1, 1, 0, 1, 2, 0), 62),
(datetime.datetime(1970, 1, 1, 0, 1, 2, 0, tzinfo=UTC), 62),
])
TEST_EPOCH_TO_SECONDS = cartesian_product(
TIMEZONES,
[
(datetime.datetime(1970, 1, 1, 0, 1, 2, 0), 62),
(datetime.datetime(1970, 1, 1, 0, 1, 2, 0, tzinfo=UTC), 62),
],
)
TEST_CONVERT_RELATIVE_TO_DATETIME = cartesian_product(TIMEZONES, [
(
'+0',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 1, 0, 0, 0),
),
(
'+1s',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
datetime.datetime(2024, 1, 1, 0, 0, 1),
),
(
'-10w20d30h40m50s',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
datetime.datetime(2023, 10, 1, 17, 19, 10),
),
(
'+0',
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
),
(
'+1s',
True,
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
datetime.datetime(2024, 1, 1, 0, 0, 1, tzinfo=UTC),
),
(
'-10w20d30h40m50s',
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2023, 10, 1, 17, 19, 10, tzinfo=UTC),
),
])
TEST_CONVERT_RELATIVE_TO_DATETIME = cartesian_product(
TIMEZONES,
[
(
"+0",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 1, 0, 0, 0),
),
(
"+1s",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
datetime.datetime(2024, 1, 1, 0, 0, 1),
),
(
"-10w20d30h40m50s",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
datetime.datetime(2023, 10, 1, 17, 19, 10),
),
(
"+0",
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
),
(
"+1s",
True,
datetime.datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC),
datetime.datetime(2024, 1, 1, 0, 0, 1, tzinfo=UTC),
),
(
"-10w20d30h40m50s",
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2023, 10, 1, 17, 19, 10, tzinfo=UTC),
),
],
)
TEST_GET_RELATIVE_TIME_OPTION = cartesian_product(TIMEZONES, [
(
'+1d2h3m4s',
'foo',
'cryptography',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 2, 3, 4),
),
(
'-1w10d24h',
'foo',
'cryptography',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2023, 12, 14, 0, 0, 0),
),
(
'20240102040506Z',
'foo',
'cryptography',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 4, 5, 6),
),
(
'202401020405Z',
'foo',
'cryptography',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 4, 5, 0),
),
(
'+1d2h3m4s',
'foo',
'cryptography',
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 2, 3, 4, tzinfo=UTC),
),
(
'-1w10d24h',
'foo',
'cryptography',
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2023, 12, 14, 0, 0, 0, tzinfo=UTC),
),
(
'20240102040506Z',
'foo',
'cryptography',
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 4, 5, 6, tzinfo=UTC),
),
(
'202401020405Z',
'foo',
'cryptography',
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 4, 5, 0, tzinfo=UTC),
),
(
'+1d2h3m4s',
'foo',
'pyopenssl',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
'20240102020304Z',
),
(
'-1w10d24h',
'foo',
'pyopenssl',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
'20231214000000Z',
),
(
'20240102040506Z',
'foo',
'pyopenssl',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
'20240102040506Z',
),
(
'202401020405Z',
'foo',
'pyopenssl',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
'202401020405Z',
),
])
TEST_GET_RELATIVE_TIME_OPTION = cartesian_product(
TIMEZONES,
[
(
"+1d2h3m4s",
"foo",
"cryptography",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 2, 3, 4),
),
(
"-1w10d24h",
"foo",
"cryptography",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2023, 12, 14, 0, 0, 0),
),
(
"20240102040506Z",
"foo",
"cryptography",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 4, 5, 6),
),
(
"202401020405Z",
"foo",
"cryptography",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 4, 5, 0),
),
(
"+1d2h3m4s",
"foo",
"cryptography",
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 2, 3, 4, tzinfo=UTC),
),
(
"-1w10d24h",
"foo",
"cryptography",
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2023, 12, 14, 0, 0, 0, tzinfo=UTC),
),
(
"20240102040506Z",
"foo",
"cryptography",
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 4, 5, 6, tzinfo=UTC),
),
(
"202401020405Z",
"foo",
"cryptography",
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 4, 5, 0, tzinfo=UTC),
),
(
"+1d2h3m4s",
"foo",
"pyopenssl",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
"20240102020304Z",
),
(
"-1w10d24h",
"foo",
"pyopenssl",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
"20231214000000Z",
),
(
"20240102040506Z",
"foo",
"pyopenssl",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
"20240102040506Z",
),
(
"202401020405Z",
"foo",
"pyopenssl",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
"202401020405Z",
),
],
)
if sys.version_info >= (3, 5):
ONE_HOUR_PLUS = datetime.timezone(datetime.timedelta(hours=1))
TEST_REMOVE_TIMEZONE.extend(cartesian_product(TIMEZONES, [
(
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=ONE_HOUR_PLUS),
datetime.datetime(2023, 12, 31, 23, 1, 2),
),
]))
TEST_UTC_TIMEZONE.extend(cartesian_product(TIMEZONES, [
(
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=ONE_HOUR_PLUS),
datetime.datetime(2023, 12, 31, 23, 1, 2, tzinfo=UTC),
),
]))
TEST_EPOCH_TO_SECONDS.extend(cartesian_product(TIMEZONES, [
(datetime.datetime(1970, 1, 1, 0, 1, 2, 0, tzinfo=ONE_HOUR_PLUS), 62 - 3600),
]))
TEST_GET_RELATIVE_TIME_OPTION.extend(cartesian_product(TIMEZONES, [
(
'20240102040506+0100',
'foo',
'cryptography',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 3, 5, 6),
),
(
'202401020405+0100',
'foo',
'cryptography',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 3, 5, 0),
),
(
'20240102040506+0100',
'foo',
'cryptography',
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 3, 5, 6, tzinfo=UTC),
),
(
'202401020405+0100',
'foo',
'cryptography',
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 3, 5, 0, tzinfo=UTC),
),
(
'20240102040506+0100',
'foo',
'pyopenssl',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
'20240102040506+0100',
),
(
'202401020405+0100',
'foo',
'pyopenssl',
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
'202401020405+0100',
),
]))
TEST_REMOVE_TIMEZONE.extend(
cartesian_product(
TIMEZONES,
[
(
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=ONE_HOUR_PLUS),
datetime.datetime(2023, 12, 31, 23, 1, 2),
),
],
)
)
TEST_UTC_TIMEZONE.extend(
cartesian_product(
TIMEZONES,
[
(
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=ONE_HOUR_PLUS),
datetime.datetime(2023, 12, 31, 23, 1, 2, tzinfo=UTC),
),
],
)
)
TEST_EPOCH_TO_SECONDS.extend(
cartesian_product(
TIMEZONES,
[
(
datetime.datetime(1970, 1, 1, 0, 1, 2, 0, tzinfo=ONE_HOUR_PLUS),
62 - 3600,
),
],
)
)
TEST_GET_RELATIVE_TIME_OPTION.extend(
cartesian_product(
TIMEZONES,
[
(
"20240102040506+0100",
"foo",
"cryptography",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 3, 5, 6),
),
(
"202401020405+0100",
"foo",
"cryptography",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 3, 5, 0),
),
(
"20240102040506+0100",
"foo",
"cryptography",
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 3, 5, 6, tzinfo=UTC),
),
(
"202401020405+0100",
"foo",
"cryptography",
True,
datetime.datetime(2024, 1, 1, 0, 0, 0),
datetime.datetime(2024, 1, 2, 3, 5, 0, tzinfo=UTC),
),
(
"20240102040506+0100",
"foo",
"pyopenssl",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
"20240102040506+0100",
),
(
"202401020405+0100",
"foo",
"pyopenssl",
False,
datetime.datetime(2024, 1, 1, 0, 0, 0),
"202401020405+0100",
),
],
)
)
@pytest.mark.parametrize("timezone, input, expected", TEST_REMOVE_TIMEZONE)
@@ -338,7 +398,7 @@ def test_epoch_seconds(timezone, seconds, timestamp):
ts_wo_tz = datetime.datetime(**timestamp)
assert seconds == get_epoch_seconds(ts_wo_tz)
timestamp_w_tz = dict(timestamp)
timestamp_w_tz['tzinfo'] = UTC
timestamp_w_tz["tzinfo"] = UTC
ts_w_tz = datetime.datetime(**timestamp_w_tz)
assert seconds == get_epoch_seconds(ts_w_tz)
output_1 = from_epoch_seconds(seconds, with_timezone=False)
@@ -353,15 +413,33 @@ def test_epoch_to_seconds(timezone, timestamp, expected_seconds):
assert expected_seconds == get_epoch_seconds(timestamp)
@pytest.mark.parametrize("timezone, relative_time_string, with_timezone, now, expected", TEST_CONVERT_RELATIVE_TO_DATETIME)
def test_convert_relative_to_datetime(timezone, relative_time_string, with_timezone, now, expected):
@pytest.mark.parametrize(
"timezone, relative_time_string, with_timezone, now, expected",
TEST_CONVERT_RELATIVE_TO_DATETIME,
)
def test_convert_relative_to_datetime(
timezone, relative_time_string, with_timezone, now, expected
):
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
output = convert_relative_to_datetime(relative_time_string, with_timezone=with_timezone, now=now)
output = convert_relative_to_datetime(
relative_time_string, with_timezone=with_timezone, now=now
)
assert expected == output
@pytest.mark.parametrize("timezone, input_string, input_name, backend, with_timezone, now, expected", TEST_GET_RELATIVE_TIME_OPTION)
def test_get_relative_time_option(timezone, input_string, input_name, backend, with_timezone, now, expected):
@pytest.mark.parametrize(
"timezone, input_string, input_name, backend, with_timezone, now, expected",
TEST_GET_RELATIVE_TIME_OPTION,
)
def test_get_relative_time_option(
timezone, input_string, input_name, backend, with_timezone, now, expected
):
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
output = get_relative_time_option(input_string, input_name, backend=backend, with_timezone=with_timezone, now=now)
output = get_relative_time_option(
input_string,
input_name,
backend=backend,
with_timezone=with_timezone,
now=now,
)
assert expected == output

View File

@@ -25,11 +25,13 @@ class DummyModule(object):
# ===== Handler & CryptHandler methods tests =====
def test_generate_luks_name(monkeypatch):
module = DummyModule()
module.params["passphrase_encoding"] = "text"
monkeypatch.setattr(luks_device.Handler, "_run_command",
lambda x, y: [0, "UUID", ""])
monkeypatch.setattr(
luks_device.Handler, "_run_command", lambda x, y: [0, "UUID", ""]
)
crypt = luks_device.CryptHandler(module)
assert crypt.generate_luks_name("/dev/dummy") == "luks-UUID"
@@ -37,8 +39,11 @@ def test_generate_luks_name(monkeypatch):
def test_get_container_name_by_device(monkeypatch):
module = DummyModule()
module.params["passphrase_encoding"] = "text"
monkeypatch.setattr(luks_device.Handler, "_run_command",
lambda x, y: [0, "crypt container_name", ""])
monkeypatch.setattr(
luks_device.Handler,
"_run_command",
lambda x, y: [0, "crypt container_name", ""],
)
crypt = luks_device.CryptHandler(module)
assert crypt.get_container_name_by_device("/dev/dummy") == "container_name"
@@ -46,8 +51,11 @@ def test_get_container_name_by_device(monkeypatch):
def test_get_container_device_by_name(monkeypatch):
module = DummyModule()
module.params["passphrase_encoding"] = "text"
monkeypatch.setattr(luks_device.Handler, "_run_command",
lambda x, y: [0, "device: /dev/luksdevice", ""])
monkeypatch.setattr(
luks_device.Handler,
"_run_command",
lambda x, y: [0, "device: /dev/luksdevice", ""],
)
crypt = luks_device.CryptHandler(module)
assert crypt.get_container_device_by_name("dummy") == "/dev/luksdevice"
@@ -60,15 +68,11 @@ def test_run_luks_remove(monkeypatch):
module = DummyModule()
module.params["passphrase_encoding"] = "text"
monkeypatch.setattr(luks_device.CryptHandler,
"get_container_name_by_device",
lambda x, y: None)
monkeypatch.setattr(luks_device.Handler,
"_run_command",
run_command_check)
monkeypatch.setattr(luks_device,
"wipe_luks_headers",
lambda device: True)
monkeypatch.setattr(
luks_device.CryptHandler, "get_container_name_by_device", lambda x, y: None
)
monkeypatch.setattr(luks_device.Handler, "_run_command", run_command_check)
monkeypatch.setattr(luks_device, "wipe_luks_headers", lambda device: True)
crypt = luks_device.CryptHandler(module)
crypt.run_luks_remove("dummy")
@@ -95,14 +99,16 @@ LUKS_CREATE_DATA = (
("dummy", None, "corge", "present", True, None, "dummy", "dummy", False),
("dummy", "key", None, "present", False, None, None, None, True),
("dummy", "key", None, "present", False, None, None, "dummy", True),
("dummy", "key", None, "present", False, None, "dummy", None, True))
("dummy", "key", None, "present", False, None, "dummy", None, True),
)
# device, state, is_luks, expected
LUKS_REMOVE_DATA = (
("dummy", "absent", True, True),
(None, "absent", True, False),
("dummy", "present", True, False),
("dummy", "absent", False, False))
("dummy", "absent", False, False),
)
# device, key, passphrase, state, name, name_by_dev, expected
LUKS_OPEN_DATA = (
@@ -121,7 +127,8 @@ LUKS_OPEN_DATA = (
(None, None, "quux", "opened", "name", None, False),
("dummy", None, None, "opened", "name", None, False),
("dummy", None, "quuz", "opened", "name", "name", False),
("dummy", None, "corge", "opened", "beer", "name", "exception"))
("dummy", None, "corge", "opened", "beer", "name", "exception"),
)
# device, dev_by_name, name, name_by_dev, state, label, expected
LUKS_CLOSE_DATA = (
@@ -131,7 +138,8 @@ LUKS_CLOSE_DATA = (
("dummy", "dummy", "name", "name", "closed", None, True),
(None, "dummy", "name", "name", "closed", None, True),
("dummy", "dummy", None, "name", "closed", None, True),
(None, "dummy", None, "name", "closed", None, False))
(None, "dummy", None, "name", "closed", None, False),
)
# device, key, passphrase, new_key, new_passphrase, state, label, expected
LUKS_ADD_KEY_DATA = (
@@ -150,7 +158,8 @@ LUKS_ADD_KEY_DATA = (
("dummy", "key", None, None, None, "present", None, False),
("dummy", "key", None, None, "new_pass", "absent", None, "exception"),
("dummy", None, "pass", None, "new_pass", "present", None, True),
(None, None, "pass", None, "new_pass", "present", "labelName", True))
(None, None, "pass", None, "new_pass", "present", "labelName", True),
)
# device, remove_key, remove_passphrase, state, label, expected
LUKS_REMOVE_KEY_DATA = (
@@ -163,15 +172,26 @@ LUKS_REMOVE_KEY_DATA = (
(None, None, "foo", None, "present", None, False),
(None, None, "foo", None, "present", "labelName", True),
("dummy", None, None, None, "present", None, False),
("dummy", None, "foo", None, "absent", None, "exception"))
("dummy", None, "foo", None, "absent", None, "exception"),
)
@pytest.mark.parametrize("device, keyfile, passphrase, state, is_luks, " +
"label, cipher, hash_, expected",
((d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8])
for d in LUKS_CREATE_DATA))
def test_luks_create(device, keyfile, passphrase, state, is_luks, label, cipher, hash_,
expected, monkeypatch):
@pytest.mark.parametrize(
"device, keyfile, passphrase, state, is_luks, " + "label, cipher, hash_, expected",
((d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8]) for d in LUKS_CREATE_DATA),
)
def test_luks_create(
device,
keyfile,
passphrase,
state,
is_luks,
label,
cipher,
hash_,
expected,
monkeypatch,
):
module = DummyModule()
module.params["device"] = device
@@ -183,12 +203,14 @@ def test_luks_create(device, keyfile, passphrase, state, is_luks, label, cipher,
module.params["cipher"] = cipher
module.params["hash"] = hash_
monkeypatch.setattr(luks_device.CryptHandler, "is_luks",
lambda x, y: is_luks)
monkeypatch.setattr(luks_device.CryptHandler, "is_luks", lambda x, y: is_luks)
crypt = luks_device.CryptHandler(module)
if device is None:
monkeypatch.setattr(luks_device.Handler, "get_device_by_label",
lambda x, y: [0, "/dev/dummy", ""])
monkeypatch.setattr(
luks_device.Handler,
"get_device_by_label",
lambda x, y: [0, "/dev/dummy", ""],
)
try:
conditions = luks_device.ConditionsHandler(module, crypt)
assert conditions.luks_create() == expected
@@ -196,9 +218,10 @@ def test_luks_create(device, keyfile, passphrase, state, is_luks, label, cipher,
assert expected == "exception"
@pytest.mark.parametrize("device, state, is_luks, expected",
((d[0], d[1], d[2], d[3])
for d in LUKS_REMOVE_DATA))
@pytest.mark.parametrize(
"device, state, is_luks, expected",
((d[0], d[1], d[2], d[3]) for d in LUKS_REMOVE_DATA),
)
def test_luks_remove(device, state, is_luks, expected, monkeypatch):
module = DummyModule()
@@ -206,8 +229,7 @@ def test_luks_remove(device, state, is_luks, expected, monkeypatch):
module.params["passphrase_encoding"] = "text"
module.params["state"] = state
monkeypatch.setattr(luks_device.CryptHandler, "is_luks",
lambda x, y: is_luks)
monkeypatch.setattr(luks_device.CryptHandler, "is_luks", lambda x, y: is_luks)
crypt = luks_device.CryptHandler(module)
try:
conditions = luks_device.ConditionsHandler(module, crypt)
@@ -216,12 +238,13 @@ def test_luks_remove(device, state, is_luks, expected, monkeypatch):
assert expected == "exception"
@pytest.mark.parametrize("device, keyfile, passphrase, state, name, "
"name_by_dev, expected",
((d[0], d[1], d[2], d[3], d[4], d[5], d[6])
for d in LUKS_OPEN_DATA))
def test_luks_open(device, keyfile, passphrase, state, name, name_by_dev,
expected, monkeypatch):
@pytest.mark.parametrize(
"device, keyfile, passphrase, state, name, name_by_dev, expected",
((d[0], d[1], d[2], d[3], d[4], d[5], d[6]) for d in LUKS_OPEN_DATA),
)
def test_luks_open(
device, keyfile, passphrase, state, name, name_by_dev, expected, monkeypatch
):
module = DummyModule()
module.params["device"] = device
module.params["keyfile"] = keyfile
@@ -230,14 +253,17 @@ def test_luks_open(device, keyfile, passphrase, state, name, name_by_dev,
module.params["state"] = state
module.params["name"] = name
monkeypatch.setattr(luks_device.CryptHandler,
"get_container_name_by_device",
lambda x, y: name_by_dev)
monkeypatch.setattr(luks_device.CryptHandler,
"get_container_device_by_name",
lambda x, y: device)
monkeypatch.setattr(luks_device.Handler, "_run_command",
lambda x, y: [0, device, ""])
monkeypatch.setattr(
luks_device.CryptHandler,
"get_container_name_by_device",
lambda x, y: name_by_dev,
)
monkeypatch.setattr(
luks_device.CryptHandler, "get_container_device_by_name", lambda x, y: device
)
monkeypatch.setattr(
luks_device.Handler, "_run_command", lambda x, y: [0, device, ""]
)
crypt = luks_device.CryptHandler(module)
try:
conditions = luks_device.ConditionsHandler(module, crypt)
@@ -246,12 +272,13 @@ def test_luks_open(device, keyfile, passphrase, state, name, name_by_dev,
assert expected == "exception"
@pytest.mark.parametrize("device, dev_by_name, name, name_by_dev, "
"state, label, expected",
((d[0], d[1], d[2], d[3], d[4], d[5], d[6])
for d in LUKS_CLOSE_DATA))
def test_luks_close(device, dev_by_name, name, name_by_dev, state,
label, expected, monkeypatch):
@pytest.mark.parametrize(
"device, dev_by_name, name, name_by_dev, state, label, expected",
((d[0], d[1], d[2], d[3], d[4], d[5], d[6]) for d in LUKS_CLOSE_DATA),
)
def test_luks_close(
device, dev_by_name, name, name_by_dev, state, label, expected, monkeypatch
):
module = DummyModule()
module.params["device"] = device
module.params["name"] = name
@@ -259,12 +286,16 @@ def test_luks_close(device, dev_by_name, name, name_by_dev, state,
module.params["state"] = state
module.params["label"] = label
monkeypatch.setattr(luks_device.CryptHandler,
"get_container_name_by_device",
lambda x, y: name_by_dev)
monkeypatch.setattr(luks_device.CryptHandler,
"get_container_device_by_name",
lambda x, y: dev_by_name)
monkeypatch.setattr(
luks_device.CryptHandler,
"get_container_name_by_device",
lambda x, y: name_by_dev,
)
monkeypatch.setattr(
luks_device.CryptHandler,
"get_container_device_by_name",
lambda x, y: dev_by_name,
)
crypt = luks_device.CryptHandler(module)
try:
conditions = luks_device.ConditionsHandler(module, crypt)
@@ -273,12 +304,22 @@ def test_luks_close(device, dev_by_name, name, name_by_dev, state,
assert expected == "exception"
@pytest.mark.parametrize("device, keyfile, passphrase, new_keyfile, " +
"new_passphrase, state, label, expected",
((d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7])
for d in LUKS_ADD_KEY_DATA))
def test_luks_add_key(device, keyfile, passphrase, new_keyfile, new_passphrase,
state, label, expected, monkeypatch):
@pytest.mark.parametrize(
"device, keyfile, passphrase, new_keyfile, "
+ "new_passphrase, state, label, expected",
((d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]) for d in LUKS_ADD_KEY_DATA),
)
def test_luks_add_key(
device,
keyfile,
passphrase,
new_keyfile,
new_passphrase,
state,
label,
expected,
monkeypatch,
):
module = DummyModule()
module.params["device"] = device
module.params["keyfile"] = keyfile
@@ -290,10 +331,12 @@ def test_luks_add_key(device, keyfile, passphrase, new_keyfile, new_passphrase,
module.params["state"] = state
module.params["label"] = label
monkeypatch.setattr(luks_device.Handler, "get_device_by_label",
lambda x, y: [0, "/dev/dummy", ""])
monkeypatch.setattr(luks_device.CryptHandler, "luks_test_key",
lambda x, y, z, w: False)
monkeypatch.setattr(
luks_device.Handler, "get_device_by_label", lambda x, y: [0, "/dev/dummy", ""]
)
monkeypatch.setattr(
luks_device.CryptHandler, "luks_test_key", lambda x, y, z, w: False
)
crypt = luks_device.CryptHandler(module)
try:
@@ -303,12 +346,21 @@ def test_luks_add_key(device, keyfile, passphrase, new_keyfile, new_passphrase,
assert expected == "exception"
@pytest.mark.parametrize("device, remove_keyfile, remove_passphrase, remove_keyslot, " +
"state, label, expected",
((d[0], d[1], d[2], d[3], d[4], d[5], d[6])
for d in LUKS_REMOVE_KEY_DATA))
def test_luks_remove_key(device, remove_keyfile, remove_passphrase, remove_keyslot, state,
label, expected, monkeypatch):
@pytest.mark.parametrize(
"device, remove_keyfile, remove_passphrase, remove_keyslot, "
+ "state, label, expected",
((d[0], d[1], d[2], d[3], d[4], d[5], d[6]) for d in LUKS_REMOVE_KEY_DATA),
)
def test_luks_remove_key(
device,
remove_keyfile,
remove_passphrase,
remove_keyslot,
state,
label,
expected,
monkeypatch,
):
module = DummyModule()
module.params["device"] = device
@@ -319,12 +371,15 @@ def test_luks_remove_key(device, remove_keyfile, remove_passphrase, remove_keysl
module.params["state"] = state
module.params["label"] = label
monkeypatch.setattr(luks_device.Handler, "get_device_by_label",
lambda x, y: [0, "/dev/dummy", ""])
monkeypatch.setattr(luks_device.Handler, "_run_command",
lambda x, y: [0, device, ""])
monkeypatch.setattr(luks_device.CryptHandler, "luks_test_key",
lambda x, y, z, w: True)
monkeypatch.setattr(
luks_device.Handler, "get_device_by_label", lambda x, y: [0, "/dev/dummy", ""]
)
monkeypatch.setattr(
luks_device.Handler, "_run_command", lambda x, y: [0, device, ""]
)
monkeypatch.setattr(
luks_device.CryptHandler, "luks_test_key", lambda x, y, z, w: True
)
crypt = luks_device.CryptHandler(module)
try: