mirror of
https://github.com/ansible-collections/community.crypto.git
synced 2026-05-06 13:22:58 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7adca3efff | ||
|
|
6731b38baa | ||
|
|
feee571bc8 | ||
|
|
21e344e283 | ||
|
|
7c93b61532 | ||
|
|
dd8b90f9d3 |
8
.github/workflows/reuse.yml
vendored
8
.github/workflows/reuse.yml
vendored
@@ -7,9 +7,13 @@ name: Verify REUSE
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
pull_request:
|
||||
branches: [main]
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
# Run CI once per day (at 04:45 UTC)
|
||||
schedule:
|
||||
- cron: '45 4 * * *'
|
||||
|
||||
475
CHANGELOG.md
475
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,20 @@ Community Crypto Release Notes
|
||||
|
||||
.. contents:: Topics
|
||||
|
||||
v2.22.3
|
||||
=======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Bugfix release.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- acme_* modules - when using the OpenSSL backend, explicitly use the UTC timezone in Python code (https://github.com/ansible-collections/community.crypto/pull/811).
|
||||
- time module utils - fix conversion of naive ``datetime`` objects to UNIX timestamps for Python 3 (https://github.com/ansible-collections/community.crypto/issues/808, https://github.com/ansible-collections/community.crypto/pull/810).
|
||||
|
||||
v2.22.2
|
||||
=======
|
||||
|
||||
|
||||
@@ -1515,3 +1515,17 @@ releases:
|
||||
- 2.22.2.yml
|
||||
- 803-fix-authorization-failure-with-mixed-case-sans.yml
|
||||
release_date: '2024-10-15'
|
||||
2.22.3:
|
||||
changes:
|
||||
bugfixes:
|
||||
- acme_* modules - when using the OpenSSL backend, explicitly use the UTC
|
||||
timezone in Python code (https://github.com/ansible-collections/community.crypto/pull/811).
|
||||
- time module utils - fix conversion of naive ``datetime`` objects to UNIX
|
||||
timestamps for Python 3 (https://github.com/ansible-collections/community.crypto/issues/808,
|
||||
https://github.com/ansible-collections/community.crypto/pull/810).
|
||||
release_summary: Bugfix release.
|
||||
fragments:
|
||||
- 2.22.3.yml
|
||||
- 810-time.yml
|
||||
- 811-openssl-timezone.yml
|
||||
release_date: '2024-10-27'
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace: community
|
||||
name: crypto
|
||||
version: 2.22.2
|
||||
version: 2.22.3
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (github.com/ansible)
|
||||
|
||||
@@ -11,7 +11,6 @@ __metaclass__ = type
|
||||
|
||||
import base64
|
||||
import binascii
|
||||
import datetime
|
||||
import os
|
||||
import traceback
|
||||
|
||||
@@ -22,7 +21,6 @@ from ansible_collections.community.crypto.plugins.module_utils.version import Lo
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.backends import (
|
||||
CertificateInformation,
|
||||
CryptoBackend,
|
||||
_parse_acme_timestamp,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.certificates import (
|
||||
@@ -38,10 +36,6 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.io import re
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.utils import nopad_b64
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
|
||||
OpenSSLObjectError,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.math import (
|
||||
convert_int_to_bytes,
|
||||
convert_int_to_hex,
|
||||
@@ -64,12 +58,7 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.support im
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
ensure_utc_timezone,
|
||||
from_epoch_seconds,
|
||||
get_epoch_seconds,
|
||||
get_now_datetime,
|
||||
get_relative_time_option,
|
||||
UTC,
|
||||
add_or_remove_timezone,
|
||||
)
|
||||
|
||||
CRYPTOGRAPHY_MINIMAL_VERSION = '1.5'
|
||||
@@ -184,33 +173,7 @@ class CryptographyChainMatcher(ChainMatcher):
|
||||
|
||||
class CryptographyBackend(CryptoBackend):
|
||||
def __init__(self, module):
|
||||
super(CryptographyBackend, self).__init__(module)
|
||||
|
||||
def get_now(self):
|
||||
return get_now_datetime(with_timezone=CRYPTOGRAPHY_TIMEZONE)
|
||||
|
||||
def parse_acme_timestamp(self, timestamp_str):
|
||||
return _parse_acme_timestamp(timestamp_str, with_timezone=CRYPTOGRAPHY_TIMEZONE)
|
||||
|
||||
def parse_module_parameter(self, value, name):
|
||||
try:
|
||||
return get_relative_time_option(value, name, backend='cryptography', with_timezone=CRYPTOGRAPHY_TIMEZONE)
|
||||
except OpenSSLObjectError as exc:
|
||||
raise BackendException(to_native(exc))
|
||||
|
||||
def interpolate_timestamp(self, timestamp_start, timestamp_end, percentage):
|
||||
start = get_epoch_seconds(timestamp_start)
|
||||
end = get_epoch_seconds(timestamp_end)
|
||||
return from_epoch_seconds(start + percentage * (end - start), with_timezone=CRYPTOGRAPHY_TIMEZONE)
|
||||
|
||||
def get_utc_datetime(self, *args, **kwargs):
|
||||
kwargs_ext = dict(kwargs)
|
||||
if CRYPTOGRAPHY_TIMEZONE and ('tzinfo' not in kwargs_ext and len(args) < 8):
|
||||
kwargs_ext['tzinfo'] = UTC
|
||||
result = datetime.datetime(*args, **kwargs_ext)
|
||||
if CRYPTOGRAPHY_TIMEZONE and ('tzinfo' in kwargs or len(args) >= 8):
|
||||
result = ensure_utc_timezone(result)
|
||||
return result
|
||||
super(CryptographyBackend, self).__init__(module, with_timezone=CRYPTOGRAPHY_TIMEZONE)
|
||||
|
||||
def parse_key(self, key_file=None, key_content=None, passphrase=None):
|
||||
'''
|
||||
@@ -419,8 +382,8 @@ class CryptographyBackend(CryptoBackend):
|
||||
|
||||
if now is None:
|
||||
now = self.get_now()
|
||||
elif CRYPTOGRAPHY_TIMEZONE:
|
||||
now = ensure_utc_timezone(now)
|
||||
else:
|
||||
now = add_or_remove_timezone(now, with_timezone=CRYPTOGRAPHY_TIMEZONE)
|
||||
return (get_not_valid_after(cert) - now).days
|
||||
|
||||
def create_chain_matcher(self, criterium):
|
||||
|
||||
@@ -33,6 +33,8 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.utils import
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.math import convert_bytes_to_int
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.time import ensure_utc_timezone
|
||||
|
||||
try:
|
||||
import ipaddress
|
||||
except ImportError:
|
||||
@@ -45,7 +47,11 @@ _OPENSSL_ENVIRONMENT_UPDATE = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTY
|
||||
def _extract_date(out_text, name, cert_filename_suffix=""):
|
||||
try:
|
||||
date_str = re.search(r"\s+%s\s*:\s+(.*)" % name, out_text).group(1)
|
||||
return datetime.datetime.strptime(date_str, '%b %d %H:%M:%S %Y %Z')
|
||||
# For some reason Python's strptime() doesn't return any timezone information,
|
||||
# even though the information is there and a supported timezone for all supported
|
||||
# Python implementations (GMT). So we have to modify the datetime object by
|
||||
# replacing it by UTC.
|
||||
return ensure_utc_timezone(datetime.datetime.strptime(date_str, '%b %d %H:%M:%S %Y %Z'))
|
||||
except AttributeError:
|
||||
raise BackendException("No '{0}' date found{1}".format(name, cert_filename_suffix))
|
||||
except ValueError as exc:
|
||||
@@ -71,7 +77,7 @@ def _extract_octets(out_text, name, required=True, potential_prefixes=None):
|
||||
|
||||
class OpenSSLCLIBackend(CryptoBackend):
|
||||
def __init__(self, module, openssl_binary=None):
|
||||
super(OpenSSLCLIBackend, self).__init__(module)
|
||||
super(OpenSSLCLIBackend, self).__init__(module, with_timezone=True)
|
||||
if openssl_binary is None:
|
||||
openssl_binary = module.get_bin_path('openssl', True)
|
||||
self.openssl_binary = openssl_binary
|
||||
@@ -340,7 +346,9 @@ class OpenSSLCLIBackend(CryptoBackend):
|
||||
out_text = to_text(out, errors='surrogate_or_strict')
|
||||
not_after = _extract_date(out_text, 'Not After', cert_filename_suffix=cert_filename_suffix)
|
||||
if now is None:
|
||||
now = datetime.datetime.now()
|
||||
now = self.get_now()
|
||||
else:
|
||||
now = ensure_utc_timezone(now)
|
||||
return (not_after - now).days
|
||||
|
||||
def create_chain_matcher(self, criterium):
|
||||
|
||||
@@ -32,6 +32,7 @@ from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
get_now_datetime,
|
||||
get_relative_time_option,
|
||||
remove_timezone,
|
||||
UTC,
|
||||
)
|
||||
|
||||
|
||||
@@ -85,31 +86,35 @@ def _parse_acme_timestamp(timestamp_str, with_timezone):
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class CryptoBackend(object):
|
||||
def __init__(self, module):
|
||||
def __init__(self, module, with_timezone=False):
|
||||
self.module = module
|
||||
self._with_timezone = with_timezone
|
||||
|
||||
def get_now(self):
|
||||
return get_now_datetime(with_timezone=False)
|
||||
return get_now_datetime(with_timezone=self._with_timezone)
|
||||
|
||||
def parse_acme_timestamp(self, timestamp_str):
|
||||
# RFC 3339 (https://www.rfc-editor.org/info/rfc3339)
|
||||
return _parse_acme_timestamp(timestamp_str, with_timezone=False)
|
||||
return _parse_acme_timestamp(timestamp_str, with_timezone=self._with_timezone)
|
||||
|
||||
def parse_module_parameter(self, value, name):
|
||||
try:
|
||||
return get_relative_time_option(value, name, backend='cryptography', with_timezone=False)
|
||||
return get_relative_time_option(value, name, backend='cryptography', with_timezone=self._with_timezone)
|
||||
except OpenSSLObjectError as exc:
|
||||
raise BackendException(to_native(exc))
|
||||
|
||||
def interpolate_timestamp(self, timestamp_start, timestamp_end, percentage):
|
||||
start = get_epoch_seconds(timestamp_start)
|
||||
end = get_epoch_seconds(timestamp_end)
|
||||
return from_epoch_seconds(start + percentage * (end - start), with_timezone=False)
|
||||
return from_epoch_seconds(start + percentage * (end - start), with_timezone=self._with_timezone)
|
||||
|
||||
def get_utc_datetime(self, *args, **kwargs):
|
||||
result = datetime.datetime(*args, **kwargs)
|
||||
if 'tzinfo' in kwargs or len(args) >= 8:
|
||||
result = remove_timezone(result)
|
||||
kwargs_ext = dict(kwargs)
|
||||
if self._with_timezone and ('tzinfo' not in kwargs_ext and len(args) < 8):
|
||||
kwargs_ext['tzinfo'] = UTC
|
||||
result = datetime.datetime(*args, **kwargs_ext)
|
||||
if self._with_timezone and ('tzinfo' in kwargs or len(args) >= 8):
|
||||
result = ensure_utc_timezone(result)
|
||||
return result
|
||||
|
||||
@abc.abstractmethod
|
||||
|
||||
@@ -83,6 +83,9 @@ if sys.version_info < (3, 3):
|
||||
return (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6
|
||||
else:
|
||||
def get_epoch_seconds(timestamp):
|
||||
if timestamp.tzinfo is None:
|
||||
# timestamp.timestamp() is offset by the local timezone if timestamp has no timezone
|
||||
timestamp = ensure_utc_timezone(timestamp)
|
||||
return timestamp.timestamp()
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.errors impor
|
||||
BackendException,
|
||||
)
|
||||
|
||||
from ..test_time import cartesian_product, TIMEZONES
|
||||
|
||||
|
||||
def load_fixture(name):
|
||||
with open(os.path.join(os.path.dirname(__file__), 'fixtures', name)) as f:
|
||||
@@ -89,11 +91,11 @@ 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 = [
|
||||
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(
|
||||
@@ -121,7 +123,7 @@ TEST_CERT_INFO = [
|
||||
]
|
||||
|
||||
|
||||
TEST_PARSE_ACME_TIMESTAMP = [
|
||||
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),
|
||||
@@ -134,10 +136,10 @@ TEST_PARSE_ACME_TIMESTAMP = [
|
||||
'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([
|
||||
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),
|
||||
@@ -146,10 +148,10 @@ if sys.version_info >= (3, 5):
|
||||
'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 = [
|
||||
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),
|
||||
@@ -168,7 +170,7 @@ TEST_INTERPOLATE_TIMESTAMP = [
|
||||
1.0,
|
||||
dict(year=2024, month=1, day=1, hour=1, minute=0, second=0),
|
||||
),
|
||||
]
|
||||
])
|
||||
|
||||
|
||||
class FakeBackend(CryptoBackend):
|
||||
|
||||
@@ -5,25 +5,27 @@
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
from freezegun import freeze_time
|
||||
|
||||
from ansible_collections.community.crypto.tests.unit.compat.mock import MagicMock
|
||||
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.backend_cryptography import (
|
||||
HAS_CURRENT_CRYPTOGRAPHY,
|
||||
CryptographyBackend,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
|
||||
ensure_utc_timezone,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
|
||||
CRYPTOGRAPHY_TIMEZONE,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
ensure_utc_timezone,
|
||||
UTC,
|
||||
)
|
||||
|
||||
from .backend_data import (
|
||||
TEST_KEYS,
|
||||
TEST_CSRS,
|
||||
@@ -34,6 +36,8 @@ from .backend_data import (
|
||||
TEST_INTERPOLATE_TIMESTAMP,
|
||||
)
|
||||
|
||||
from ..test_time import TIMEZONES
|
||||
|
||||
|
||||
if not HAS_CURRENT_CRYPTOGRAPHY:
|
||||
pytest.skip('cryptography not found')
|
||||
@@ -65,16 +69,17 @@ def test_csridentifiers_cryptography(csr, result, openssl_output, tmpdir):
|
||||
assert identifiers == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize("now, expected_days", TEST_CERT_DAYS)
|
||||
def test_certdays_cryptography(now, expected_days, tmpdir):
|
||||
fn = tmpdir / 'test-cert.pem'
|
||||
fn.write(TEST_CERT)
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
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("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.write(TEST_CERT)
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
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)
|
||||
@@ -96,28 +101,40 @@ def test_get_cert_information(cert_content, expected_cert_info, openssl_output,
|
||||
assert cert_info == expected_cert_info
|
||||
|
||||
|
||||
def test_now():
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
now = backend.get_now()
|
||||
assert CRYPTOGRAPHY_TIMEZONE == (now.tzinfo is not None)
|
||||
# @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)
|
||||
def test_now(timezone):
|
||||
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
now = backend.get_now()
|
||||
if CRYPTOGRAPHY_TIMEZONE:
|
||||
assert now.tzinfo is not None
|
||||
assert now == datetime.datetime(2024, 2, 3, 4, 5, 6, tzinfo=UTC)
|
||||
else:
|
||||
assert now.tzinfo is None
|
||||
assert now == datetime.datetime(2024, 2, 3, 4, 5, 6)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", TEST_PARSE_ACME_TIMESTAMP)
|
||||
def test_parse_acme_timestamp(input, expected):
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
ts_expected = backend.get_utc_datetime(**expected)
|
||||
timestamp = backend.parse_acme_timestamp(input)
|
||||
assert ts_expected == timestamp
|
||||
@pytest.mark.parametrize("timezone, input, expected", TEST_PARSE_ACME_TIMESTAMP)
|
||||
def test_parse_acme_timestamp(timezone, input, expected):
|
||||
with freeze_time("2024-02-03 04:05:06 +00:00", tz_offset=timezone):
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
ts_expected = backend.get_utc_datetime(**expected)
|
||||
timestamp = backend.parse_acme_timestamp(input)
|
||||
assert ts_expected == timestamp
|
||||
|
||||
|
||||
@pytest.mark.parametrize("start, end, percentage, expected", TEST_INTERPOLATE_TIMESTAMP)
|
||||
def test_interpolate_timestamp(start, end, percentage, expected):
|
||||
module = MagicMock()
|
||||
backend = CryptographyBackend(module)
|
||||
ts_start = backend.get_utc_datetime(**start)
|
||||
ts_end = backend.get_utc_datetime(**end)
|
||||
ts_expected = backend.get_utc_datetime(**expected)
|
||||
timestamp = backend.interpolate_timestamp(ts_start, ts_end, percentage)
|
||||
assert ts_expected == 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 = CryptographyBackend(module)
|
||||
ts_start = backend.get_utc_datetime(**start)
|
||||
ts_end = backend.get_utc_datetime(**end)
|
||||
ts_expected = backend.get_utc_datetime(**expected)
|
||||
timestamp = backend.interpolate_timestamp(ts_start, ts_end, percentage)
|
||||
assert ts_expected == timestamp
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
from freezegun import freeze_time
|
||||
|
||||
from ansible_collections.community.crypto.tests.unit.compat.mock import MagicMock
|
||||
|
||||
@@ -15,6 +17,11 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.backend_open
|
||||
OpenSSLCLIBackend,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
ensure_utc_timezone,
|
||||
UTC,
|
||||
)
|
||||
|
||||
from .backend_data import (
|
||||
TEST_KEYS,
|
||||
TEST_CSRS,
|
||||
@@ -26,6 +33,8 @@ from .backend_data import (
|
||||
TEST_INTERPOLATE_TIMESTAMP,
|
||||
)
|
||||
|
||||
# from ..test_time import TIMEZONES
|
||||
|
||||
|
||||
TEST_IPS = [
|
||||
("0:0:0:0:0:0:0:1", "::1"),
|
||||
@@ -69,17 +78,18 @@ def test_normalize_ip(ip, result):
|
||||
assert backend._normalize_ip(ip) == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize("now, expected_days", TEST_CERT_DAYS)
|
||||
def test_certdays_cryptography(now, expected_days, tmpdir):
|
||||
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')
|
||||
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("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.write(TEST_CERT)
|
||||
module = MagicMock()
|
||||
module.run_command = MagicMock(return_value=(0, TEST_CERT_OPENSSL_OUTPUT, 0))
|
||||
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)
|
||||
@@ -89,34 +99,48 @@ def test_get_cert_information(cert_content, expected_cert_info, openssl_output,
|
||||
module = MagicMock()
|
||||
module.run_command = MagicMock(return_value=(0, openssl_output, 0))
|
||||
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),
|
||||
not_valid_before=ensure_utc_timezone(expected_cert_info.not_valid_before),
|
||||
)
|
||||
|
||||
cert_info = backend.get_cert_information(cert_filename=str(fn))
|
||||
assert cert_info == expected_cert_info
|
||||
cert_info = backend.get_cert_information(cert_content=cert_content)
|
||||
assert cert_info == expected_cert_info
|
||||
|
||||
|
||||
def test_now():
|
||||
module = MagicMock()
|
||||
backend = OpenSSLCLIBackend(module, openssl_binary='openssl')
|
||||
now = backend.get_now()
|
||||
assert now.tzinfo is None
|
||||
# @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)])
|
||||
def test_now(timezone):
|
||||
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
|
||||
module = MagicMock()
|
||||
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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", TEST_PARSE_ACME_TIMESTAMP)
|
||||
def test_parse_acme_timestamp(input, expected):
|
||||
module = MagicMock()
|
||||
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, input, expected", TEST_PARSE_ACME_TIMESTAMP)
|
||||
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')
|
||||
ts_expected = backend.get_utc_datetime(**expected)
|
||||
timestamp = backend.parse_acme_timestamp(input)
|
||||
assert ts_expected == timestamp
|
||||
|
||||
|
||||
@pytest.mark.parametrize("start, end, percentage, expected", TEST_INTERPOLATE_TIMESTAMP)
|
||||
def test_interpolate_timestamp(start, end, percentage, expected):
|
||||
module = MagicMock()
|
||||
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)
|
||||
timestamp = backend.interpolate_timestamp(ts_start, ts_end, percentage)
|
||||
assert ts_expected == 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')
|
||||
ts_start = backend.get_utc_datetime(**start)
|
||||
ts_end = backend.get_utc_datetime(**end)
|
||||
ts_expected = backend.get_utc_datetime(**expected)
|
||||
timestamp = backend.interpolate_timestamp(ts_start, ts_end, percentage)
|
||||
assert ts_expected == timestamp
|
||||
|
||||
@@ -10,7 +10,9 @@ import datetime
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from freezegun import freeze_time
|
||||
|
||||
from ansible.module_utils.common.collections import is_sequence
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
add_or_remove_timezone,
|
||||
@@ -25,18 +27,42 @@ from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
)
|
||||
|
||||
|
||||
TEST_REMOVE_TIMEZONE = [
|
||||
(
|
||||
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),
|
||||
),
|
||||
TIMEZONES = [
|
||||
datetime.timedelta(hours=0),
|
||||
datetime.timedelta(hours=1),
|
||||
datetime.timedelta(hours=2),
|
||||
datetime.timedelta(hours=-6),
|
||||
]
|
||||
|
||||
TEST_UTC_TIMEZONE = [
|
||||
|
||||
def cartesian_product(list1, list2):
|
||||
result = []
|
||||
for item1 in list1:
|
||||
if not is_sequence(item1):
|
||||
item1 = (item1, )
|
||||
elif not isinstance(item1, tuple):
|
||||
item1 = tuple(item1)
|
||||
for item2 in list2:
|
||||
if not is_sequence(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_UTC_TIMEZONE = cartesian_product(TIMEZONES, [
|
||||
(
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2),
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
|
||||
@@ -45,21 +71,21 @@ TEST_UTC_TIMEZONE = [
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
|
||||
datetime.datetime(2024, 1, 1, 0, 1, 2, tzinfo=UTC),
|
||||
),
|
||||
]
|
||||
])
|
||||
|
||||
TEST_EPOCH_SECONDS = [
|
||||
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 = [
|
||||
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 = [
|
||||
TEST_CONVERT_RELATIVE_TO_DATETIME = cartesian_product(TIMEZONES, [
|
||||
(
|
||||
'+0',
|
||||
False,
|
||||
@@ -96,9 +122,9 @@ TEST_CONVERT_RELATIVE_TO_DATETIME = [
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
datetime.datetime(2023, 10, 1, 17, 19, 10, tzinfo=UTC),
|
||||
),
|
||||
]
|
||||
])
|
||||
|
||||
TEST_GET_RELATIVE_TIME_OPTION = [
|
||||
TEST_GET_RELATIVE_TIME_OPTION = cartesian_product(TIMEZONES, [
|
||||
(
|
||||
'+1d2h3m4s',
|
||||
'foo',
|
||||
@@ -195,28 +221,28 @@ TEST_GET_RELATIVE_TIME_OPTION = [
|
||||
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([
|
||||
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([
|
||||
]))
|
||||
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([
|
||||
]))
|
||||
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([
|
||||
]))
|
||||
TEST_GET_RELATIVE_TIME_OPTION.extend(cartesian_product(TIMEZONES, [
|
||||
(
|
||||
'20240102040506+0100',
|
||||
'foo',
|
||||
@@ -265,59 +291,77 @@ if sys.version_info >= (3, 5):
|
||||
datetime.datetime(2024, 1, 1, 0, 0, 0),
|
||||
'202401020405+0100',
|
||||
),
|
||||
])
|
||||
]))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", TEST_REMOVE_TIMEZONE)
|
||||
def test_remove_timezone(input, expected):
|
||||
output_1 = remove_timezone(input)
|
||||
assert expected == output_1
|
||||
output_2 = add_or_remove_timezone(input, with_timezone=False)
|
||||
assert expected == output_2
|
||||
@pytest.mark.parametrize("timezone, input, expected", TEST_REMOVE_TIMEZONE)
|
||||
def test_remove_timezone(timezone, input, expected):
|
||||
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
|
||||
output_1 = remove_timezone(input)
|
||||
assert expected == output_1
|
||||
output_2 = add_or_remove_timezone(input, with_timezone=False)
|
||||
assert expected == output_2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", TEST_UTC_TIMEZONE)
|
||||
def test_utc_timezone(input, expected):
|
||||
output_1 = ensure_utc_timezone(input)
|
||||
assert expected == output_1
|
||||
output_2 = add_or_remove_timezone(input, with_timezone=True)
|
||||
assert expected == output_2
|
||||
@pytest.mark.parametrize("timezone, input, expected", TEST_UTC_TIMEZONE)
|
||||
def test_utc_timezone(timezone, input, expected):
|
||||
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
|
||||
output_1 = ensure_utc_timezone(input)
|
||||
assert expected == output_1
|
||||
output_2 = add_or_remove_timezone(input, with_timezone=True)
|
||||
assert expected == output_2
|
||||
|
||||
|
||||
def test_get_now_datetime():
|
||||
output_1 = get_now_datetime(with_timezone=False)
|
||||
assert output_1.tzinfo is None
|
||||
output_2 = get_now_datetime(with_timezone=True)
|
||||
assert output_2.tzinfo is not None
|
||||
assert output_2.tzinfo == UTC
|
||||
# @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
|
||||
@pytest.mark.parametrize("timezone", [datetime.timedelta(hours=0)])
|
||||
def test_get_now_datetime_w_timezone(timezone):
|
||||
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
|
||||
output_2 = get_now_datetime(with_timezone=True)
|
||||
assert output_2.tzinfo is not None
|
||||
assert output_2.tzinfo == UTC
|
||||
assert output_2 == datetime.datetime(2024, 2, 3, 4, 5, 6, tzinfo=UTC)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("seconds, timestamp", TEST_EPOCH_SECONDS)
|
||||
def test_epoch_seconds(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
|
||||
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)
|
||||
assert ts_wo_tz == output_1
|
||||
output_2 = from_epoch_seconds(seconds, with_timezone=True)
|
||||
assert ts_w_tz == output_2
|
||||
@pytest.mark.parametrize("timezone", TIMEZONES)
|
||||
def test_get_now_datetime_wo_timezone(timezone):
|
||||
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
|
||||
output_1 = get_now_datetime(with_timezone=False)
|
||||
assert output_1.tzinfo is None
|
||||
assert output_1 == datetime.datetime(2024, 2, 3, 4, 5, 6)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("timestamp, expected_seconds", TEST_EPOCH_TO_SECONDS)
|
||||
def test_epoch_to_seconds(timestamp, expected_seconds):
|
||||
assert expected_seconds == get_epoch_seconds(timestamp)
|
||||
@pytest.mark.parametrize("timezone, seconds, timestamp", TEST_EPOCH_SECONDS)
|
||||
def test_epoch_seconds(timezone, seconds, timestamp):
|
||||
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
|
||||
ts_wo_tz = datetime.datetime(**timestamp)
|
||||
assert seconds == get_epoch_seconds(ts_wo_tz)
|
||||
timestamp_w_tz = dict(timestamp)
|
||||
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)
|
||||
assert ts_wo_tz == output_1
|
||||
output_2 = from_epoch_seconds(seconds, with_timezone=True)
|
||||
assert ts_w_tz == output_2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("relative_time_string, with_timezone, now, expected", TEST_CONVERT_RELATIVE_TO_DATETIME)
|
||||
def test_convert_relative_to_datetime(relative_time_string, with_timezone, now, expected):
|
||||
output = convert_relative_to_datetime(relative_time_string, with_timezone=with_timezone, now=now)
|
||||
assert expected == output
|
||||
@pytest.mark.parametrize("timezone, timestamp, expected_seconds", TEST_EPOCH_TO_SECONDS)
|
||||
def test_epoch_to_seconds(timezone, timestamp, expected_seconds):
|
||||
with freeze_time("2024-02-03 04:05:06", tz_offset=timezone):
|
||||
assert expected_seconds == get_epoch_seconds(timestamp)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input_string, input_name, backend, with_timezone, now, expected", TEST_GET_RELATIVE_TIME_OPTION)
|
||||
def test_get_relative_time_option(input_string, input_name, backend, with_timezone, now, expected):
|
||||
output = get_relative_time_option(input_string, input_name, backend=backend, with_timezone=with_timezone, now=now)
|
||||
assert expected == output
|
||||
@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)
|
||||
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):
|
||||
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)
|
||||
assert expected == output
|
||||
|
||||
@@ -7,5 +7,7 @@ cryptography
|
||||
idna
|
||||
ipaddress ; python_version < '3.0'
|
||||
|
||||
freezegun == 0.3.10 ; python_version < '2.7'
|
||||
freezegun ; python_version >= '2.7'
|
||||
unittest2 ; python_version < '2.7'
|
||||
importlib ; python_version < '2.7'
|
||||
|
||||
Reference in New Issue
Block a user