mirror of
https://github.com/ansible-collections/community.crypto.git
synced 2026-05-08 14:22:56 +00:00
Replace % and str.format() with f-strings (#875)
* Replace % and str.format() with f-strings. * Apply suggestions from review.
This commit is contained in:
@@ -32,9 +32,7 @@ class PrivateKeyModule:
|
|||||||
try:
|
try:
|
||||||
data = base64.b64decode(module.params["content"])
|
data = base64.b64decode(module.params["content"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Cannot decode Base64 encoded data: {e}")
|
||||||
msg="Cannot decode Base64 encoded data: {0}".format(e)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
data = to_bytes(module.params["content"])
|
data = to_bytes(module.params["content"])
|
||||||
module_backend.set_existing(data)
|
module_backend.set_existing(data)
|
||||||
|
|||||||
@@ -54,9 +54,7 @@ from ansible_collections.community.crypto.plugins.plugin_utils.gnupg import (
|
|||||||
def gpg_fingerprint(input):
|
def gpg_fingerprint(input):
|
||||||
if not isinstance(input, string_types):
|
if not isinstance(input, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The input for the community.crypto.gpg_fingerprint filter must be a string; got {type} instead".format(
|
f"The input for the community.crypto.gpg_fingerprint filter must be a string; got {type(input)} instead"
|
||||||
type=type(input)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
gpg = PluginGPGRunner()
|
gpg = PluginGPGRunner()
|
||||||
|
|||||||
@@ -292,19 +292,16 @@ def openssl_csr_info_filter(data, name_encoding="ignore"):
|
|||||||
"""Extract information from X.509 PEM certificate."""
|
"""Extract information from X.509 PEM certificate."""
|
||||||
if not isinstance(data, string_types):
|
if not isinstance(data, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The community.crypto.openssl_csr_info input must be a text type, not %s"
|
f"The community.crypto.openssl_csr_info input must be a text type, not {type(data)}"
|
||||||
% type(data)
|
|
||||||
)
|
)
|
||||||
if not isinstance(name_encoding, string_types):
|
if not isinstance(name_encoding, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The name_encoding option must be of a text type, not %s"
|
f"The name_encoding option must be of a text type, not {type(name_encoding)}"
|
||||||
% type(name_encoding)
|
|
||||||
)
|
)
|
||||||
name_encoding = to_native(name_encoding)
|
name_encoding = to_native(name_encoding)
|
||||||
if name_encoding not in ("ignore", "idna", "unicode"):
|
if name_encoding not in ("ignore", "idna", "unicode"):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
'The name_encoding option must be one of the values "ignore", "idna", or "unicode", not "%s"'
|
f'The name_encoding option must be one of the values "ignore", "idna", or "unicode", not "{name_encoding}"'
|
||||||
% name_encoding
|
|
||||||
)
|
)
|
||||||
|
|
||||||
module = FilterModuleMock({"name_encoding": name_encoding})
|
module = FilterModuleMock({"name_encoding": name_encoding})
|
||||||
|
|||||||
@@ -167,17 +167,15 @@ def openssl_privatekey_info_filter(
|
|||||||
"""Extract information from X.509 PEM certificate."""
|
"""Extract information from X.509 PEM certificate."""
|
||||||
if not isinstance(data, string_types):
|
if not isinstance(data, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The community.crypto.openssl_privatekey_info input must be a text type, not %s"
|
f"The community.crypto.openssl_privatekey_info input must be a text type, not {type(data)}"
|
||||||
% type(data)
|
|
||||||
)
|
)
|
||||||
if passphrase is not None and not isinstance(passphrase, string_types):
|
if passphrase is not None and not isinstance(passphrase, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The passphrase option must be a text type, not %s" % type(passphrase)
|
f"The passphrase option must be a text type, not {type(passphrase)}"
|
||||||
)
|
)
|
||||||
if not isinstance(return_private_key_data, bool):
|
if not isinstance(return_private_key_data, bool):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The return_private_key_data option must be a boolean, not %s"
|
f"The return_private_key_data option must be a boolean, not {type(return_private_key_data)}"
|
||||||
% type(return_private_key_data)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
module = FilterModuleMock({})
|
module = FilterModuleMock({})
|
||||||
|
|||||||
@@ -142,8 +142,7 @@ def openssl_publickey_info_filter(data):
|
|||||||
"""Extract information from OpenSSL PEM public key."""
|
"""Extract information from OpenSSL PEM public key."""
|
||||||
if not isinstance(data, string_types):
|
if not isinstance(data, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The community.crypto.openssl_publickey_info input must be a text type, not %s"
|
f"The community.crypto.openssl_publickey_info input must be a text type, not {type(data)}"
|
||||||
% type(data)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
module = FilterModuleMock({})
|
module = FilterModuleMock({})
|
||||||
|
|||||||
@@ -50,9 +50,7 @@ from ansible_collections.community.crypto.plugins.module_utils.serial import (
|
|||||||
def parse_serial_filter(input):
|
def parse_serial_filter(input):
|
||||||
if not isinstance(input, string_types):
|
if not isinstance(input, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The input for the community.crypto.parse_serial filter must be a string; got {type} instead".format(
|
f"The input for the community.crypto.parse_serial filter must be a string; got {type(input)} instead"
|
||||||
type=type(input)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
return parse_serial(to_native(input))
|
return parse_serial(to_native(input))
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ def split_pem_filter(data):
|
|||||||
"""Split PEM file."""
|
"""Split PEM file."""
|
||||||
if not isinstance(data, string_types):
|
if not isinstance(data, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The community.crypto.split_pem input must be a text type, not %s"
|
f"The community.crypto.split_pem input must be a text type, not {type(data)}"
|
||||||
% type(data)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
data = to_text(data)
|
data = to_text(data)
|
||||||
|
|||||||
@@ -48,9 +48,7 @@ from ansible_collections.community.crypto.plugins.module_utils.serial import to_
|
|||||||
def to_serial_filter(input):
|
def to_serial_filter(input):
|
||||||
if not isinstance(input, integer_types):
|
if not isinstance(input, integer_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The input for the community.crypto.to_serial filter must be an integer; got {type} instead".format(
|
f"The input for the community.crypto.to_serial filter must be an integer; got {type(input)} instead"
|
||||||
type=type(input)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if input < 0:
|
if input < 0:
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
|
|||||||
@@ -326,19 +326,16 @@ def x509_certificate_info_filter(data, name_encoding="ignore"):
|
|||||||
"""Extract information from X.509 PEM certificate."""
|
"""Extract information from X.509 PEM certificate."""
|
||||||
if not isinstance(data, string_types):
|
if not isinstance(data, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The community.crypto.x509_certificate_info input must be a text type, not %s"
|
f"The community.crypto.x509_certificate_info input must be a text type, not {type(data)}"
|
||||||
% type(data)
|
|
||||||
)
|
)
|
||||||
if not isinstance(name_encoding, string_types):
|
if not isinstance(name_encoding, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The name_encoding option must be of a text type, not %s"
|
f"The name_encoding option must be of a text type, not {type(name_encoding)}"
|
||||||
% type(name_encoding)
|
|
||||||
)
|
)
|
||||||
name_encoding = to_native(name_encoding)
|
name_encoding = to_native(name_encoding)
|
||||||
if name_encoding not in ("ignore", "idna", "unicode"):
|
if name_encoding not in ("ignore", "idna", "unicode"):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
'The name_encoding option must be one of the values "ignore", "idna", or "unicode", not "%s"'
|
f'The name_encoding option must be one of the values "ignore", "idna", or "unicode", not "{name_encoding}"'
|
||||||
% name_encoding
|
|
||||||
)
|
)
|
||||||
|
|
||||||
module = FilterModuleMock({"name_encoding": name_encoding})
|
module = FilterModuleMock({"name_encoding": name_encoding})
|
||||||
|
|||||||
@@ -177,24 +177,20 @@ def x509_crl_info_filter(data, name_encoding="ignore", list_revoked_certificates
|
|||||||
"""Extract information from X.509 PEM certificate."""
|
"""Extract information from X.509 PEM certificate."""
|
||||||
if not isinstance(data, string_types):
|
if not isinstance(data, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The community.crypto.x509_crl_info input must be a text type, not %s"
|
f"The community.crypto.x509_crl_info input must be a text type, not {type(data)}"
|
||||||
% type(data)
|
|
||||||
)
|
)
|
||||||
if not isinstance(name_encoding, string_types):
|
if not isinstance(name_encoding, string_types):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The name_encoding option must be of a text type, not %s"
|
f"The name_encoding option must be of a text type, not {type(name_encoding)}"
|
||||||
% type(name_encoding)
|
|
||||||
)
|
)
|
||||||
if not isinstance(list_revoked_certificates, bool):
|
if not isinstance(list_revoked_certificates, bool):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
"The list_revoked_certificates option must be a boolean, not %s"
|
f"The list_revoked_certificates option must be a boolean, not {type(list_revoked_certificates)}"
|
||||||
% type(list_revoked_certificates)
|
|
||||||
)
|
)
|
||||||
name_encoding = to_native(name_encoding)
|
name_encoding = to_native(name_encoding)
|
||||||
if name_encoding not in ("ignore", "idna", "unicode"):
|
if name_encoding not in ("ignore", "idna", "unicode"):
|
||||||
raise AnsibleFilterError(
|
raise AnsibleFilterError(
|
||||||
'The name_encoding option must be one of the values "ignore", "idna", or "unicode", not "%s"'
|
f'The name_encoding option must be one of the values "ignore", "idna", or "unicode", not "{name_encoding}"'
|
||||||
% name_encoding
|
|
||||||
)
|
)
|
||||||
|
|
||||||
data = to_bytes(data)
|
data = to_bytes(data)
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ def _decode_retry(module, response, info, retry_count):
|
|||||||
if retry_count >= RETRY_COUNT:
|
if retry_count >= RETRY_COUNT:
|
||||||
raise ACMEProtocolException(
|
raise ACMEProtocolException(
|
||||||
module,
|
module,
|
||||||
msg="Giving up after {retry} retries".format(retry=RETRY_COUNT),
|
msg=f"Giving up after {RETRY_COUNT} retries",
|
||||||
info=info,
|
info=info,
|
||||||
response=response,
|
response=response,
|
||||||
)
|
)
|
||||||
@@ -77,8 +77,7 @@ def _decode_retry(module, response, info, retry_count):
|
|||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
retry_after = 10
|
retry_after = 10
|
||||||
module.log(
|
module.log(
|
||||||
"Retrieved a %s HTTP status on %s, retrying in %s seconds"
|
f"Retrieved a {format_http_status(info['status'])} HTTP status on {info['url']}, retrying in {retry_after} seconds"
|
||||||
% (format_http_status(info["status"]), info["url"], retry_after)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
time.sleep(retry_after)
|
time.sleep(retry_after)
|
||||||
@@ -94,9 +93,7 @@ def _assert_fetch_url_success(
|
|||||||
allow_server_error=True,
|
allow_server_error=True,
|
||||||
):
|
):
|
||||||
if info["status"] < 0:
|
if info["status"] < 0:
|
||||||
raise NetworkException(
|
raise NetworkException(msg=f"Failure downloading {info['url']}, {info['msg']}")
|
||||||
msg="Failure downloading %s, %s" % (info["url"], info["msg"])
|
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(300 <= info["status"] < 400 and not allow_redirect)
|
(300 <= info["status"] < 400 and not allow_redirect)
|
||||||
@@ -169,16 +166,12 @@ class ACMEDirectory:
|
|||||||
continue
|
continue
|
||||||
if info["status"] not in (200, 204):
|
if info["status"] not in (200, 204):
|
||||||
raise NetworkException(
|
raise NetworkException(
|
||||||
"Failed to get replay-nonce, got status {0}".format(
|
f"Failed to get replay-nonce, got status {format_http_status(info['status'])}"
|
||||||
format_http_status(info["status"])
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if "replay-nonce" in info:
|
if "replay-nonce" in info:
|
||||||
return info["replay-nonce"]
|
return info["replay-nonce"]
|
||||||
self.module.log(
|
self.module.log(
|
||||||
"HEAD to {0} did return status {1}, but no replay-nonce header!".format(
|
f"HEAD to {url} did return status {format_http_status(info['status'])}, but no replay-nonce header!"
|
||||||
url, format_http_status(info["status"])
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if retry_count >= 5:
|
if retry_count >= 5:
|
||||||
raise ACMEProtocolException(
|
raise ACMEProtocolException(
|
||||||
@@ -228,9 +221,7 @@ class ACMEClient:
|
|||||||
passphrase=self.account_key_passphrase,
|
passphrase=self.account_key_passphrase,
|
||||||
)
|
)
|
||||||
except KeyParsingError as e:
|
except KeyParsingError as e:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(f"Error while parsing account key: {e.msg}")
|
||||||
"Error while parsing account key: {msg}".format(msg=e.msg)
|
|
||||||
)
|
|
||||||
self.account_jwk = self.account_key_data["jwk"]
|
self.account_jwk = self.account_key_data["jwk"]
|
||||||
self.account_jws_header = {
|
self.account_jws_header = {
|
||||||
"alg": self.account_key_data["alg"],
|
"alg": self.account_key_data["alg"],
|
||||||
@@ -276,7 +267,7 @@ class ACMEClient:
|
|||||||
protected64 = nopad_b64(self.module.jsonify(protected).encode("utf8"))
|
protected64 = nopad_b64(self.module.jsonify(protected).encode("utf8"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"Failed to encode payload / headers as JSON: {0}".format(e)
|
f"Failed to encode payload / headers as JSON: {e}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return self.backend.sign(payload64, protected64, key_data)
|
return self.backend.sign(payload64, protected64, key_data)
|
||||||
@@ -287,16 +278,13 @@ class ACMEClient:
|
|||||||
"""
|
"""
|
||||||
if self._debug:
|
if self._debug:
|
||||||
with open("acme.log", "ab") as f:
|
with open("acme.log", "ab") as f:
|
||||||
f.write(
|
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%s")
|
||||||
"[{0}] {1}\n".format(
|
f.write(f"[{timestamp}] {msg}\n".encode("utf-8"))
|
||||||
datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%s"), msg
|
|
||||||
).encode("utf-8")
|
|
||||||
)
|
|
||||||
if data is not None:
|
if data is not None:
|
||||||
f.write(
|
f.write(
|
||||||
"{0}\n\n".format(
|
f"{json.dumps(data, indent=2, sort_keys=True)}\n\n".encode(
|
||||||
json.dumps(data, indent=2, sort_keys=True)
|
"utf-8"
|
||||||
).encode("utf-8")
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def send_signed_request(
|
def send_signed_request(
|
||||||
@@ -389,9 +377,7 @@ class ACMEClient:
|
|||||||
result = content
|
result = content
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise NetworkException(
|
raise NetworkException(
|
||||||
"Failed to parse the ACME response: {0} {1}".format(
|
f"Failed to parse the ACME response: {url} {content}"
|
||||||
url, content
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
result = content
|
result = content
|
||||||
@@ -471,9 +457,7 @@ class ACMEClient:
|
|||||||
parsed_json_result = True
|
parsed_json_result = True
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise NetworkException(
|
raise NetworkException(
|
||||||
"Failed to parse the ACME response: {0} {1}".format(
|
f"Failed to parse the ACME response: {uri} {content}"
|
||||||
uri, content
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
result = content
|
result = content
|
||||||
@@ -513,9 +497,7 @@ class ACMEClient:
|
|||||||
cert_filename=cert_filename,
|
cert_filename=cert_filename,
|
||||||
cert_content=cert_content,
|
cert_content=cert_content,
|
||||||
)
|
)
|
||||||
url = "{base}/{cert_id}".format(
|
url = f"{self.directory.directory['renewalInfo'].rstrip('/')}/{cert_id}"
|
||||||
base=self.directory.directory["renewalInfo"].rstrip("/"), cert_id=cert_id
|
|
||||||
)
|
|
||||||
|
|
||||||
data, info = self.get_request(
|
data, info = self.get_request(
|
||||||
url, parse_json_result=True, fail_on_error=True, get_only=True
|
url, parse_json_result=True, fail_on_error=True, get_only=True
|
||||||
@@ -593,31 +575,25 @@ def create_backend(module, needs_acme_v2=True):
|
|||||||
if CRYPTOGRAPHY_VERSION is None:
|
if CRYPTOGRAPHY_VERSION is None:
|
||||||
msg = missing_required_lib("cryptography")
|
msg = missing_required_lib("cryptography")
|
||||||
else:
|
else:
|
||||||
msg = "Unexpected error while preparing cryptography: {0}".format(
|
msg = f"Unexpected error while preparing cryptography: {CRYPTOGRAPHY_ERROR.splitlines()[-1]}"
|
||||||
CRYPTOGRAPHY_ERROR.splitlines()[-1]
|
|
||||||
)
|
|
||||||
module.fail_json(msg=msg, exception=CRYPTOGRAPHY_ERROR)
|
module.fail_json(msg=msg, exception=CRYPTOGRAPHY_ERROR)
|
||||||
if not HAS_CURRENT_CRYPTOGRAPHY:
|
if not HAS_CURRENT_CRYPTOGRAPHY:
|
||||||
# We succeeded importing cryptography, but its version is too old.
|
# We succeeded importing cryptography, but its version is too old.
|
||||||
|
mrl = missing_required_lib(
|
||||||
|
f"cryptography >= {CRYPTOGRAPHY_MINIMAL_VERSION}"
|
||||||
|
)
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Found cryptography, but only version {0}. {1}".format(
|
msg=f"Found cryptography, but only version {CRYPTOGRAPHY_VERSION}. {mrl}"
|
||||||
CRYPTOGRAPHY_VERSION,
|
|
||||||
missing_required_lib(
|
|
||||||
"cryptography >= {0}".format(CRYPTOGRAPHY_MINIMAL_VERSION)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
module.debug(
|
module.debug(
|
||||||
"Using cryptography backend (library version {0})".format(
|
f"Using cryptography backend (library version {CRYPTOGRAPHY_VERSION})"
|
||||||
CRYPTOGRAPHY_VERSION
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
module_backend = CryptographyBackend(module)
|
module_backend = CryptographyBackend(module)
|
||||||
elif backend == "openssl":
|
elif backend == "openssl":
|
||||||
module.debug("Using OpenSSL binary backend")
|
module.debug("Using OpenSSL binary backend")
|
||||||
module_backend = OpenSSLCLIBackend(module)
|
module_backend = OpenSSLCLIBackend(module)
|
||||||
else:
|
else:
|
||||||
module.fail_json(msg='Unknown crypto backend "{0}"!'.format(backend))
|
module.fail_json(msg=f'Unknown crypto backend "{backend}"!')
|
||||||
|
|
||||||
# Check common module parameters
|
# Check common module parameters
|
||||||
if not module.params["validate_certs"]:
|
if not module.params["validate_certs"]:
|
||||||
|
|||||||
@@ -91,14 +91,12 @@ class CryptographyChainMatcher(ChainMatcher):
|
|||||||
except Exception:
|
except Exception:
|
||||||
if criterium_idx is None:
|
if criterium_idx is None:
|
||||||
module.warn(
|
module.warn(
|
||||||
"Criterium has invalid {0} value. Ignoring criterium.".format(
|
f"Criterium has invalid {name} value. Ignoring criterium."
|
||||||
name
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
module.warn(
|
module.warn(
|
||||||
"Criterium {0} in select_chain has invalid {1} value. "
|
f"Criterium {criterium_idx} in select_chain has invalid {name} value. "
|
||||||
"Ignoring criterium.".format(criterium_idx, name)
|
"Ignoring criterium."
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -181,9 +179,7 @@ class CryptographyChainMatcher(ChainMatcher):
|
|||||||
if matches:
|
if matches:
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.module.warn(
|
self.module.warn(f"Error while loading certificate {cert}: {e}")
|
||||||
"Error while loading certificate {0}: {1}".format(cert, e)
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@@ -211,7 +207,7 @@ class CryptographyBackend(CryptoBackend):
|
|||||||
backend=_cryptography_backend,
|
backend=_cryptography_backend,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise KeyParsingError("error while loading key: {0}".format(e))
|
raise KeyParsingError(f"error while loading key: {e}")
|
||||||
if isinstance(key, cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey):
|
if isinstance(key, cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey):
|
||||||
pk = key.public_key().public_numbers()
|
pk = key.public_key().public_numbers()
|
||||||
return {
|
return {
|
||||||
@@ -250,9 +246,7 @@ class CryptographyBackend(CryptoBackend):
|
|||||||
point_size = 66
|
point_size = 66
|
||||||
curve = "P-521"
|
curve = "P-521"
|
||||||
else:
|
else:
|
||||||
raise KeyParsingError(
|
raise KeyParsingError(f"unknown elliptic curve: {pk.curve.name}")
|
||||||
"unknown elliptic curve: {0}".format(pk.curve.name)
|
|
||||||
)
|
|
||||||
num_bytes = (bits + 7) // 8
|
num_bytes = (bits + 7) // 8
|
||||||
return {
|
return {
|
||||||
"key_obj": key,
|
"key_obj": key,
|
||||||
@@ -268,10 +262,10 @@ class CryptographyBackend(CryptoBackend):
|
|||||||
"point_size": point_size,
|
"point_size": point_size,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
raise KeyParsingError('unknown key type "{0}"'.format(type(key)))
|
raise KeyParsingError(f'unknown key type "{type(key)}"')
|
||||||
|
|
||||||
def sign(self, payload64, protected64, key_data):
|
def sign(self, payload64, protected64, key_data):
|
||||||
sign_payload = "{0}.{1}".format(protected64, payload64).encode("utf8")
|
sign_payload = f"{protected64}.{payload64}".encode("utf8")
|
||||||
if "mac_obj" in key_data:
|
if "mac_obj" in key_data:
|
||||||
mac = key_data["mac_obj"]()
|
mac = key_data["mac_obj"]()
|
||||||
mac.update(sign_payload)
|
mac.update(sign_payload)
|
||||||
@@ -320,16 +314,12 @@ class CryptographyBackend(CryptoBackend):
|
|||||||
hashbytes = 64
|
hashbytes = 64
|
||||||
else:
|
else:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"Unsupported MAC key algorithm for cryptography backend: {0}".format(
|
f"Unsupported MAC key algorithm for cryptography backend: {alg}"
|
||||||
alg
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
key_bytes = base64.urlsafe_b64decode(key)
|
key_bytes = base64.urlsafe_b64decode(key)
|
||||||
if len(key_bytes) < hashbytes:
|
if len(key_bytes) < hashbytes:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"{0} key must be at least {1} bytes long (after Base64 decoding)".format(
|
f"{alg} key must be at least {hashbytes} bytes long (after Base64 decoding)"
|
||||||
alg, hashbytes
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"mac_obj": lambda: cryptography.hazmat.primitives.hmac.HMAC(
|
"mac_obj": lambda: cryptography.hazmat.primitives.hmac.HMAC(
|
||||||
@@ -382,7 +372,7 @@ class CryptographyBackend(CryptoBackend):
|
|||||||
add_identifier(("ip", name.value.compressed))
|
add_identifier(("ip", name.value.compressed))
|
||||||
else:
|
else:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"Found unsupported SAN identifier {0}".format(name)
|
f"Found unsupported SAN identifier {name}"
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -425,10 +415,8 @@ class CryptographyBackend(CryptoBackend):
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if cert_filename is None:
|
if cert_filename is None:
|
||||||
raise BackendException("Cannot parse certificate: {0}".format(e))
|
raise BackendException(f"Cannot parse certificate: {e}")
|
||||||
raise BackendException(
|
raise BackendException(f"Cannot parse certificate {cert_filename}: {e}")
|
||||||
"Cannot parse certificate {0}: {1}".format(cert_filename, e)
|
|
||||||
)
|
|
||||||
|
|
||||||
if now is None:
|
if now is None:
|
||||||
now = self.get_now()
|
now = self.get_now()
|
||||||
@@ -460,10 +448,8 @@ class CryptographyBackend(CryptoBackend):
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if cert_filename is None:
|
if cert_filename is None:
|
||||||
raise BackendException("Cannot parse certificate: {0}".format(e))
|
raise BackendException(f"Cannot parse certificate: {e}")
|
||||||
raise BackendException(
|
raise BackendException(f"Cannot parse certificate {cert_filename}: {e}")
|
||||||
"Cannot parse certificate {0}: {1}".format(cert_filename, e)
|
|
||||||
)
|
|
||||||
|
|
||||||
ski = None
|
ski = None
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ _OPENSSL_ENVIRONMENT_UPDATE = dict(LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTY
|
|||||||
|
|
||||||
def _extract_date(out_text, name, cert_filename_suffix=""):
|
def _extract_date(out_text, name, cert_filename_suffix=""):
|
||||||
try:
|
try:
|
||||||
date_str = re.search(r"\s+%s\s*:\s+(.*)" % name, out_text).group(1)
|
date_str = re.search(rf"\s+{name}\s*:\s+(.*)", out_text).group(1)
|
||||||
# For some reason Python's strptime() does not return any timezone information,
|
# For some reason Python's strptime() does not return any timezone information,
|
||||||
# even though the information is there and a supported timezone for all supported
|
# 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
|
# Python implementations (GMT). So we have to modify the datetime object by
|
||||||
@@ -53,12 +53,10 @@ def _extract_date(out_text, name, cert_filename_suffix=""):
|
|||||||
datetime.datetime.strptime(date_str, "%b %d %H:%M:%S %Y %Z")
|
datetime.datetime.strptime(date_str, "%b %d %H:%M:%S %Y %Z")
|
||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise BackendException(
|
raise BackendException(f"No '{name}' date found{cert_filename_suffix}")
|
||||||
"No '{0}' date found{1}".format(name, cert_filename_suffix)
|
|
||||||
)
|
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"Failed to parse '{0}' date{1}: {2}".format(name, cert_filename_suffix, exc)
|
f"Failed to parse '{name}' date{cert_filename_suffix}: {exc}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -67,20 +65,18 @@ def _decode_octets(octets_text):
|
|||||||
|
|
||||||
|
|
||||||
def _extract_octets(out_text, name, required=True, potential_prefixes=None):
|
def _extract_octets(out_text, name, required=True, potential_prefixes=None):
|
||||||
regexp = r"\s+%s:\s*\n\s+%s([A-Fa-f0-9]{2}(?::[A-Fa-f0-9]{2})*)\s*\n" % (
|
part = (
|
||||||
name,
|
f"(?:{'|'.join(re.escape(pp) for pp in potential_prefixes)})"
|
||||||
(
|
if potential_prefixes
|
||||||
("(?:%s)" % "|".join(re.escape(pp) for pp in potential_prefixes))
|
else ""
|
||||||
if potential_prefixes
|
|
||||||
else ""
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
regexp = rf"\s+{name}:\s*\n\s+{part}([A-Fa-f0-9]{{2}}(?::[A-Fa-f0-9]{{2}})*)\s*\n"
|
||||||
match = re.search(regexp, out_text, re.MULTILINE | re.DOTALL)
|
match = re.search(regexp, out_text, re.MULTILINE | re.DOTALL)
|
||||||
if match is not None:
|
if match is not None:
|
||||||
return _decode_octets(match.group(1))
|
return _decode_octets(match.group(1))
|
||||||
if not required:
|
if not required:
|
||||||
return None
|
return None
|
||||||
raise BackendException("No '{0}' octet string found".format(name))
|
raise BackendException(f"No '{name}' octet string found")
|
||||||
|
|
||||||
|
|
||||||
class OpenSSLCLIBackend(CryptoBackend):
|
class OpenSSLCLIBackend(CryptoBackend):
|
||||||
@@ -111,7 +107,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
raise KeyParsingError(
|
raise KeyParsingError(
|
||||||
"failed to create temporary content file: %s" % to_native(err),
|
f"failed to create temporary content file: {err}",
|
||||||
exception=traceback.format_exc(),
|
exception=traceback.format_exc(),
|
||||||
)
|
)
|
||||||
f.close()
|
f.close()
|
||||||
@@ -132,7 +128,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
# FIXME: add some kind of auto-detection
|
# FIXME: add some kind of auto-detection
|
||||||
account_key_type = "rsa"
|
account_key_type = "rsa"
|
||||||
if account_key_type not in ("rsa", "ec"):
|
if account_key_type not in ("rsa", "ec"):
|
||||||
raise KeyParsingError('unknown key type "%s"' % account_key_type)
|
raise KeyParsingError(f'unknown key type "{account_key_type}"')
|
||||||
|
|
||||||
openssl_keydump_cmd = [
|
openssl_keydump_cmd = [
|
||||||
self.openssl_binary,
|
self.openssl_binary,
|
||||||
@@ -149,9 +145,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"Error while running {cmd}: {stderr}".format(
|
f"Error while running {' '.join(openssl_keydump_cmd)}: {to_text(err)}"
|
||||||
cmd=" ".join(openssl_keydump_cmd), stderr=to_text(err)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
out_text = to_text(out, errors="surrogate_or_strict")
|
out_text = to_text(out, errors="surrogate_or_strict")
|
||||||
@@ -166,9 +160,9 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
pub_exp = re.search(
|
pub_exp = re.search(
|
||||||
r"\npublicExponent: ([0-9]+)", out_text, re.MULTILINE | re.DOTALL
|
r"\npublicExponent: ([0-9]+)", out_text, re.MULTILINE | re.DOTALL
|
||||||
).group(1)
|
).group(1)
|
||||||
pub_exp = "{0:x}".format(int(pub_exp))
|
pub_exp = f"{int(pub_exp):x}"
|
||||||
if len(pub_exp) % 2:
|
if len(pub_exp) % 2:
|
||||||
pub_exp = "0{0}".format(pub_exp)
|
pub_exp = f"0{pub_exp}"
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"key_file": key_file,
|
"key_file": key_file,
|
||||||
@@ -214,12 +208,12 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
curve = "P-521"
|
curve = "P-521"
|
||||||
else:
|
else:
|
||||||
raise KeyParsingError(
|
raise KeyParsingError(
|
||||||
"unknown elliptic curve: %s / %s" % (asn1_oid_curve, nist_curve)
|
f"unknown elliptic curve: {asn1_oid_curve} / {nist_curve}"
|
||||||
)
|
)
|
||||||
num_bytes = (bits + 7) // 8
|
num_bytes = (bits + 7) // 8
|
||||||
if len(pub_hex) != 2 * num_bytes:
|
if len(pub_hex) != 2 * num_bytes:
|
||||||
raise KeyParsingError(
|
raise KeyParsingError(
|
||||||
"bad elliptic curve point (%s / %s)" % (asn1_oid_curve, nist_curve)
|
f"bad elliptic curve point ({asn1_oid_curve} / {nist_curve})"
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"key_file": key_file,
|
"key_file": key_file,
|
||||||
@@ -236,7 +230,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def sign(self, payload64, protected64, key_data):
|
def sign(self, payload64, protected64, key_data):
|
||||||
sign_payload = "{0}.{1}".format(protected64, payload64).encode("utf8")
|
sign_payload = f"{protected64}.{payload64}".encode("utf8")
|
||||||
if key_data["type"] == "hmac":
|
if key_data["type"] == "hmac":
|
||||||
hex_key = to_native(
|
hex_key = to_native(
|
||||||
binascii.hexlify(base64.urlsafe_b64decode(key_data["jwk"]["k"]))
|
binascii.hexlify(base64.urlsafe_b64decode(key_data["jwk"]["k"]))
|
||||||
@@ -245,7 +239,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
"-mac",
|
"-mac",
|
||||||
"hmac",
|
"hmac",
|
||||||
"-macopt",
|
"-macopt",
|
||||||
"hexkey:{0}".format(hex_key),
|
f"hexkey:{hex_key}",
|
||||||
"-binary",
|
"-binary",
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
@@ -253,7 +247,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
openssl_sign_cmd = [
|
openssl_sign_cmd = [
|
||||||
self.openssl_binary,
|
self.openssl_binary,
|
||||||
"dgst",
|
"dgst",
|
||||||
"-{0}".format(key_data["hash"]),
|
f"-{key_data['hash']}",
|
||||||
] + cmd_postfix
|
] + cmd_postfix
|
||||||
|
|
||||||
rc, out, err = self.module.run_command(
|
rc, out, err = self.module.run_command(
|
||||||
@@ -265,9 +259,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"Error while running {cmd}: {stderr}".format(
|
f"Error while running {' '.join(openssl_sign_cmd)}: {to_text(err)}"
|
||||||
cmd=" ".join(openssl_sign_cmd), stderr=to_text(err)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if key_data["type"] == "ec":
|
if key_data["type"] == "ec":
|
||||||
@@ -279,14 +271,13 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
)
|
)
|
||||||
expected_len = 2 * key_data["point_size"]
|
expected_len = 2 * key_data["point_size"]
|
||||||
sig = re.findall(
|
sig = re.findall(
|
||||||
r"prim:\s+INTEGER\s+:([0-9A-F]{1,%s})\n" % expected_len,
|
rf"prim:\s+INTEGER\s+:([0-9A-F]{{1,{expected_len}}})\n",
|
||||||
to_text(der_out, errors="surrogate_or_strict"),
|
to_text(der_out, errors="surrogate_or_strict"),
|
||||||
)
|
)
|
||||||
if len(sig) != 2:
|
if len(sig) != 2:
|
||||||
|
der_output = to_text(der_out, errors="surrogate_or_strict")
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"failed to generate Elliptic Curve signature; cannot parse DER output: {0}".format(
|
f"failed to generate Elliptic Curve signature; cannot parse DER output: {der_output}"
|
||||||
to_text(der_out, errors="surrogate_or_strict")
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
sig[0] = (expected_len - len(sig[0])) * "0" + sig[0]
|
sig[0] = (expected_len - len(sig[0])) * "0" + sig[0]
|
||||||
sig[1] = (expected_len - len(sig[1])) * "0" + sig[1]
|
sig[1] = (expected_len - len(sig[1])) * "0" + sig[1]
|
||||||
@@ -311,14 +302,12 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
hashbytes = 64
|
hashbytes = 64
|
||||||
else:
|
else:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"Unsupported MAC key algorithm for OpenSSL backend: {0}".format(alg)
|
f"Unsupported MAC key algorithm for OpenSSL backend: {alg}"
|
||||||
)
|
)
|
||||||
key_bytes = base64.urlsafe_b64decode(key)
|
key_bytes = base64.urlsafe_b64decode(key)
|
||||||
if len(key_bytes) < hashbytes:
|
if len(key_bytes) < hashbytes:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"{0} key must be at least {1} bytes long (after Base64 decoding)".format(
|
f"{alg} key must be at least {hashbytes} bytes long (after Base64 decoding)"
|
||||||
alg, hashbytes
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"type": "hmac",
|
"type": "hmac",
|
||||||
@@ -370,9 +359,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"Error while running {cmd}: {stderr}".format(
|
f"Error while running {' '.join(openssl_csr_cmd)}: {to_text(err)}"
|
||||||
cmd=" ".join(openssl_csr_cmd), stderr=to_text(err)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
identifiers = set()
|
identifiers = set()
|
||||||
@@ -404,9 +391,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
elif san.lower().startswith("ip address:"):
|
elif san.lower().startswith("ip address:"):
|
||||||
add_identifier(("ip", self._normalize_ip(san[11:])))
|
add_identifier(("ip", self._normalize_ip(san[11:])))
|
||||||
else:
|
else:
|
||||||
raise BackendException(
|
raise BackendException(f'Found unsupported SAN identifier "{san}"')
|
||||||
'Found unsupported SAN identifier "{0}"'.format(san)
|
|
||||||
)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_csr_identifiers(self, csr_filename=None, csr_content=None):
|
def get_csr_identifiers(self, csr_filename=None, csr_content=None):
|
||||||
@@ -438,7 +423,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
elif cert_filename is not None:
|
elif cert_filename is not None:
|
||||||
if not os.path.exists(cert_filename):
|
if not os.path.exists(cert_filename):
|
||||||
return -1
|
return -1
|
||||||
cert_filename_suffix = " in {0}".format(cert_filename)
|
cert_filename_suffix = f" in {cert_filename}"
|
||||||
else:
|
else:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
@@ -459,9 +444,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"Error while running {cmd}: {stderr}".format(
|
f"Error while running {' '.join(openssl_cert_cmd)}: {to_text(err)}"
|
||||||
cmd=" ".join(openssl_cert_cmd), stderr=to_text(err)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
out_text = to_text(out, errors="surrogate_or_strict")
|
out_text = to_text(out, errors="surrogate_or_strict")
|
||||||
@@ -489,7 +472,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
filename = cert_filename
|
filename = cert_filename
|
||||||
data = None
|
data = None
|
||||||
if cert_filename is not None:
|
if cert_filename is not None:
|
||||||
cert_filename_suffix = " in {0}".format(cert_filename)
|
cert_filename_suffix = f" in {cert_filename}"
|
||||||
else:
|
else:
|
||||||
filename = "/dev/stdin"
|
filename = "/dev/stdin"
|
||||||
data = to_bytes(cert_content)
|
data = to_bytes(cert_content)
|
||||||
@@ -512,9 +495,7 @@ class OpenSSLCLIBackend(CryptoBackend):
|
|||||||
)
|
)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
raise BackendException(
|
raise BackendException(
|
||||||
"Error while running {cmd}: {stderr}".format(
|
f"Error while running {' '.join(openssl_cert_cmd)}: {to_text(err)}"
|
||||||
cmd=" ".join(openssl_cert_cmd), stderr=to_text(err)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
out_text = to_text(out, errors="surrogate_or_strict")
|
out_text = to_text(out, errors="surrogate_or_strict")
|
||||||
|
|||||||
@@ -53,15 +53,13 @@ def _reduce_fractional_digits(timestamp_str):
|
|||||||
# RFC 3339 (https://www.rfc-editor.org/info/rfc3339)
|
# RFC 3339 (https://www.rfc-editor.org/info/rfc3339)
|
||||||
m = _FRACTIONAL_MATCHER.match(timestamp_str)
|
m = _FRACTIONAL_MATCHER.match(timestamp_str)
|
||||||
if not m:
|
if not m:
|
||||||
raise BackendException(
|
raise BackendException(f"Cannot parse ISO 8601 timestamp {timestamp_str!r}")
|
||||||
"Cannot parse ISO 8601 timestamp {0!r}".format(timestamp_str)
|
|
||||||
)
|
|
||||||
timestamp, fractional, timezone = m.groups()
|
timestamp, fractional, timezone = m.groups()
|
||||||
if len(fractional) > 7:
|
if len(fractional) > 7:
|
||||||
# Python does not support anything smaller than microseconds
|
# Python does not support anything smaller than microseconds
|
||||||
# (Golang supports nanoseconds, Boulder often emits more fractional digits, which Python chokes on)
|
# (Golang supports nanoseconds, Boulder often emits more fractional digits, which Python chokes on)
|
||||||
fractional = fractional[:7]
|
fractional = fractional[:7]
|
||||||
return "%s%s%s" % (timestamp, fractional, timezone)
|
return f"{timestamp}{fractional}{timezone}"
|
||||||
|
|
||||||
|
|
||||||
def _parse_acme_timestamp(timestamp_str, with_timezone):
|
def _parse_acme_timestamp(timestamp_str, with_timezone):
|
||||||
@@ -87,9 +85,7 @@ def _parse_acme_timestamp(timestamp_str, with_timezone):
|
|||||||
if with_timezone
|
if with_timezone
|
||||||
else remove_timezone(result)
|
else remove_timezone(result)
|
||||||
)
|
)
|
||||||
raise BackendException(
|
raise BackendException(f"Cannot parse ISO 8601 timestamp {timestamp_str!r}")
|
||||||
"Cannot parse ISO 8601 timestamp {0!r}".format(timestamp_str)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class ACMECertificateClient:
|
|||||||
raise ModuleFailException(msg="Account does not exist or is deactivated.")
|
raise ModuleFailException(msg="Account does not exist or is deactivated.")
|
||||||
|
|
||||||
if self.csr is not None and not os.path.exists(self.csr):
|
if self.csr is not None and not os.path.exists(self.csr):
|
||||||
raise ModuleFailException("CSR %s not found" % (self.csr))
|
raise ModuleFailException(f"CSR {self.csr} not found")
|
||||||
|
|
||||||
# Extract list of identifiers from CSR
|
# Extract list of identifiers from CSR
|
||||||
if self.csr is not None or self.csr_content is not None:
|
if self.csr is not None or self.csr_content is not None:
|
||||||
@@ -84,9 +84,7 @@ class ACMECertificateClient:
|
|||||||
)
|
)
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
self.module.warn(
|
self.module.warn(
|
||||||
"Error while parsing criterium: {error}. Ignoring criterium.".format(
|
f"Error while parsing criterium: {exc}. Ignoring criterium."
|
||||||
error=exc
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return select_chain_matcher
|
return select_chain_matcher
|
||||||
|
|
||||||
@@ -154,17 +152,13 @@ class ACMECertificateClient:
|
|||||||
for authz in order.authorizations.values():
|
for authz in order.authorizations.values():
|
||||||
if authz.status not in ("valid", "pending"):
|
if authz.status not in ("valid", "pending"):
|
||||||
bad_authzs.append(
|
bad_authzs.append(
|
||||||
"{authz} (status={status!r})".format(
|
f"{authz.combined_identifier} (status={authz.status!r})"
|
||||||
authz=authz.combined_identifier,
|
|
||||||
status=authz.status,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if bad_authzs:
|
if bad_authzs:
|
||||||
|
bad_authzs = ", ".join(sorted(bad_authzs))
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"Some of the authorizations for the order are in a bad state, so the order"
|
"Some of the authorizations for the order are in a bad state, so the order"
|
||||||
" can no longer be satisfied: {bad_authzs}".format(
|
f" can no longer be satisfied: {bad_authzs}",
|
||||||
bad_authzs=", ".join(sorted(bad_authzs)),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def collect_invalid_authzs(self, order):
|
def collect_invalid_authzs(self, order):
|
||||||
@@ -201,18 +195,14 @@ class ACMECertificateClient:
|
|||||||
alt_cert = CertificateChain.download(self.client, alternate)
|
alt_cert = CertificateChain.download(self.client, alternate)
|
||||||
except ModuleFailException as e:
|
except ModuleFailException as e:
|
||||||
self.module.warn(
|
self.module.warn(
|
||||||
"Error while downloading alternative certificate {0}: {1}".format(
|
f"Error while downloading alternative certificate {alternate}: {e}"
|
||||||
alternate, e
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
if alt_cert.cert is not None:
|
if alt_cert.cert is not None:
|
||||||
alternate_chains.append(alt_cert)
|
alternate_chains.append(alt_cert)
|
||||||
else:
|
else:
|
||||||
self.module.warn(
|
self.module.warn(
|
||||||
"Error while downloading alternative certificate {0}: no certificate found".format(
|
f"Error while downloading alternative certificate {alternate}: no certificate found"
|
||||||
alternate
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return alternate_chains
|
return alternate_chains
|
||||||
|
|
||||||
@@ -222,22 +212,18 @@ class ACMECertificateClient:
|
|||||||
"""
|
"""
|
||||||
if order.status != "valid":
|
if order.status != "valid":
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"The order must be valid, but has state {state!r}!".format(
|
f"The order must be valid, but has state {order.state!r}!"
|
||||||
state=order.state
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not order.certificate_uri:
|
if not order.certificate_uri:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"Order's crtificate URL {url!r} is empty!".format(
|
f"Order's crtificate URL {order.certificate_uri!r} is empty!"
|
||||||
url=order.certificate_uri
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
cert = CertificateChain.download(self.client, order.certificate_uri)
|
cert = CertificateChain.download(self.client, order.certificate_uri)
|
||||||
if cert.cert is None:
|
if cert.cert is None:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"Certificate at {url} is empty!".format(url=order.certificate_uri)
|
f"Certificate at {order.certificate_uri} is empty!"
|
||||||
)
|
)
|
||||||
|
|
||||||
alternate_chains = None
|
alternate_chains = None
|
||||||
@@ -256,7 +242,7 @@ class ACMECertificateClient:
|
|||||||
for identifier, authz in order.authorizations.items():
|
for identifier, authz in order.authorizations.items():
|
||||||
if authz.status != "valid":
|
if authz.status != "valid":
|
||||||
authz.raise_error(
|
authz.raise_error(
|
||||||
'Status is {status!r} and not "valid"'.format(status=authz.status),
|
f'Status is {authz.status!r} and not "valid"',
|
||||||
module=self.module,
|
module=self.module,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -269,7 +255,7 @@ class ACMECertificateClient:
|
|||||||
for chain in chains:
|
for chain in chains:
|
||||||
if matcher.match(chain):
|
if matcher.match(chain):
|
||||||
self.module.debug(
|
self.module.debug(
|
||||||
"Found matching chain for criterium {0}".format(criterium_idx)
|
f"Found matching chain for criterium {criterium_idx}"
|
||||||
)
|
)
|
||||||
return chain
|
return chain
|
||||||
return None
|
return None
|
||||||
@@ -312,9 +298,7 @@ class ACMECertificateClient:
|
|||||||
pass
|
pass
|
||||||
if authz is None or authz.status != "deactivated":
|
if authz is None or authz.status != "deactivated":
|
||||||
self.module.warn(
|
self.module.warn(
|
||||||
warning="Could not deactivate authz object {0}.".format(
|
warning=f"Could not deactivate authz object {authz_uri}."
|
||||||
authz_uri
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
for authz in order.authorizations.values():
|
for authz in order.authorizations.values():
|
||||||
@@ -325,7 +309,5 @@ class ACMECertificateClient:
|
|||||||
pass
|
pass
|
||||||
if authz.status != "deactivated":
|
if authz.status != "deactivated":
|
||||||
self.module.warn(
|
self.module.warn(
|
||||||
warning="Could not deactivate authz object {0}.".format(
|
warning=f"Could not deactivate authz object {authz.url}."
|
||||||
authz.url
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -44,9 +44,7 @@ class CertificateChain:
|
|||||||
"application/pem-certificate-chain"
|
"application/pem-certificate-chain"
|
||||||
):
|
):
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"Cannot download certificate chain from {0}, as content type is not application/pem-certificate-chain: {1} (headers: {2})".format(
|
f"Cannot download certificate chain from {url}, as content type is not application/pem-certificate-chain: {content} (headers: {info})"
|
||||||
url, content, info
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
result = cls(url)
|
result = cls(url)
|
||||||
@@ -63,9 +61,7 @@ class CertificateChain:
|
|||||||
|
|
||||||
if result.cert is None:
|
if result.cert is None:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"Failed to parse certificate chain download from {0}: {1} (headers: {2})".format(
|
f"Failed to parse certificate chain download from {url}: {content} (headers: {info})"
|
||||||
url, content, info
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ def create_key_authorization(client, token):
|
|||||||
client.account_jwk, sort_keys=True, separators=(",", ":")
|
client.account_jwk, sort_keys=True, separators=(",", ":")
|
||||||
)
|
)
|
||||||
thumbprint = nopad_b64(hashlib.sha256(accountkey_json.encode("utf8")).digest())
|
thumbprint = nopad_b64(hashlib.sha256(accountkey_json.encode("utf8")).digest())
|
||||||
return "{0}.{1}".format(token, thumbprint)
|
return f"{token}.{thumbprint}"
|
||||||
|
|
||||||
|
|
||||||
def combine_identifier(identifier_type, identifier):
|
def combine_identifier(identifier_type, identifier):
|
||||||
return "{type}:{identifier}".format(type=identifier_type, identifier=identifier)
|
return f"{identifier_type}:{identifier}"
|
||||||
|
|
||||||
|
|
||||||
def normalize_combined_identifier(identifier):
|
def normalize_combined_identifier(identifier):
|
||||||
@@ -55,9 +55,7 @@ def split_identifier(identifier):
|
|||||||
parts = identifier.split(":", 1)
|
parts = identifier.split(":", 1)
|
||||||
if len(parts) != 2:
|
if len(parts) != 2:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
'Identifier "{identifier}" is not of the form <type>:<identifier>'.format(
|
f'Identifier "{identifier}" is not of the form <type>:<identifier>'
|
||||||
identifier=identifier
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return parts
|
return parts
|
||||||
|
|
||||||
@@ -94,7 +92,7 @@ class Challenge:
|
|||||||
if self.type == "http-01":
|
if self.type == "http-01":
|
||||||
# https://tools.ietf.org/html/rfc8555#section-8.3
|
# https://tools.ietf.org/html/rfc8555#section-8.3
|
||||||
return {
|
return {
|
||||||
"resource": ".well-known/acme-challenge/{token}".format(token=token),
|
"resource": f".well-known/acme-challenge/{token}",
|
||||||
"resource_value": key_authorization,
|
"resource_value": key_authorization,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,9 +102,7 @@ class Challenge:
|
|||||||
# https://tools.ietf.org/html/rfc8555#section-8.4
|
# https://tools.ietf.org/html/rfc8555#section-8.4
|
||||||
resource = "_acme-challenge"
|
resource = "_acme-challenge"
|
||||||
value = nopad_b64(hashlib.sha256(to_bytes(key_authorization)).digest())
|
value = nopad_b64(hashlib.sha256(to_bytes(key_authorization)).digest())
|
||||||
record = "{0}.{1}".format(
|
record = f"{resource}.{identifier[2:] if identifier.startswith('*.') else identifier}"
|
||||||
resource, identifier[2:] if identifier.startswith("*.") else identifier
|
|
||||||
)
|
|
||||||
return {
|
return {
|
||||||
"resource": resource,
|
"resource": resource,
|
||||||
"resource_value": value,
|
"resource_value": value,
|
||||||
@@ -152,7 +148,7 @@ class Authorization:
|
|||||||
self.identifier = data["identifier"]["value"]
|
self.identifier = data["identifier"]["value"]
|
||||||
self.identifier_type = data["identifier"]["type"]
|
self.identifier_type = data["identifier"]["type"]
|
||||||
if data.get("wildcard", False):
|
if data.get("wildcard", False):
|
||||||
self.identifier = "*.{0}".format(self.identifier)
|
self.identifier = f"*.{self.identifier}"
|
||||||
|
|
||||||
def __init__(self, url):
|
def __init__(self, url):
|
||||||
self.url = url
|
self.url = url
|
||||||
@@ -238,23 +234,17 @@ class Authorization:
|
|||||||
# details for all of them before failing
|
# details for all of them before failing
|
||||||
for challenge in self.challenges:
|
for challenge in self.challenges:
|
||||||
if challenge.status == "invalid":
|
if challenge.status == "invalid":
|
||||||
msg = "Challenge {type}".format(type=challenge.type)
|
msg = f"Challenge {challenge.type}"
|
||||||
if "error" in challenge.data:
|
if "error" in challenge.data:
|
||||||
msg = "{msg}: {problem}".format(
|
problem = format_error_problem(
|
||||||
msg=msg,
|
challenge.data["error"],
|
||||||
problem=format_error_problem(
|
subproblem_prefix=f"{challenge.type}.",
|
||||||
challenge.data["error"],
|
|
||||||
subproblem_prefix="{0}.".format(challenge.type),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
msg = f"{msg}: {problem}"
|
||||||
error_details.append(msg)
|
error_details.append(msg)
|
||||||
raise ACMEProtocolException(
|
raise ACMEProtocolException(
|
||||||
module,
|
module,
|
||||||
"Failed to validate challenge for {identifier}: {error}. {details}".format(
|
f"Failed to validate challenge for {self.combined_identifier}: {error_msg}. {'; '.join(error_details)}",
|
||||||
identifier=self.combined_identifier,
|
|
||||||
error=error_msg,
|
|
||||||
details="; ".join(error_details),
|
|
||||||
),
|
|
||||||
extras=dict(
|
extras=dict(
|
||||||
identifier=self.combined_identifier,
|
identifier=self.combined_identifier,
|
||||||
authorization=self.data,
|
authorization=self.data,
|
||||||
@@ -287,10 +277,7 @@ class Authorization:
|
|||||||
challenge = self.find_challenge(challenge_type)
|
challenge = self.find_challenge(challenge_type)
|
||||||
if challenge is None:
|
if challenge is None:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
'Found no challenge of type "{challenge}" for identifier {identifier}!'.format(
|
f'Found no challenge of type "{challenge_type}" for identifier {self.combined_identifier}!'
|
||||||
challenge=challenge_type,
|
|
||||||
identifier=self.combined_identifier,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
challenge.call_validate(client)
|
challenge.call_validate(client)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ def format_http_status(status_code):
|
|||||||
expl = http_responses.get(status_code)
|
expl = http_responses.get(status_code)
|
||||||
if not expl:
|
if not expl:
|
||||||
return str(status_code)
|
return str(status_code)
|
||||||
return "%d %s" % (status_code, expl)
|
return f"{status_code} {expl}"
|
||||||
|
|
||||||
|
|
||||||
def format_error_problem(problem, subproblem_prefix=""):
|
def format_error_problem(problem, subproblem_prefix=""):
|
||||||
@@ -22,26 +22,18 @@ def format_error_problem(problem, subproblem_prefix=""):
|
|||||||
"type", "about:blank"
|
"type", "about:blank"
|
||||||
) # https://www.rfc-editor.org/rfc/rfc7807#section-3.1
|
) # https://www.rfc-editor.org/rfc/rfc7807#section-3.1
|
||||||
if "title" in problem:
|
if "title" in problem:
|
||||||
msg = 'Error "{title}" ({type})'.format(
|
msg = f'Error "{problem["title"]}" ({error_type})'
|
||||||
type=error_type,
|
|
||||||
title=problem["title"],
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
msg = "Error {type}".format(type=error_type)
|
msg = f"Error {error_type}"
|
||||||
if "detail" in problem:
|
if "detail" in problem:
|
||||||
msg += ': "{detail}"'.format(detail=problem["detail"])
|
msg += f': "{problem["detail"]}"'
|
||||||
subproblems = problem.get("subproblems")
|
subproblems = problem.get("subproblems")
|
||||||
if subproblems is not None:
|
if subproblems is not None:
|
||||||
msg = "{msg} Subproblems:".format(msg=msg)
|
msg = f"{msg} Subproblems:"
|
||||||
for index, problem in enumerate(subproblems):
|
for index, problem in enumerate(subproblems):
|
||||||
index_str = "{prefix}{index}".format(prefix=subproblem_prefix, index=index)
|
index_str = f"{subproblem_prefix}{index}"
|
||||||
msg = "{msg}\n({index}) {problem}".format(
|
problem = format_error_problem(problem, subproblem_prefix=f"{index_str}.")
|
||||||
msg=msg,
|
msg = f"{msg}\n({index_str}) {problem}"
|
||||||
index=index_str,
|
|
||||||
problem=format_error_problem(
|
|
||||||
problem, subproblem_prefix="{0}.".format(index_str)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
||||||
@@ -116,55 +108,37 @@ class ACMEProtocolException(ModuleFailException):
|
|||||||
):
|
):
|
||||||
error_type = content_json["type"]
|
error_type = content_json["type"]
|
||||||
if "status" in content_json and content_json["status"] != code:
|
if "status" in content_json and content_json["status"] != code:
|
||||||
code_msg = (
|
code_msg = f"status {content_json['status']} (HTTP status: {format_http_status(code)})"
|
||||||
"status {problem_code} (HTTP status: {http_code})".format(
|
|
||||||
http_code=format_http_status(code),
|
|
||||||
problem_code=content_json["status"],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
code_msg = "status {problem_code}".format(
|
code_msg = f"status {format_http_status(code)}"
|
||||||
problem_code=format_http_status(code)
|
|
||||||
)
|
|
||||||
if code == -1 and info.get("msg"):
|
if code == -1 and info.get("msg"):
|
||||||
code_msg = "error: {msg}".format(msg=info["msg"])
|
code_msg = f"error: {info['msg']}"
|
||||||
subproblems = content_json.pop("subproblems", None)
|
subproblems = content_json.pop("subproblems", None)
|
||||||
add_msg = " {problem}.".format(
|
add_msg = f" {format_error_problem(content_json)}."
|
||||||
problem=format_error_problem(content_json)
|
|
||||||
)
|
|
||||||
extras["problem"] = content_json
|
extras["problem"] = content_json
|
||||||
extras["subproblems"] = subproblems or []
|
extras["subproblems"] = subproblems or []
|
||||||
if subproblems is not None:
|
if subproblems is not None:
|
||||||
add_msg = "{add_msg} Subproblems:".format(add_msg=add_msg)
|
add_msg = f"{add_msg} Subproblems:"
|
||||||
for index, problem in enumerate(subproblems):
|
for index, problem in enumerate(subproblems):
|
||||||
add_msg = "{add_msg}\n({index}) {problem}.".format(
|
problem = format_error_problem(
|
||||||
add_msg=add_msg,
|
problem, subproblem_prefix=f"{index}."
|
||||||
index=index,
|
|
||||||
problem=format_error_problem(
|
|
||||||
problem, subproblem_prefix="{0}.".format(index)
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
add_msg = f"{add_msg}\n({index}) {problem}."
|
||||||
else:
|
else:
|
||||||
code_msg = "HTTP status {code}".format(code=format_http_status(code))
|
code_msg = f"HTTP status {format_http_status(code)}"
|
||||||
if code == -1 and info.get("msg"):
|
if code == -1 and info.get("msg"):
|
||||||
code_msg = "error: {msg}".format(msg=info["msg"])
|
code_msg = f"error: {info['msg']}"
|
||||||
if content_json is not None:
|
if content_json is not None:
|
||||||
add_msg = " The JSON error result: {content}".format(
|
add_msg = f" The JSON error result: {content_json}"
|
||||||
content=content_json
|
|
||||||
)
|
|
||||||
elif content is not None:
|
elif content is not None:
|
||||||
add_msg = " The raw error result: {content}".format(
|
add_msg = f" The raw error result: {to_text(content)}"
|
||||||
content=to_text(content)
|
msg = f"{msg} for {url} with {code_msg}"
|
||||||
)
|
|
||||||
msg = "{msg} for {url} with {code}".format(msg=msg, url=url, code=code_msg)
|
|
||||||
elif content_json is not None:
|
elif content_json is not None:
|
||||||
add_msg = " The JSON result: {content}".format(content=content_json)
|
add_msg = f" The JSON result: {content_json}"
|
||||||
elif content is not None:
|
elif content is not None:
|
||||||
add_msg = " The raw result: {content}".format(content=to_text(content))
|
add_msg = f" The raw result: {to_text(content)}"
|
||||||
|
|
||||||
super(ACMEProtocolException, self).__init__(
|
super(ACMEProtocolException, self).__init__(f"{msg}.{add_msg}", **extras)
|
||||||
"{msg}.{add_msg}".format(msg=msg, add_msg=add_msg), **extras
|
|
||||||
)
|
|
||||||
self.problem = {}
|
self.problem = {}
|
||||||
self.subproblems = []
|
self.subproblems = []
|
||||||
self.error_code = error_code
|
self.error_code = error_code
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ def read_file(fn, mode="b"):
|
|||||||
with open(fn, "r" + mode) as f:
|
with open(fn, "r" + mode) as f:
|
||||||
return f.read()
|
return f.read()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ModuleFailException('Error while reading file "{0}": {1}'.format(fn, e))
|
raise ModuleFailException(f'Error while reading file "{fn}": {e}')
|
||||||
|
|
||||||
|
|
||||||
# This function was adapted from an earlier version of https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/uri.py
|
# This function was adapted from an earlier version of https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/uri.py
|
||||||
@@ -44,7 +44,7 @@ def write_file(module, dest, content):
|
|||||||
pass
|
pass
|
||||||
os.remove(tmpsrc)
|
os.remove(tmpsrc)
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"failed to create temporary content file: %s" % to_native(err),
|
f"failed to create temporary content file: {err}",
|
||||||
exception=traceback.format_exc(),
|
exception=traceback.format_exc(),
|
||||||
)
|
)
|
||||||
f.close()
|
f.close()
|
||||||
@@ -56,26 +56,26 @@ def write_file(module, dest, content):
|
|||||||
os.remove(tmpsrc)
|
os.remove(tmpsrc)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
raise ModuleFailException("Source %s does not exist" % (tmpsrc))
|
raise ModuleFailException(f"Source {tmpsrc} does not exist")
|
||||||
if not os.access(tmpsrc, os.R_OK):
|
if not os.access(tmpsrc, os.R_OK):
|
||||||
os.remove(tmpsrc)
|
os.remove(tmpsrc)
|
||||||
raise ModuleFailException("Source %s not readable" % (tmpsrc))
|
raise ModuleFailException(f"Source {tmpsrc} not readable")
|
||||||
checksum_src = module.sha1(tmpsrc)
|
checksum_src = module.sha1(tmpsrc)
|
||||||
# check if there is no dest file
|
# check if there is no dest file
|
||||||
if os.path.exists(dest):
|
if os.path.exists(dest):
|
||||||
# raise an error if copy has no permission on dest
|
# raise an error if copy has no permission on dest
|
||||||
if not os.access(dest, os.W_OK):
|
if not os.access(dest, os.W_OK):
|
||||||
os.remove(tmpsrc)
|
os.remove(tmpsrc)
|
||||||
raise ModuleFailException("Destination %s not writable" % (dest))
|
raise ModuleFailException(f"Destination {dest} not writable")
|
||||||
if not os.access(dest, os.R_OK):
|
if not os.access(dest, os.R_OK):
|
||||||
os.remove(tmpsrc)
|
os.remove(tmpsrc)
|
||||||
raise ModuleFailException("Destination %s not readable" % (dest))
|
raise ModuleFailException(f"Destination {dest} not readable")
|
||||||
checksum_dest = module.sha1(dest)
|
checksum_dest = module.sha1(dest)
|
||||||
else:
|
else:
|
||||||
dirname = os.path.dirname(dest) or "."
|
dirname = os.path.dirname(dest) or "."
|
||||||
if not os.access(dirname, os.W_OK):
|
if not os.access(dirname, os.W_OK):
|
||||||
os.remove(tmpsrc)
|
os.remove(tmpsrc)
|
||||||
raise ModuleFailException("Destination dir %s not writable" % (dirname))
|
raise ModuleFailException(f"Destination dir {dirname} not writable")
|
||||||
if checksum_src != checksum_dest:
|
if checksum_src != checksum_dest:
|
||||||
try:
|
try:
|
||||||
shutil.copyfile(tmpsrc, dest)
|
shutil.copyfile(tmpsrc, dest)
|
||||||
@@ -83,7 +83,7 @@ def write_file(module, dest, content):
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
os.remove(tmpsrc)
|
os.remove(tmpsrc)
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"failed to copy %s to %s: %s" % (tmpsrc, dest, to_native(err)),
|
f"failed to copy {tmpsrc} to {dest}: {to_native(err)}",
|
||||||
exception=traceback.format_exc(),
|
exception=traceback.format_exc(),
|
||||||
)
|
)
|
||||||
os.remove(tmpsrc)
|
os.remove(tmpsrc)
|
||||||
|
|||||||
@@ -133,11 +133,7 @@ class Order:
|
|||||||
):
|
):
|
||||||
if message_callback:
|
if message_callback:
|
||||||
message_callback(
|
message_callback(
|
||||||
"Stop passing `replaces={replaces}` due to error {code} {type} when creating ACME order".format(
|
f"Stop passing `replaces={replaces_cert_id}` due to error {exc.error_code} {exc.error_type} when creating ACME order"
|
||||||
code=exc.error_code,
|
|
||||||
type=exc.error_type,
|
|
||||||
replaces=replaces_cert_id,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
replaces_cert_id = None
|
replaces_cert_id = None
|
||||||
continue
|
continue
|
||||||
@@ -167,9 +163,7 @@ class Order:
|
|||||||
if self.status != "valid":
|
if self.status != "valid":
|
||||||
raise ACMEProtocolException(
|
raise ACMEProtocolException(
|
||||||
client.module,
|
client.module,
|
||||||
'Failed to wait for order to complete; got status "{status}"'.format(
|
f'Failed to wait for order to complete; got status "{self.status}"',
|
||||||
status=self.status
|
|
||||||
),
|
|
||||||
content_json=self.data,
|
content_json=self.data,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -198,9 +192,7 @@ class Order:
|
|||||||
if self.status not in ["procesing", "valid", "invalid"]:
|
if self.status not in ["procesing", "valid", "invalid"]:
|
||||||
raise ACMEProtocolException(
|
raise ACMEProtocolException(
|
||||||
client.module,
|
client.module,
|
||||||
'Failed to finalize order; got status "{status}"'.format(
|
f'Failed to finalize order; got status "{self.status}"',
|
||||||
status=self.status
|
|
||||||
),
|
|
||||||
info=info,
|
info=info,
|
||||||
content_json=result,
|
content_json=result,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -32,9 +32,8 @@ def der_to_pem(der_cert):
|
|||||||
"""
|
"""
|
||||||
Convert the DER format certificate in der_cert to a PEM format certificate and return it.
|
Convert the DER format certificate in der_cert to a PEM format certificate and return it.
|
||||||
"""
|
"""
|
||||||
return """-----BEGIN CERTIFICATE-----\n{0}\n-----END CERTIFICATE-----\n""".format(
|
content = "\n".join(textwrap.wrap(base64.b64encode(der_cert).decode("utf8"), 64))
|
||||||
"\n".join(textwrap.wrap(base64.b64encode(der_cert).decode("utf8"), 64))
|
return f"-----BEGIN CERTIFICATE-----\n{content}\n-----END CERTIFICATE-----\n"
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def pem_to_der(pem_filename=None, pem_content=None):
|
def pem_to_der(pem_filename=None, pem_content=None):
|
||||||
@@ -52,7 +51,7 @@ def pem_to_der(pem_filename=None, pem_content=None):
|
|||||||
lines = list(f)
|
lines = list(f)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"cannot load PEM file {0}: {1}".format(pem_filename, to_native(err)),
|
f"cannot load PEM file {pem_filename}: {to_native(err)}",
|
||||||
exception=traceback.format_exc(),
|
exception=traceback.format_exc(),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -104,7 +103,7 @@ def parse_retry_after(value, relative_with_timezone=True, now=None):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
raise ValueError("Cannot parse Retry-After header value %s" % repr(value))
|
raise ValueError(f"Cannot parse Retry-After header value {repr(value)}")
|
||||||
|
|
||||||
|
|
||||||
def compute_cert_id(
|
def compute_cert_id(
|
||||||
@@ -138,4 +137,4 @@ def compute_cert_id(
|
|||||||
serial = to_native(base64.urlsafe_b64encode(serial_bytes)).replace("=", "")
|
serial = to_native(base64.urlsafe_b64encode(serial_bytes)).replace("=", "")
|
||||||
|
|
||||||
# Compose cert ID
|
# Compose cert ID
|
||||||
return "{aki}.{serial}".format(aki=aki, serial=serial)
|
return f"{aki}.{serial}"
|
||||||
|
|||||||
@@ -82,8 +82,7 @@ def serialize_asn1_string_as_der(value):
|
|||||||
|
|
||||||
if value_type != "UTF8":
|
if value_type != "UTF8":
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'The ASN.1 serialized string is not a known type "{0}", only UTF8 types are '
|
f'The ASN.1 serialized string is not a known type "{value_type}", only UTF8 types are supported'
|
||||||
"supported".format(value_type)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
b_value = to_bytes(asn1_value, encoding="utf-8", errors="surrogate_or_strict")
|
b_value = to_bytes(asn1_value, encoding="utf-8", errors="surrogate_or_strict")
|
||||||
@@ -117,7 +116,7 @@ def pack_asn1(tag_class, constructed, tag_number, b_data):
|
|||||||
b_asn1_data = bytearray()
|
b_asn1_data = bytearray()
|
||||||
|
|
||||||
if tag_class < 0 or tag_class > 3:
|
if tag_class < 0 or tag_class > 3:
|
||||||
raise ValueError("tag_class must be between 0 and 3 not %s" % tag_class)
|
raise ValueError(f"tag_class must be between 0 and 3 not {tag_class}")
|
||||||
|
|
||||||
# Bit 8 and 7 denotes the class.
|
# Bit 8 and 7 denotes the class.
|
||||||
identifier_octets = tag_class << 6
|
identifier_octets = tag_class << 6
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ for dotted, names in OID_MAP.items():
|
|||||||
for name in names:
|
for name in names:
|
||||||
if name in NORMALIZE_NAMES and OID_LOOKUP[name] != dotted:
|
if name in NORMALIZE_NAMES and OID_LOOKUP[name] != dotted:
|
||||||
raise AssertionError(
|
raise AssertionError(
|
||||||
'Name collision during setup: "{0}" for OIDs {1} and {2}'.format(
|
f'Name collision during setup: "{name}" for OIDs {dotted} and {OID_LOOKUP[name]}'
|
||||||
name, dotted, OID_LOOKUP[name]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
NORMALIZE_NAMES[name] = names[0]
|
NORMALIZE_NAMES[name] = names[0]
|
||||||
NORMALIZE_NAMES_SHORT[name] = names[-1]
|
NORMALIZE_NAMES_SHORT[name] = names[-1]
|
||||||
@@ -25,9 +23,7 @@ for dotted, names in OID_MAP.items():
|
|||||||
for alias, original in [("userID", "userId")]:
|
for alias, original in [("userID", "userId")]:
|
||||||
if alias in NORMALIZE_NAMES:
|
if alias in NORMALIZE_NAMES:
|
||||||
raise AssertionError(
|
raise AssertionError(
|
||||||
'Name collision during adding aliases: "{0}" (alias for "{1}") is already mapped to OID {2}'.format(
|
f'Name collision during adding aliases: "{alias}" (alias for "{original}") is already mapped to OID {OID_LOOKUP[alias]}'
|
||||||
alias, original, OID_LOOKUP[alias]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
NORMALIZE_NAMES[alias] = original
|
NORMALIZE_NAMES[alias] = original
|
||||||
NORMALIZE_NAMES_SHORT[alias] = NORMALIZE_NAMES_SHORT[original]
|
NORMALIZE_NAMES_SHORT[alias] = NORMALIZE_NAMES_SHORT[original]
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ def cryptography_name_to_oid(name):
|
|||||||
if dotted is None:
|
if dotted is None:
|
||||||
if DOTTED_OID.match(name):
|
if DOTTED_OID.match(name):
|
||||||
return x509.oid.ObjectIdentifier(name)
|
return x509.oid.ObjectIdentifier(name)
|
||||||
raise OpenSSLObjectError('Cannot find OID for "{0}"'.format(name))
|
raise OpenSSLObjectError(f'Cannot find OID for "{name}"')
|
||||||
return x509.oid.ObjectIdentifier(dotted)
|
return x509.oid.ObjectIdentifier(dotted)
|
||||||
|
|
||||||
|
|
||||||
@@ -297,7 +297,7 @@ else:
|
|||||||
def _parse_dn_component(name, sep=b",", decode_remainder=True):
|
def _parse_dn_component(name, sep=b",", decode_remainder=True):
|
||||||
m = DN_COMPONENT_START_RE.match(name)
|
m = DN_COMPONENT_START_RE.match(name)
|
||||||
if not m:
|
if not m:
|
||||||
raise OpenSSLObjectError('cannot start part in "{0}"'.format(to_text(name)))
|
raise OpenSSLObjectError(f'cannot start part in "{to_text(name)}"')
|
||||||
oid = cryptography_name_to_oid(to_text(m.group(1)))
|
oid = cryptography_name_to_oid(to_text(m.group(1)))
|
||||||
idx = len(m.group(0))
|
idx = len(m.group(0))
|
||||||
decoded_name = []
|
decoded_name = []
|
||||||
@@ -314,7 +314,7 @@ def _parse_dn_component(name, sep=b",", decode_remainder=True):
|
|||||||
idx2 = DN_HEX_LETTER.find(ch2.lower())
|
idx2 = DN_HEX_LETTER.find(ch2.lower())
|
||||||
if idx1 < 0 or idx2 < 0:
|
if idx1 < 0 or idx2 < 0:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Invalid hex sequence entry "{0}"'.format(to_text(ch1 + ch2))
|
f'Invalid hex sequence entry "{to_text(ch1 + ch2)}"'
|
||||||
)
|
)
|
||||||
idx += 2
|
idx += 2
|
||||||
decoded_name.append(_int_to_byte(idx1 * 16 + idx2))
|
decoded_name.append(_int_to_byte(idx1 * 16 + idx2))
|
||||||
@@ -333,17 +333,13 @@ def _parse_dn_component(name, sep=b",", decode_remainder=True):
|
|||||||
if idx1 >= 0:
|
if idx1 >= 0:
|
||||||
if idx + 2 >= length:
|
if idx + 2 >= length:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Hex escape sequence "\\{0}" incomplete at end of string'.format(
|
f'Hex escape sequence "\\{to_text(ch)}" incomplete at end of string'
|
||||||
to_text(ch)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
ch2 = name[idx + 2 : idx + 3]
|
ch2 = name[idx + 2 : idx + 3]
|
||||||
idx2 = DN_HEX_LETTER.find(ch2.lower())
|
idx2 = DN_HEX_LETTER.find(ch2.lower())
|
||||||
if idx2 < 0:
|
if idx2 < 0:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Hex escape sequence "\\{0}" has invalid second letter'.format(
|
f'Hex escape sequence "\\{to_text(ch + ch2)}" has invalid second letter'
|
||||||
to_text(ch + ch2)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
ch = _int_to_byte(idx1 * 16 + idx2)
|
ch = _int_to_byte(idx1 * 16 + idx2)
|
||||||
idx += 1
|
idx += 1
|
||||||
@@ -375,17 +371,13 @@ def _parse_dn(name):
|
|||||||
attribute, name = _parse_dn_component(name, sep=sep)
|
attribute, name = _parse_dn_component(name, sep=sep)
|
||||||
except OpenSSLObjectError as e:
|
except OpenSSLObjectError as e:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Error while parsing distinguished name "{0}": {1}'.format(
|
f'Error while parsing distinguished name "{to_text(original_name)}": {e}'
|
||||||
to_text(original_name), e
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
result.append(attribute)
|
result.append(attribute)
|
||||||
if name:
|
if name:
|
||||||
if name[0:1] != sep or len(name) < 2:
|
if name[0:1] != sep or len(name) < 2:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Error while parsing distinguished name "{0}": unexpected end of string'.format(
|
f'Error while parsing distinguished name "{to_text(original_name)}": unexpected end of string'
|
||||||
to_text(original_name)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
name = name[1:]
|
name = name[1:]
|
||||||
return result
|
return result
|
||||||
@@ -398,9 +390,7 @@ def cryptography_parse_relative_distinguished_name(rdn):
|
|||||||
names.append(_parse_dn_component(to_bytes(part), decode_remainder=False)[0])
|
names.append(_parse_dn_component(to_bytes(part), decode_remainder=False)[0])
|
||||||
except OpenSSLObjectError as e:
|
except OpenSSLObjectError as e:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Error while parsing relative distinguished name "{0}": {1}'.format(
|
f'Error while parsing relative distinguished name "{part}": {e}'
|
||||||
part, e
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return cryptography.x509.RelativeDistinguishedName(names)
|
return cryptography.x509.RelativeDistinguishedName(names)
|
||||||
|
|
||||||
@@ -420,16 +410,14 @@ def _adjust_idn(value, idn_rewrite):
|
|||||||
if idn_rewrite == "idna" and _is_ascii(value):
|
if idn_rewrite == "idna" and _is_ascii(value):
|
||||||
return value
|
return value
|
||||||
if idn_rewrite not in ("idna", "unicode"):
|
if idn_rewrite not in ("idna", "unicode"):
|
||||||
raise ValueError('Invalid value for idn_rewrite: "{0}"'.format(idn_rewrite))
|
raise ValueError(f'Invalid value for idn_rewrite: "{idn_rewrite}"')
|
||||||
if not HAS_IDNA:
|
if not HAS_IDNA:
|
||||||
|
what = "IDNA" if idn_rewrite == "unicode" else "Unicode"
|
||||||
|
dest = "Unicode" if idn_rewrite == "unicode" else "IDNA"
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
missing_required_lib(
|
missing_required_lib(
|
||||||
"idna",
|
"idna",
|
||||||
reason='to transform {what} DNS name "{name}" to {dest}'.format(
|
reason=f'to transform {what} DNS name "{value}" to {dest}',
|
||||||
name=value,
|
|
||||||
what="IDNA" if idn_rewrite == "unicode" else "Unicode",
|
|
||||||
dest="Unicode" if idn_rewrite == "unicode" else "IDNA",
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# Since IDNA does not like '*' or empty labels (except one empty label at the end),
|
# Since IDNA does not like '*' or empty labels (except one empty label at the end),
|
||||||
@@ -450,16 +438,11 @@ def _adjust_idn(value, idn_rewrite):
|
|||||||
elif idn_rewrite == "unicode" and part.startswith("xn--"):
|
elif idn_rewrite == "unicode" and part.startswith("xn--"):
|
||||||
parts[index] = part.encode("ascii").decode("idna")
|
parts[index] = part.encode("ascii").decode("idna")
|
||||||
except Exception as exc2003:
|
except Exception as exc2003:
|
||||||
|
what = "IDNA" if idn_rewrite == "unicode" else "Unicode"
|
||||||
|
dest = "Unicode" if idn_rewrite == "unicode" else "IDNA"
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Error while transforming part "{part}" of {what} DNS name "{name}" to {dest}.'
|
f'Error while transforming part "{part}" of {what} DNS name "{value}" to {dest}.'
|
||||||
' IDNA2008 transformation resulted in "{exc2008}", IDNA2003 transformation resulted in "{exc2003}".'.format(
|
f' IDNA2008 transformation resulted in "{exc2008}", IDNA2003 transformation resulted in "{exc2003}".'
|
||||||
part=part,
|
|
||||||
name=value,
|
|
||||||
what="IDNA" if idn_rewrite == "unicode" else "Unicode",
|
|
||||||
dest="Unicode" if idn_rewrite == "unicode" else "IDNA",
|
|
||||||
exc2003=exc2003,
|
|
||||||
exc2008=exc2008,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return ".".join(parts)
|
return ".".join(parts)
|
||||||
|
|
||||||
@@ -468,18 +451,18 @@ def _adjust_idn_email(value, idn_rewrite):
|
|||||||
idx = value.find("@")
|
idx = value.find("@")
|
||||||
if idx < 0:
|
if idx < 0:
|
||||||
return value
|
return value
|
||||||
return "{0}@{1}".format(value[:idx], _adjust_idn(value[idx + 1 :], idn_rewrite))
|
return f"{value[:idx]}@{_adjust_idn(value[idx + 1:], idn_rewrite)}"
|
||||||
|
|
||||||
|
|
||||||
def _adjust_idn_url(value, idn_rewrite):
|
def _adjust_idn_url(value, idn_rewrite):
|
||||||
url = urlparse(value)
|
url = urlparse(value)
|
||||||
host = _adjust_idn(url.hostname, idn_rewrite)
|
host = _adjust_idn(url.hostname, idn_rewrite)
|
||||||
if url.username is not None and url.password is not None:
|
if url.username is not None and url.password is not None:
|
||||||
host = "{0}:{1}@{2}".format(url.username, url.password, host)
|
host = f"{url.username}:{url.password}@{host}"
|
||||||
elif url.username is not None:
|
elif url.username is not None:
|
||||||
host = "{0}@{1}".format(url.username, host)
|
host = f"{url.username}@{host}"
|
||||||
if url.port is not None:
|
if url.port is not None:
|
||||||
host = "{0}:{1}".format(host, url.port)
|
host = f"{host}:{url.port}"
|
||||||
return urlunparse(
|
return urlunparse(
|
||||||
ParseResult(
|
ParseResult(
|
||||||
scheme=url.scheme,
|
scheme=url.scheme,
|
||||||
@@ -514,9 +497,7 @@ def cryptography_get_name(name, what="Subject Alternative Name"):
|
|||||||
if name.startswith("RID:"):
|
if name.startswith("RID:"):
|
||||||
m = re.match(r"^([0-9]+(?:\.[0-9]+)*)$", to_text(name[4:]))
|
m = re.match(r"^([0-9]+(?:\.[0-9]+)*)$", to_text(name[4:]))
|
||||||
if not m:
|
if not m:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(f'Cannot parse {what} "{name}"')
|
||||||
'Cannot parse {what} "{name}"'.format(name=name, what=what)
|
|
||||||
)
|
|
||||||
return x509.RegisteredID(x509.oid.ObjectIdentifier(m.group(1)))
|
return x509.RegisteredID(x509.oid.ObjectIdentifier(m.group(1)))
|
||||||
if name.startswith("otherName:"):
|
if name.startswith("otherName:"):
|
||||||
# otherName can either be a raw ASN.1 hex string or in the format that OpenSSL works with.
|
# otherName can either be a raw ASN.1 hex string or in the format that OpenSSL works with.
|
||||||
@@ -534,9 +515,9 @@ def cryptography_get_name(name, what="Subject Alternative Name"):
|
|||||||
name = to_text(name[10:], errors="surrogate_or_strict")
|
name = to_text(name[10:], errors="surrogate_or_strict")
|
||||||
if ";" not in name:
|
if ";" not in name:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Cannot parse {what} otherName "{name}", must be in the '
|
f'Cannot parse {what} otherName "{name}", must be in the '
|
||||||
'format "otherName:<OID>;<ASN.1 OpenSSL Encoded String>" or '
|
'format "otherName:<OID>;<ASN.1 OpenSSL Encoded String>" or '
|
||||||
'"otherName:<OID>;<hex string>"'.format(name=name, what=what)
|
'"otherName:<OID>;<hex string>"'
|
||||||
)
|
)
|
||||||
|
|
||||||
oid, value = name.split(";", 1)
|
oid, value = name.split(";", 1)
|
||||||
@@ -547,21 +528,13 @@ def cryptography_get_name(name, what="Subject Alternative Name"):
|
|||||||
x509.Name(reversed(_parse_dn(to_bytes(name[8:]))))
|
x509.Name(reversed(_parse_dn(to_bytes(name[8:]))))
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(f'Cannot parse {what} "{name}": {e}')
|
||||||
'Cannot parse {what} "{name}": {error}'.format(
|
|
||||||
name=name, what=what, error=e
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if ":" not in name:
|
if ":" not in name:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Cannot parse {what} "{name}" (forgot "DNS:" prefix?)'.format(
|
f'Cannot parse {what} "{name}" (forgot "DNS:" prefix?)'
|
||||||
name=name, what=what
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Cannot parse {what} "{name}" (potentially unsupported by cryptography backend)'.format(
|
f'Cannot parse {what} "{name}" (potentially unsupported by cryptography backend)'
|
||||||
name=name, what=what
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -571,12 +544,12 @@ def _dn_escape_value(value):
|
|||||||
"""
|
"""
|
||||||
value = value.replace("\\", "\\\\")
|
value = value.replace("\\", "\\\\")
|
||||||
for ch in [",", "+", "<", ">", ";", '"']:
|
for ch in [",", "+", "<", ">", ";", '"']:
|
||||||
value = value.replace(ch, "\\%s" % ch)
|
value = value.replace(ch, f"\\{ch}")
|
||||||
value = value.replace("\0", "\\00")
|
value = value.replace("\0", "\\00")
|
||||||
if value.startswith((" ", "#")):
|
if value.startswith((" ", "#")):
|
||||||
value = "\\%s" % value[0] + value[1:]
|
value = f"\\{value[0]}{value[1:]}"
|
||||||
if value.endswith(" "):
|
if value.endswith(" "):
|
||||||
value = value[:-1] + "\\ "
|
value = f"{value[:-1]}\\ "
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
@@ -590,36 +563,29 @@ def cryptography_decode_name(name, idn_rewrite="ignore"):
|
|||||||
'idn_rewrite must be one of "ignore", "idna", or "unicode"'
|
'idn_rewrite must be one of "ignore", "idna", or "unicode"'
|
||||||
)
|
)
|
||||||
if isinstance(name, x509.DNSName):
|
if isinstance(name, x509.DNSName):
|
||||||
return "DNS:{0}".format(_adjust_idn(name.value, idn_rewrite))
|
return f"DNS:{_adjust_idn(name.value, idn_rewrite)}"
|
||||||
if isinstance(name, x509.IPAddress):
|
if isinstance(name, x509.IPAddress):
|
||||||
if isinstance(name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)):
|
if isinstance(name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)):
|
||||||
return "IP:{0}/{1}".format(
|
return f"IP:{name.value.network_address.compressed}/{name.value.prefixlen}"
|
||||||
name.value.network_address.compressed, name.value.prefixlen
|
return f"IP:{name.value.compressed}"
|
||||||
)
|
|
||||||
return "IP:{0}".format(name.value.compressed)
|
|
||||||
if isinstance(name, x509.RFC822Name):
|
if isinstance(name, x509.RFC822Name):
|
||||||
return "email:{0}".format(_adjust_idn_email(name.value, idn_rewrite))
|
return f"email:{_adjust_idn_email(name.value, idn_rewrite)}"
|
||||||
if isinstance(name, x509.UniformResourceIdentifier):
|
if isinstance(name, x509.UniformResourceIdentifier):
|
||||||
return "URI:{0}".format(_adjust_idn_url(name.value, idn_rewrite))
|
return f"URI:{_adjust_idn_url(name.value, idn_rewrite)}"
|
||||||
if isinstance(name, x509.DirectoryName):
|
if isinstance(name, x509.DirectoryName):
|
||||||
# According to https://datatracker.ietf.org/doc/html/rfc4514.html#section-2.1 the
|
# According to https://datatracker.ietf.org/doc/html/rfc4514.html#section-2.1 the
|
||||||
# list needs to be reversed, and joined by commas
|
# list needs to be reversed, and joined by commas
|
||||||
return "dirName:" + ",".join(
|
return "dirName:" + ",".join(
|
||||||
[
|
[
|
||||||
"{0}={1}".format(
|
f"{to_text(cryptography_oid_to_name(attribute.oid, short=True))}={_dn_escape_value(attribute.value)}"
|
||||||
to_text(cryptography_oid_to_name(attribute.oid, short=True)),
|
|
||||||
_dn_escape_value(attribute.value),
|
|
||||||
)
|
|
||||||
for attribute in reversed(list(name.value))
|
for attribute in reversed(list(name.value))
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
if isinstance(name, x509.RegisteredID):
|
if isinstance(name, x509.RegisteredID):
|
||||||
return "RID:{0}".format(name.value.dotted_string)
|
return f"RID:{name.value.dotted_string}"
|
||||||
if isinstance(name, x509.OtherName):
|
if isinstance(name, x509.OtherName):
|
||||||
return "otherName:{0};{1}".format(
|
return f"otherName:{name.type_id.dotted_string};{_get_hex(name.value)}"
|
||||||
name.type_id.dotted_string, _get_hex(name.value)
|
raise OpenSSLObjectError(f'Cannot decode name "{name}"')
|
||||||
)
|
|
||||||
raise OpenSSLObjectError('Cannot decode name "{0}"'.format(name))
|
|
||||||
|
|
||||||
|
|
||||||
def _cryptography_get_keyusage(usage):
|
def _cryptography_get_keyusage(usage):
|
||||||
@@ -645,7 +611,7 @@ def _cryptography_get_keyusage(usage):
|
|||||||
return "encipher_only"
|
return "encipher_only"
|
||||||
if usage in ("Decipher Only", "decipherOnly"):
|
if usage in ("Decipher Only", "decipherOnly"):
|
||||||
return "decipher_only"
|
return "decipher_only"
|
||||||
raise OpenSSLObjectError('Unknown key usage "{0}"'.format(usage))
|
raise OpenSSLObjectError(f'Unknown key usage "{usage}"')
|
||||||
|
|
||||||
|
|
||||||
def cryptography_parse_key_usage_params(usages):
|
def cryptography_parse_key_usage_params(usages):
|
||||||
@@ -685,9 +651,7 @@ def cryptography_get_basic_constraints(constraints):
|
|||||||
ca = False
|
ca = False
|
||||||
else:
|
else:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Unknown basic constraint value "{0}" for CA'.format(
|
f'Unknown basic constraint value "{constraint[3:]}" for CA'
|
||||||
constraint[3:]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
elif constraint.startswith("pathlen:"):
|
elif constraint.startswith("pathlen:"):
|
||||||
v = constraint[len("pathlen:") :]
|
v = constraint[len("pathlen:") :]
|
||||||
@@ -695,12 +659,10 @@ def cryptography_get_basic_constraints(constraints):
|
|||||||
path_length = int(v)
|
path_length = int(v)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'Cannot parse path length constraint "{0}" ({1})'.format(v, e)
|
f'Cannot parse path length constraint "{v}" ({e})'
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(f'Unknown basic constraint "{constraint}"')
|
||||||
'Unknown basic constraint "{0}"'.format(constraint)
|
|
||||||
)
|
|
||||||
return ca, path_length
|
return ca, path_length
|
||||||
|
|
||||||
|
|
||||||
@@ -958,7 +920,7 @@ def cryptography_verify_signature(signature, data, hash_algorithm, signer_public
|
|||||||
signer_public_key.verify(signature, data)
|
signer_public_key.verify(signature, data)
|
||||||
return True
|
return True
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
"Unsupported public key type {0}".format(type(signer_public_key))
|
f"Unsupported public key type {type(signer_public_key)}"
|
||||||
)
|
)
|
||||||
except InvalidSignature:
|
except InvalidSignature:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -162,9 +162,9 @@ else:
|
|||||||
def _convert_int_to_bytes(count, n):
|
def _convert_int_to_bytes(count, n):
|
||||||
if n == 0 and count == 0:
|
if n == 0 and count == 0:
|
||||||
return ""
|
return ""
|
||||||
h = "%x" % n
|
h = f"{n:x}"
|
||||||
if len(h) > 2 * count:
|
if len(h) > 2 * count:
|
||||||
raise Exception("Number {1} needs more than {0} bytes!".format(count, n))
|
raise Exception(f"Number {n} needs more than {count} bytes!")
|
||||||
return ("0" * (2 * count - len(h)) + h).decode("hex")
|
return ("0" * (2 * count - len(h)) + h).decode("hex")
|
||||||
|
|
||||||
def _convert_bytes_to_int(data):
|
def _convert_bytes_to_int(data):
|
||||||
@@ -174,7 +174,7 @@ else:
|
|||||||
return v
|
return v
|
||||||
|
|
||||||
def _to_hex(no):
|
def _to_hex(no):
|
||||||
return "%x" % no
|
return f"{no:x}"
|
||||||
|
|
||||||
|
|
||||||
def convert_int_to_bytes(no, count=None):
|
def convert_int_to_bytes(no, count=None):
|
||||||
|
|||||||
@@ -363,16 +363,14 @@ def select_backend(module, backend, provider):
|
|||||||
# Fail if no backend has been found
|
# Fail if no backend has been found
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect the required Python library cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
|
||||||
"Cannot detect the required Python library " "cryptography (>= {0})"
|
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -31,17 +31,17 @@ class AcmeCertificateBackend(CertificateBackend):
|
|||||||
)
|
)
|
||||||
if self.csr_content is None and not os.path.exists(self.csr_path):
|
if self.csr_content is None and not os.path.exists(self.csr_path):
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The certificate signing request file %s does not exist" % self.csr_path
|
f"The certificate signing request file {self.csr_path} does not exist"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not os.path.exists(self.accountkey_path):
|
if not os.path.exists(self.accountkey_path):
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The account key %s does not exist" % self.accountkey_path
|
f"The account key {self.accountkey_path} does not exist"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not os.path.exists(self.challenge_path):
|
if not os.path.exists(self.challenge_path):
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The challenge path %s does not exist" % self.challenge_path
|
f"The challenge path {self.challenge_path} does not exist"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.acme_tiny_path = self.module.get_bin_path("acme-tiny", required=True)
|
self.acme_tiny_path = self.module.get_bin_path("acme-tiny", required=True)
|
||||||
@@ -66,7 +66,7 @@ class AcmeCertificateBackend(CertificateBackend):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="failed to create temporary CSR file: %s" % to_native(err),
|
msg=f"failed to create temporary CSR file: {to_native(err)}",
|
||||||
exception=traceback.format_exc(),
|
exception=traceback.format_exc(),
|
||||||
)
|
)
|
||||||
f.close()
|
f.close()
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ class EntrustCertificateBackend(CertificateBackend):
|
|||||||
)
|
)
|
||||||
if self.csr_content is None and not os.path.exists(self.csr_path):
|
if self.csr_content is None and not os.path.exists(self.csr_path):
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The certificate signing request file {0} does not exist".format(
|
f"The certificate signing request file {self.csr_path} does not exist"
|
||||||
self.csr_path
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self._ensure_csr_loaded()
|
self._ensure_csr_loaded()
|
||||||
@@ -77,7 +75,7 @@ class EntrustCertificateBackend(CertificateBackend):
|
|||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg=(
|
msg=(
|
||||||
"Entrust provider does not currently support multiple validated organizations. Multiple organizations found in "
|
"Entrust provider does not currently support multiple validated organizations. Multiple organizations found in "
|
||||||
"Subject DN: '{0}'. ".format(self.csr.subject)
|
f"Subject DN: '{self.csr.subject}'. "
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# If no organization in the CSR, explicitly tell ECS that it should be blank in issued cert, not defaulted to
|
# If no organization in the CSR, explicitly tell ECS that it should be blank in issued cert, not defaulted to
|
||||||
@@ -98,11 +96,7 @@ class EntrustCertificateBackend(CertificateBackend):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
except SessionConfigurationException as e:
|
except SessionConfigurationException as e:
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Failed to initialize Entrust Provider: {e.message}")
|
||||||
msg="Failed to initialize Entrust Provider: {0}".format(
|
|
||||||
to_native(e.message)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def generate_certificate(self):
|
def generate_certificate(self):
|
||||||
"""(Re-)Generate certificate."""
|
"""(Re-)Generate certificate."""
|
||||||
@@ -138,9 +132,7 @@ class EntrustCertificateBackend(CertificateBackend):
|
|||||||
self.trackingId = result.get("trackingId")
|
self.trackingId = result.get("trackingId")
|
||||||
except RestOperationException as e:
|
except RestOperationException as e:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Failed to request new certificate from Entrust Certificate Services (ECS): {0}".format(
|
msg=f"Failed to request new certificate from Entrust Certificate Services (ECS): {e.message}"
|
||||||
to_native(e.message)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.cert_bytes = to_bytes(result.get("endEntityCert"))
|
self.cert_bytes = to_bytes(result.get("endEntityCert"))
|
||||||
@@ -159,9 +151,7 @@ class EntrustCertificateBackend(CertificateBackend):
|
|||||||
cert_details = self._get_cert_details()
|
cert_details = self._get_cert_details()
|
||||||
except RestOperationException as e:
|
except RestOperationException as e:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Failed to get status of existing certificate from Entrust Certificate Services (ECS): {0}.".format(
|
msg=f"Failed to get status of existing certificate from Entrust Certificate Services (ECS): {e.message}."
|
||||||
to_native(e.message)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Always issue a new certificate if the certificate is expired, suspended or revoked
|
# Always issue a new certificate if the certificate is expired, suspended or revoked
|
||||||
@@ -189,8 +179,8 @@ class EntrustCertificateBackend(CertificateBackend):
|
|||||||
serial_number = None
|
serial_number = None
|
||||||
expiry = None
|
expiry = None
|
||||||
if self.backend == "cryptography":
|
if self.backend == "cryptography":
|
||||||
serial_number = "{0:X}".format(
|
serial_number = (
|
||||||
cryptography_serial_number_of_cert(self.existing_certificate)
|
f"{cryptography_serial_number_of_cert(self.existing_certificate):X}"
|
||||||
)
|
)
|
||||||
expiry = get_not_valid_after(self.existing_certificate)
|
expiry = get_not_valid_after(self.existing_certificate)
|
||||||
|
|
||||||
|
|||||||
@@ -332,11 +332,9 @@ class CertificateInfoRetrievalCryptography(CertificateInfoRetrieval):
|
|||||||
x509.BasicConstraints
|
x509.BasicConstraints
|
||||||
)
|
)
|
||||||
result = []
|
result = []
|
||||||
result.append(
|
result.append(f"CA:{'TRUE' if ext_keyusage_ext.value.ca else 'FALSE'}")
|
||||||
"CA:{0}".format("TRUE" if ext_keyusage_ext.value.ca else "FALSE")
|
|
||||||
)
|
|
||||||
if ext_keyusage_ext.value.path_length is not None:
|
if ext_keyusage_ext.value.path_length is not None:
|
||||||
result.append("pathlen:{0}".format(ext_keyusage_ext.value.path_length))
|
result.append(f"pathlen:{ext_keyusage_ext.value.path_length}")
|
||||||
return sorted(result), ext_keyusage_ext.critical
|
return sorted(result), ext_keyusage_ext.critical
|
||||||
except cryptography.x509.ExtensionNotFound:
|
except cryptography.x509.ExtensionNotFound:
|
||||||
return None, False
|
return None, False
|
||||||
@@ -474,20 +472,17 @@ def select_backend(module, backend, content):
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect any of the required Python libraries cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
|
||||||
"Cannot detect any of the required Python libraries "
|
|
||||||
"cryptography (>= {0})"
|
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
return backend, CertificateInfoRetrievalCryptography(module, content)
|
return backend, CertificateInfoRetrievalCryptography(module, content)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported value for backend: {0}".format(backend))
|
raise ValueError(f"Unsupported value for backend: {backend}")
|
||||||
|
|||||||
@@ -93,21 +93,17 @@ class OwnCACertificateBackendCryptography(CertificateBackend):
|
|||||||
)
|
)
|
||||||
if self.csr_content is None and not os.path.exists(self.csr_path):
|
if self.csr_content is None and not os.path.exists(self.csr_path):
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The certificate signing request file {0} does not exist".format(
|
f"The certificate signing request file {self.csr_path} does not exist"
|
||||||
self.csr_path
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if self.ca_cert_content is None and not os.path.exists(self.ca_cert_path):
|
if self.ca_cert_content is None and not os.path.exists(self.ca_cert_path):
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The CA certificate file {0} does not exist".format(self.ca_cert_path)
|
f"The CA certificate file {self.ca_cert_path} does not exist"
|
||||||
)
|
)
|
||||||
if self.ca_privatekey_content is None and not os.path.exists(
|
if self.ca_privatekey_content is None and not os.path.exists(
|
||||||
self.ca_privatekey_path
|
self.ca_privatekey_path
|
||||||
):
|
):
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The CA private key file {0} does not exist".format(
|
f"The CA private key file {self.ca_privatekey_path} does not exist"
|
||||||
self.ca_privatekey_path
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self._ensure_csr_loaded()
|
self._ensure_csr_loaded()
|
||||||
@@ -134,8 +130,7 @@ class OwnCACertificateBackendCryptography(CertificateBackend):
|
|||||||
if cryptography_key_needs_digest_for_signing(self.ca_private_key):
|
if cryptography_key_needs_digest_for_signing(self.ca_private_key):
|
||||||
if self.digest is None:
|
if self.digest is None:
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The digest %s is not supported with the cryptography backend"
|
f"The digest {module.params['ownca_digest']} is not supported with the cryptography backend"
|
||||||
% module.params["ownca_digest"]
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.digest = None
|
self.digest = None
|
||||||
|
|||||||
@@ -67,13 +67,11 @@ class SelfSignedCertificateBackendCryptography(CertificateBackend):
|
|||||||
|
|
||||||
if self.csr_path is not None and not os.path.exists(self.csr_path):
|
if self.csr_path is not None and not os.path.exists(self.csr_path):
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The certificate signing request file {0} does not exist".format(
|
f"The certificate signing request file {self.csr_path} does not exist"
|
||||||
self.csr_path
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if self.privatekey_content is None and not os.path.exists(self.privatekey_path):
|
if self.privatekey_content is None and not os.path.exists(self.privatekey_path):
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The private key file {0} does not exist".format(self.privatekey_path)
|
f"The private key file {self.privatekey_path} does not exist"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._module = module
|
self._module = module
|
||||||
@@ -90,9 +88,7 @@ class SelfSignedCertificateBackendCryptography(CertificateBackend):
|
|||||||
digest = self.digest
|
digest = self.digest
|
||||||
if digest is None:
|
if digest is None:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg='Unsupported digest "{0}"'.format(
|
msg=f'Unsupported digest "{module.params["selfsigned_digest"]}"'
|
||||||
module.params["selfsigned_digest"]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
self.csr = csr.sign(self.privatekey, digest, default_backend())
|
self.csr = csr.sign(self.privatekey, digest, default_backend())
|
||||||
@@ -109,8 +105,7 @@ class SelfSignedCertificateBackendCryptography(CertificateBackend):
|
|||||||
if cryptography_key_needs_digest_for_signing(self.privatekey):
|
if cryptography_key_needs_digest_for_signing(self.privatekey):
|
||||||
if self.digest is None:
|
if self.digest is None:
|
||||||
raise CertificateError(
|
raise CertificateError(
|
||||||
"The digest %s is not supported with the cryptography backend"
|
f"The digest {module.params['selfsigned_digest']} is not supported with the cryptography backend"
|
||||||
% module.params["selfsigned_digest"]
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.digest = None
|
self.digest = None
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class CRLInfoRetrieval:
|
|||||||
else:
|
else:
|
||||||
self.crl = x509.load_der_x509_crl(self.content, default_backend())
|
self.crl = x509.load_der_x509_crl(self.content, default_backend())
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
self.module.fail_json(msg="Error while decoding CRL: {0}".format(e))
|
self.module.fail_json(msg=f"Error while decoding CRL: {e}")
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
"changed": False,
|
"changed": False,
|
||||||
@@ -96,9 +96,7 @@ class CRLInfoRetrieval:
|
|||||||
def get_crl_info(module, content, list_revoked_certificates=True):
|
def get_crl_info(module, content, list_revoked_certificates=True):
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"),
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
),
|
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ class CertificateSigningRequestBackend:
|
|||||||
if not self.subjectAltName and module.params["use_common_name_for_san"]:
|
if not self.subjectAltName and module.params["use_common_name_for_san"]:
|
||||||
for sub in self.subject:
|
for sub in self.subject:
|
||||||
if sub[0] in ("commonName", "CN"):
|
if sub[0] in ("commonName", "CN"):
|
||||||
self.subjectAltName = ["DNS:%s" % sub[1]]
|
self.subjectAltName = [f"DNS:{sub[1]}"]
|
||||||
self.using_common_name_for_san = True
|
self.using_common_name_for_san = True
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ class CertificateSigningRequestBackend:
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise CertificateSigningRequestError(
|
raise CertificateSigningRequestError(
|
||||||
"Cannot parse subject_key_identifier: {0}".format(e)
|
f"Cannot parse subject_key_identifier: {e}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.authority_key_identifier is not None:
|
if self.authority_key_identifier is not None:
|
||||||
@@ -184,7 +184,7 @@ class CertificateSigningRequestBackend:
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise CertificateSigningRequestError(
|
raise CertificateSigningRequestError(
|
||||||
"Cannot parse authority_key_identifier: {0}".format(e)
|
f"Cannot parse authority_key_identifier: {e}"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.existing_csr = None
|
self.existing_csr = None
|
||||||
@@ -337,9 +337,7 @@ def parse_crl_distribution_points(module, crl_distribution_points):
|
|||||||
result.append(cryptography.x509.DistributionPoint(**params))
|
result.append(cryptography.x509.DistributionPoint(**params))
|
||||||
except (OpenSSLObjectError, ValueError) as e:
|
except (OpenSSLObjectError, ValueError) as e:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
"Error while parsing CRL distribution point #{index}: {error}".format(
|
f"Error while parsing CRL distribution point #{index}: {e}"
|
||||||
index=index, error=e
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -446,9 +444,7 @@ class CertificateSigningRequestCryptographyBackend(CertificateSigningRequestBack
|
|||||||
critical=self.name_constraints_critical,
|
critical=self.name_constraints_critical,
|
||||||
)
|
)
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(f"Error while parsing name constraint: {e}")
|
||||||
"Error while parsing name constraint: {0}".format(e)
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.create_subject_key_identifier:
|
if self.create_subject_key_identifier:
|
||||||
csr = csr.add_extension(
|
csr = csr.add_extension(
|
||||||
@@ -494,7 +490,7 @@ class CertificateSigningRequestCryptographyBackend(CertificateSigningRequestBack
|
|||||||
digest = select_message_digest(self.digest)
|
digest = select_message_digest(self.digest)
|
||||||
if digest is None:
|
if digest is None:
|
||||||
raise CertificateSigningRequestError(
|
raise CertificateSigningRequestError(
|
||||||
'Unsupported digest "{0}"'.format(self.digest)
|
f'Unsupported digest "{self.digest}"'
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
self.csr = csr.sign(self.privatekey, digest, self.cryptography_backend)
|
self.csr = csr.sign(self.privatekey, digest, self.cryptography_backend)
|
||||||
@@ -518,7 +514,7 @@ class CertificateSigningRequestCryptographyBackend(CertificateSigningRequestBack
|
|||||||
# https://github.com/kjd/idna/commit/ebefacd3134d0f5da4745878620a6a1cba86d130
|
# https://github.com/kjd/idna/commit/ebefacd3134d0f5da4745878620a6a1cba86d130
|
||||||
# and then
|
# and then
|
||||||
# https://github.com/kjd/idna/commit/ea03c7b5db7d2a99af082e0239da2b68aeea702a).
|
# https://github.com/kjd/idna/commit/ea03c7b5db7d2a99af082e0239da2b68aeea702a).
|
||||||
msg = "Error while creating CSR: {0}\n".format(e)
|
msg = f"Error while creating CSR: {e}\n"
|
||||||
if self.using_common_name_for_san:
|
if self.using_common_name_for_san:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg=msg
|
msg=msg
|
||||||
@@ -813,23 +809,20 @@ def select_backend(module, backend):
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect any of the required Python libraries cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
|
||||||
"Cannot detect any of the required Python libraries "
|
|
||||||
"cryptography (>= {0})"
|
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
return backend, CertificateSigningRequestCryptographyBackend(module)
|
return backend, CertificateSigningRequestCryptographyBackend(module)
|
||||||
else:
|
else:
|
||||||
raise Exception("Unsupported value for backend: {0}".format(backend))
|
raise Exception(f"Unsupported value for backend: {backend}")
|
||||||
|
|
||||||
|
|
||||||
def get_csr_argument_spec():
|
def get_csr_argument_spec():
|
||||||
|
|||||||
@@ -258,9 +258,9 @@ class CSRInfoRetrievalCryptography(CSRInfoRetrieval):
|
|||||||
ext_keyusage_ext = self.csr.extensions.get_extension_for_class(
|
ext_keyusage_ext = self.csr.extensions.get_extension_for_class(
|
||||||
x509.BasicConstraints
|
x509.BasicConstraints
|
||||||
)
|
)
|
||||||
result = ["CA:{0}".format("TRUE" if ext_keyusage_ext.value.ca else "FALSE")]
|
result = [f"CA:{'TRUE' if ext_keyusage_ext.value.ca else 'FALSE'}"]
|
||||||
if ext_keyusage_ext.value.path_length is not None:
|
if ext_keyusage_ext.value.path_length is not None:
|
||||||
result.append("pathlen:{0}".format(ext_keyusage_ext.value.path_length))
|
result.append(f"pathlen:{ext_keyusage_ext.value.path_length}")
|
||||||
return sorted(result), ext_keyusage_ext.critical
|
return sorted(result), ext_keyusage_ext.critical
|
||||||
except cryptography.x509.ExtensionNotFound:
|
except cryptography.x509.ExtensionNotFound:
|
||||||
return None, False
|
return None, False
|
||||||
@@ -380,16 +380,14 @@ def select_backend(module, backend, content, validate_signature=True):
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect the required Python library cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
|
||||||
"Cannot detect the required Python library " "cryptography (>= {0})"
|
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
@@ -397,4 +395,4 @@ def select_backend(module, backend, content, validate_signature=True):
|
|||||||
module, content, validate_signature=validate_signature
|
module, content, validate_signature=validate_signature
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported value for backend: {0}".format(backend))
|
raise ValueError(f"Unsupported value for backend: {backend}")
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ class PrivateKeyCryptographyBackend(PrivateKeyBackend):
|
|||||||
ecclass = cryptography.hazmat.primitives.asymmetric.ec.__dict__.get(ectype)
|
ecclass = cryptography.hazmat.primitives.asymmetric.ec.__dict__.get(ectype)
|
||||||
if ecclass is None:
|
if ecclass is None:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Your cryptography version does not support {0}".format(ectype)
|
msg=f"Your cryptography version does not support {ectype}"
|
||||||
)
|
)
|
||||||
return ecclass
|
return ecclass
|
||||||
|
|
||||||
@@ -385,9 +385,7 @@ class PrivateKeyCryptographyBackend(PrivateKeyBackend):
|
|||||||
if self.type == "ECC" and self.curve in self.curves:
|
if self.type == "ECC" and self.curve in self.curves:
|
||||||
if self.curves[self.curve]["deprecated"]:
|
if self.curves[self.curve]["deprecated"]:
|
||||||
self.module.warn(
|
self.module.warn(
|
||||||
"Elliptic curves of type {0} should not be used for new keys!".format(
|
f"Elliptic curves of type {self.curve} should not be used for new keys!"
|
||||||
self.curve
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
self.private_key = (
|
self.private_key = (
|
||||||
cryptography.hazmat.primitives.asymmetric.ec.generate_private_key(
|
cryptography.hazmat.primitives.asymmetric.ec.generate_private_key(
|
||||||
@@ -397,9 +395,7 @@ class PrivateKeyCryptographyBackend(PrivateKeyBackend):
|
|||||||
)
|
)
|
||||||
except cryptography.exceptions.UnsupportedAlgorithm:
|
except cryptography.exceptions.UnsupportedAlgorithm:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Cryptography backend does not support the algorithm required for {0}".format(
|
msg=f"Cryptography backend does not support the algorithm required for {self.type}"
|
||||||
self.type
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_private_key_data(self):
|
def get_private_key_data(self):
|
||||||
@@ -426,9 +422,7 @@ class PrivateKeyCryptographyBackend(PrivateKeyBackend):
|
|||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg='Cryptography backend does not support the selected output format "{0}"'.format(
|
msg=f'Cryptography backend does not support the selected output format "{self.format}"'
|
||||||
self.format
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Select key encryption
|
# Select key encryption
|
||||||
@@ -454,15 +448,11 @@ class PrivateKeyCryptographyBackend(PrivateKeyBackend):
|
|||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg='Cryptography backend cannot serialize the private key in the required format "{0}"'.format(
|
msg=f'Cryptography backend cannot serialize the private key in the required format "{self.format}"'
|
||||||
self.format
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg='Error while serializing the private key in the required format "{0}"'.format(
|
msg=f'Error while serializing the private key in the required format "{self.format}"',
|
||||||
self.format
|
|
||||||
),
|
|
||||||
exception=traceback.format_exc(),
|
exception=traceback.format_exc(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -611,21 +601,19 @@ def select_backend(module, backend):
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect the required Python library cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
|
||||||
"Cannot detect the required Python library " "cryptography (>= {0})"
|
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
)
|
)
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
return backend, PrivateKeyCryptographyBackend(module)
|
return backend, PrivateKeyCryptographyBackend(module)
|
||||||
else:
|
else:
|
||||||
raise Exception("Unsupported value for backend: {0}".format(backend))
|
raise Exception(f"Unsupported value for backend: {backend}")
|
||||||
|
|
||||||
|
|
||||||
def get_privatekey_argument_spec():
|
def get_privatekey_argument_spec():
|
||||||
|
|||||||
@@ -161,9 +161,7 @@ class PrivateKeyConvertCryptographyBackend(PrivateKeyConvertBackend):
|
|||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg='Cryptography backend does not support the selected output format "{0}"'.format(
|
msg=f'Cryptography backend does not support the selected output format "{self.format}"'
|
||||||
self.format
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Select key encryption
|
# Select key encryption
|
||||||
@@ -186,15 +184,11 @@ class PrivateKeyConvertCryptographyBackend(PrivateKeyConvertBackend):
|
|||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg='Cryptography backend cannot serialize the private key in the required format "{0}"'.format(
|
msg=f'Cryptography backend cannot serialize the private key in the required format "{self.format}"'
|
||||||
self.format
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg='Error while serializing the private key in the required format "{0}"'.format(
|
msg=f'Error while serializing the private key in the required format "{self.format}"',
|
||||||
self.format
|
|
||||||
),
|
|
||||||
exception=traceback.format_exc(),
|
exception=traceback.format_exc(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -285,9 +279,7 @@ class PrivateKeyConvertCryptographyBackend(PrivateKeyConvertBackend):
|
|||||||
def select_backend(module):
|
def select_backend(module):
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"),
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
),
|
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
return PrivateKeyConvertCryptographyBackend(module)
|
return PrivateKeyConvertCryptographyBackend(module)
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ def _is_cryptography_key_consistent(
|
|||||||
return False
|
return False
|
||||||
# For X25519 and X448, there's no test yet.
|
# For X25519 and X448, there's no test yet.
|
||||||
if warn_func is not None:
|
if warn_func is not None:
|
||||||
warn_func("Cannot determine consistency for key of type %s" % type(key))
|
warn_func(f"Cannot determine consistency for key of type {type(key)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -338,16 +338,14 @@ def select_backend(
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect the required Python library cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
|
||||||
"Cannot detect the required Python library " "cryptography (>= {0})"
|
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
@@ -359,4 +357,4 @@ def select_backend(
|
|||||||
check_consistency=check_consistency,
|
check_consistency=check_consistency,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported value for backend: {0}".format(backend))
|
raise ValueError(f"Unsupported value for backend: {backend}")
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ def _get_cryptography_public_key_info(key):
|
|||||||
key_public_data["y"] = public_numbers.y
|
key_public_data["y"] = public_numbers.y
|
||||||
key_public_data["exponent_size"] = key.curve.key_size
|
key_public_data["exponent_size"] = key.curve.key_size
|
||||||
else:
|
else:
|
||||||
key_type = "unknown ({0})".format(type(key))
|
key_type = f"unknown ({type(key)})"
|
||||||
return key_type, key_public_data
|
return key_type, key_public_data
|
||||||
|
|
||||||
|
|
||||||
@@ -174,17 +174,14 @@ def select_backend(module, backend, content=None, key=None):
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect any of the required Python libraries cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
|
||||||
"Cannot detect any of the required Python libraries "
|
|
||||||
"cryptography (>= {0})"
|
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
@@ -192,4 +189,4 @@ def select_backend(module, backend, content=None, key=None):
|
|||||||
module, content=content, key=key
|
module, content=content, key=key
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported value for backend: {0}".format(backend))
|
raise ValueError(f"Unsupported value for backend: {backend}")
|
||||||
|
|||||||
@@ -98,36 +98,24 @@ def _extract_type(line, start=PEM_START):
|
|||||||
def extract_pem(content, strict=False):
|
def extract_pem(content, strict=False):
|
||||||
lines = content.splitlines()
|
lines = content.splitlines()
|
||||||
if len(lines) < 3:
|
if len(lines) < 3:
|
||||||
raise ValueError(
|
raise ValueError(f"PEM must have at least 3 lines, have only {len(lines)}")
|
||||||
"PEM must have at least 3 lines, have only {count}".format(count=len(lines))
|
|
||||||
)
|
|
||||||
header_type = _extract_type(lines[0])
|
header_type = _extract_type(lines[0])
|
||||||
if header_type is None:
|
if header_type is None:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"First line is not of format {start}...{end}: {line!r}".format(
|
f"First line is not of format {PEM_START}...{PEM_END}: {lines[0]!r}"
|
||||||
start=PEM_START, end=PEM_END, line=lines[0]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
footer_type = _extract_type(lines[-1], start=PEM_END_START)
|
footer_type = _extract_type(lines[-1], start=PEM_END_START)
|
||||||
if strict:
|
if strict:
|
||||||
if header_type != footer_type:
|
if header_type != footer_type:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Header type ({header}) is different from footer type ({footer})".format(
|
f"Header type ({header_type}) is different from footer type ({footer_type})"
|
||||||
header=header_type, footer=footer_type
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
for idx, line in enumerate(lines[1:-2]):
|
for idx, line in enumerate(lines[1:-2]):
|
||||||
if len(line) != 64:
|
if len(line) != 64:
|
||||||
raise ValueError(
|
raise ValueError(f"Line {idx} has length {len(line)} instead of 64")
|
||||||
"Line {idx} has length {len} instead of 64".format(
|
|
||||||
idx=idx, len=len(line)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if not (0 < len(lines[-2]) <= 64):
|
if not (0 < len(lines[-2]) <= 64):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Last line has length {len}, should be in (0, 64]".format(
|
f"Last line has length {len(lines[-2])}, should be in (0, 64]"
|
||||||
len=len(lines[-2])
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
content = lines[1:-1]
|
content = lines[1:-1]
|
||||||
return header_type, "".join(content)
|
return header_type, "".join(content)
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ def load_publickey(path=None, content=None, backend=None):
|
|||||||
content, backend=cryptography_backend()
|
content, backend=cryptography_backend()
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise OpenSSLObjectError("Error while deserializing key: {0}".format(e))
|
raise OpenSSLObjectError(f"Error while deserializing key: {e}")
|
||||||
|
|
||||||
|
|
||||||
def load_certificate(
|
def load_certificate(
|
||||||
@@ -209,9 +209,7 @@ def load_certificate(
|
|||||||
cert_content, cryptography_backend()
|
cert_content, cryptography_backend()
|
||||||
)
|
)
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(f"Cannot parse DER certificate: {exc}")
|
||||||
"Cannot parse DER certificate: {0}".format(exc)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def load_certificate_request(path, content=None, backend="cryptography"):
|
def load_certificate_request(path, content=None, backend="cryptography"):
|
||||||
@@ -241,31 +239,30 @@ def parse_name_field(input_dict, name_field_name=None):
|
|||||||
for entry in value:
|
for entry in value:
|
||||||
if not isinstance(entry, six.string_types):
|
if not isinstance(entry, six.string_types):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
("Values %s must be strings" % error_str).format(
|
f"Values {error_str} must be strings".format(
|
||||||
key=key, name=name_field_name
|
key=key, name=name_field_name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if not entry:
|
if not entry:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
("Values for %s must not be empty strings" % error_str).format(
|
f"Values for {error_str} must not be empty strings".format(
|
||||||
key=key
|
key=key, name=name_field_name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result.append((key, entry))
|
result.append((key, entry))
|
||||||
elif isinstance(value, six.string_types):
|
elif isinstance(value, six.string_types):
|
||||||
if not value:
|
if not value:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
("Value for %s must not be an empty string" % error_str).format(
|
f"Value for {error_str} must not be an empty string".format(
|
||||||
key=key
|
key=key, name=name_field_name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result.append((key, value))
|
result.append((key, value))
|
||||||
else:
|
else:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
(
|
(
|
||||||
"Value for %s must be either a string or a list of strings"
|
f"Value for {error_str} must be either a string or a list of strings"
|
||||||
% error_str
|
).format(key=key, name=name_field_name)
|
||||||
).format(key=key)
|
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -277,17 +274,13 @@ def parse_ordered_name_field(input_list, name_field_name):
|
|||||||
for index, entry in enumerate(input_list):
|
for index, entry in enumerate(input_list):
|
||||||
if len(entry) != 1:
|
if len(entry) != 1:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Entry #{index} in {name} must be a dictionary with exactly one key-value pair".format(
|
f"Entry #{index + 1} in {name_field_name} must be a dictionary with exactly one key-value pair"
|
||||||
name=name_field_name, index=index + 1
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
result.extend(parse_name_field(entry, name_field_name=name_field_name))
|
result.extend(parse_name_field(entry, name_field_name=name_field_name))
|
||||||
except (TypeError, ValueError) as exc:
|
except (TypeError, ValueError) as exc:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Error while processing entry #{index} in {name}: {error}".format(
|
f"Error while processing entry #{index + 1} in {name_field_name}: {exc}"
|
||||||
name=name_field_name, index=index + 1, error=exc
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -73,12 +73,8 @@ def generate_docstring(operation_spec):
|
|||||||
if len(parameters) != 0:
|
if len(parameters) != 0:
|
||||||
docs += "\tArguments:\n\n"
|
docs += "\tArguments:\n\n"
|
||||||
for parameter in parameters:
|
for parameter in parameters:
|
||||||
docs += "{0} ({1}:{2}): {3}\n".format(
|
req = "Required" if parameter.get("required", False) else "Not Required"
|
||||||
parameter.get("name"),
|
docs += f"{parameter.get('name')} ({parameter.get('type', 'No Type')}:{req}): {parameter.get('description')}\n"
|
||||||
parameter.get("type", "No Type"),
|
|
||||||
"Required" if parameter.get("required", False) else "Not Required",
|
|
||||||
parameter.get("description"),
|
|
||||||
)
|
|
||||||
|
|
||||||
return docs
|
return docs
|
||||||
|
|
||||||
@@ -104,11 +100,8 @@ class RestOperation:
|
|||||||
self.parameters = {}
|
self.parameters = {}
|
||||||
else:
|
else:
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
self.url = "{scheme}://{host}{base_path}{uri}".format(
|
self.url = (
|
||||||
scheme="https",
|
f"https://{session._spec.get('host')}{session._spec.get('basePath')}{uri}"
|
||||||
host=session._spec.get("host"),
|
|
||||||
base_path=session._spec.get("basePath"),
|
|
||||||
uri=uri,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def restmethod(self, *args, **kwargs):
|
def restmethod(self, *args, **kwargs):
|
||||||
@@ -204,7 +197,7 @@ class Resource:
|
|||||||
operation_name = "Patch"
|
operation_name = "Patch"
|
||||||
else:
|
else:
|
||||||
raise SessionConfigurationException(
|
raise SessionConfigurationException(
|
||||||
to_native("Invalid REST method type {0}".format(method))
|
to_native(f"Invalid REST method type {method}")
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get the non-parameter parts of the URL and append to the operation name
|
# Get the non-parameter parts of the URL and append to the operation name
|
||||||
@@ -286,9 +279,7 @@ class ECSSession:
|
|||||||
):
|
):
|
||||||
raise SessionConfigurationException(
|
raise SessionConfigurationException(
|
||||||
to_native(
|
to_native(
|
||||||
"OpenAPI specification was not found at location {0}.".format(
|
f"OpenAPI specification was not found at location {entrust_api_specification_path}."
|
||||||
entrust_api_specification_path
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if not valid_file_format.match(entrust_api_specification_path):
|
if not valid_file_format.match(entrust_api_specification_path):
|
||||||
@@ -315,9 +306,7 @@ class ECSSession:
|
|||||||
except HTTPError as e:
|
except HTTPError as e:
|
||||||
raise SessionConfigurationException(
|
raise SessionConfigurationException(
|
||||||
to_native(
|
to_native(
|
||||||
"Error downloading specification from address '{0}', received error code '{1}'".format(
|
f"Error downloading specification from address '{entrust_api_specification_path}', received error code '{e.getcode()}'"
|
||||||
entrust_api_specification_path, e.getcode()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -344,9 +333,8 @@ class ECSSession:
|
|||||||
):
|
):
|
||||||
raise SessionConfigurationException(
|
raise SessionConfigurationException(
|
||||||
to_native(
|
to_native(
|
||||||
"Parameter provided for entrust_api_specification_path of value '{0}' was not a valid file path or HTTPS address.".format(
|
f"Parameter provided for entrust_api_specification_path of value '{entrust_api_specification_path}'"
|
||||||
entrust_api_specification_path
|
" was not a valid file path or HTTPS address."
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -355,18 +343,14 @@ class ECSSession:
|
|||||||
if not file_path or not os.path.isfile(file_path):
|
if not file_path or not os.path.isfile(file_path):
|
||||||
raise SessionConfigurationException(
|
raise SessionConfigurationException(
|
||||||
to_native(
|
to_native(
|
||||||
"Parameter provided for {0} of value '{1}' was not a valid file path.".format(
|
f"Parameter provided for {required_file} of value '{file_path}' was not a valid file path."
|
||||||
required_file, file_path
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
for required_var in ["entrust_api_user", "entrust_api_key"]:
|
for required_var in ["entrust_api_user", "entrust_api_key"]:
|
||||||
if not kwargs.get(required_var):
|
if not kwargs.get(required_var):
|
||||||
raise SessionConfigurationException(
|
raise SessionConfigurationException(
|
||||||
to_native(
|
to_native(f"Parameter provided for {required_var} was missing.")
|
||||||
"Parameter provided for {0} was missing.".format(required_var)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
config["entrust_api_cert"] = kwargs.get("entrust_api_cert")
|
config["entrust_api_cert"] = kwargs.get("entrust_api_cert")
|
||||||
|
|||||||
@@ -39,19 +39,15 @@ def get_fingerprint_from_stdout(stdout):
|
|||||||
parts = line.split(":")
|
parts = line.split(":")
|
||||||
if len(parts) <= 9 or not parts[9]:
|
if len(parts) <= 9 or not parts[9]:
|
||||||
raise GPGError(
|
raise GPGError(
|
||||||
'Result line "{line}" does not have fingerprint as 10th component'.format(
|
f'Result line "{line}" does not have fingerprint as 10th component'
|
||||||
line=line
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return parts[9]
|
return parts[9]
|
||||||
raise GPGError(
|
raise GPGError(f'Cannot extract fingerprint from stdout "{stdout}"')
|
||||||
'Cannot extract fingerprint from stdout "{stdout}"'.format(stdout=stdout)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_fingerprint_from_file(gpg_runner, path):
|
def get_fingerprint_from_file(gpg_runner, path):
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise GPGError("{path} does not exist".format(path=path))
|
raise GPGError(f"{path} does not exist")
|
||||||
stdout = gpg_runner.run_command(
|
stdout = gpg_runner.run_command(
|
||||||
[
|
[
|
||||||
"--no-keyring",
|
"--no-keyring",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ def load_file(path, module=None):
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
if module is None:
|
if module is None:
|
||||||
raise
|
raise
|
||||||
module.fail_json("Error while loading {0} - {1}".format(path, str(exc)))
|
module.fail_json(f"Error while loading {path} - {exc}")
|
||||||
|
|
||||||
|
|
||||||
def load_file_if_exists(path, module=None, ignore_errors=False):
|
def load_file_if_exists(path, module=None, ignore_errors=False):
|
||||||
@@ -40,13 +40,13 @@ def load_file_if_exists(path, module=None, ignore_errors=False):
|
|||||||
return None
|
return None
|
||||||
if module is None:
|
if module is None:
|
||||||
raise
|
raise
|
||||||
module.fail_json("Error while loading {0} - {1}".format(path, str(exc)))
|
module.fail_json(f"Error while loading {path} - {exc}")
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
if ignore_errors:
|
if ignore_errors:
|
||||||
return None
|
return None
|
||||||
if module is None:
|
if module is None:
|
||||||
raise
|
raise
|
||||||
module.fail_json("Error while loading {0} - {1}".format(path, str(exc)))
|
module.fail_json(f"Error while loading {path} - {exc}")
|
||||||
|
|
||||||
|
|
||||||
def write_file(module, content, default_mode=None, path=None):
|
def write_file(module, content, default_mode=None, path=None):
|
||||||
@@ -83,9 +83,7 @@ def write_file(module, content, default_mode=None, path=None):
|
|||||||
os.remove(tmp_name)
|
os.remove(tmp_name)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Error while writing result into temporary file: {e}")
|
||||||
msg="Error while writing result into temporary file: {0}".format(e)
|
|
||||||
)
|
|
||||||
# Update destination to wanted permissions
|
# Update destination to wanted permissions
|
||||||
if os.path.exists(file_args["path"]):
|
if os.path.exists(file_args["path"]):
|
||||||
module.set_fs_attributes_if_different(file_args, False)
|
module.set_fs_attributes_if_different(file_args, False)
|
||||||
@@ -101,4 +99,4 @@ def write_file(module, content, default_mode=None, path=None):
|
|||||||
os.remove(tmp_name)
|
os.remove(tmp_name)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
module.fail_json(msg="Error while writing result: {0}".format(e))
|
module.fail_json(msg=f"Error while writing result: {e}")
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class OpensshModule:
|
|||||||
self._execute()
|
self._execute()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="unexpected error occurred: %s" % to_native(e),
|
msg=f"unexpected error occurred: {to_native(e)}",
|
||||||
exception=traceback.format_exc(),
|
exception=traceback.format_exc(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -125,8 +125,7 @@ class OpensshModule:
|
|||||||
if not os.path.isdir(base_dir):
|
if not os.path.isdir(base_dir):
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
name=base_dir,
|
name=base_dir,
|
||||||
msg="The directory %s does not exist or the file is not a directory"
|
msg=f"The directory {base_dir} does not exist or the file is not a directory",
|
||||||
% base_dir,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_ssh_version(self):
|
def _get_ssh_version(self):
|
||||||
@@ -253,8 +252,7 @@ class KeygenCommand:
|
|||||||
os.chmod(private_key_path, stat.S_IWUSR + stat.S_IRUSR)
|
os.chmod(private_key_path, stat.S_IWUSR + stat.S_IRUSR)
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
raise e(
|
raise e(
|
||||||
"The private key at %s is not writeable preventing a comment update"
|
f"The private key at {private_key_path} is not writeable preventing a comment update"
|
||||||
% private_key_path
|
|
||||||
)
|
)
|
||||||
|
|
||||||
command = [self._bin_path, "-q"]
|
command = [self._bin_path, "-q"]
|
||||||
@@ -332,7 +330,7 @@ class PublicKey:
|
|||||||
return not self == other
|
return not self == other
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s %s" % (self._type_string, self._data)
|
return f"{self._type_string} {self._data}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def comment(self):
|
def comment(self):
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class KeypairBackend(OpensshModule):
|
|||||||
result = 256
|
result = 256
|
||||||
else:
|
else:
|
||||||
return self.module.fail_json(
|
return self.module.fail_json(
|
||||||
msg="%s is not a valid value for key type" % self.type
|
msg=f"{self.type} is not a valid value for key type"
|
||||||
)
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -100,8 +100,7 @@ class KeypairBackend(OpensshModule):
|
|||||||
|
|
||||||
if os.path.isdir(self.private_key_path):
|
if os.path.isdir(self.private_key_path):
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="%s is a directory. Please specify a path to a file."
|
msg=f"{self.private_key_path} is a directory. Please specify a path to a file."
|
||||||
% self.private_key_path
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _execute(self):
|
def _execute(self):
|
||||||
@@ -562,4 +561,4 @@ def select_backend(module, backend):
|
|||||||
module.fail_json(msg=missing_required_lib("cryptography >= 2.6"))
|
module.fail_json(msg=missing_required_lib("cryptography >= 2.6"))
|
||||||
return backend, KeypairBackendCryptography(module)
|
return backend, KeypairBackendCryptography(module)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported value for backend: {0}".format(backend))
|
raise ValueError(f"Unsupported value for backend: {backend}")
|
||||||
|
|||||||
@@ -110,8 +110,7 @@ class OpensshCertificateTimeParameters:
|
|||||||
|
|
||||||
if self._valid_from > self._valid_to:
|
if self._valid_from > self._valid_to:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Valid from: %s must not be greater than Valid to: %s"
|
f"Valid from: {valid_from} must not be greater than Valid to: {valid_to}"
|
||||||
% (valid_from, valid_to)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
@@ -129,10 +128,7 @@ class OpensshCertificateTimeParameters:
|
|||||||
@property
|
@property
|
||||||
def validity_string(self):
|
def validity_string(self):
|
||||||
if not (self._valid_from == _ALWAYS and self._valid_to == _FOREVER):
|
if not (self._valid_from == _ALWAYS and self._valid_to == _FOREVER):
|
||||||
return "%s:%s" % (
|
return f"{self.valid_from(date_format='openssh')}:{self.valid_to(date_format='openssh')}"
|
||||||
self.valid_from(date_format="openssh"),
|
|
||||||
self.valid_to(date_format="openssh"),
|
|
||||||
)
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def valid_from(self, date_format):
|
def valid_from(self, date_format):
|
||||||
@@ -166,7 +162,7 @@ class OpensshCertificateTimeParameters:
|
|||||||
(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
|
(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError("%s is not a valid format" % date_format)
|
raise ValueError(f"{date_format} is not a valid format")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -182,8 +178,7 @@ class OpensshCertificateTimeParameters:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Value must be of type (str, unicode, int, long) not %s"
|
f"Value must be of type (str, unicode, int, long) not {type(time_string_or_timestamp)}"
|
||||||
% type(time_string_or_timestamp)
|
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise
|
raise
|
||||||
@@ -238,10 +233,10 @@ class OpensshCertificateOption:
|
|||||||
raise ValueError("type must be either 'critical' or 'extension'")
|
raise ValueError("type must be either 'critical' or 'extension'")
|
||||||
|
|
||||||
if not isinstance(name, six.string_types):
|
if not isinstance(name, six.string_types):
|
||||||
raise TypeError("name must be a string not %s" % type(name))
|
raise TypeError(f"name must be a string not {type(name)}")
|
||||||
|
|
||||||
if not isinstance(data, six.string_types):
|
if not isinstance(data, six.string_types):
|
||||||
raise TypeError("data must be a string not %s" % type(data))
|
raise TypeError(f"data must be a string not {type(data)}")
|
||||||
|
|
||||||
self._option_type = option_type
|
self._option_type = option_type
|
||||||
self._name = name.lower()
|
self._name = name.lower()
|
||||||
@@ -267,7 +262,7 @@ class OpensshCertificateOption:
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self._data:
|
if self._data:
|
||||||
return "%s=%s" % (self._name, self._data)
|
return f"{self._name}={self._data}"
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -286,7 +281,7 @@ class OpensshCertificateOption:
|
|||||||
def from_string(cls, option_string):
|
def from_string(cls, option_string):
|
||||||
if not isinstance(option_string, six.string_types):
|
if not isinstance(option_string, six.string_types):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"option_string must be a string not %s" % type(option_string)
|
f"option_string must be a string not {type(option_string)}"
|
||||||
)
|
)
|
||||||
option_type = None
|
option_type = None
|
||||||
|
|
||||||
@@ -356,7 +351,7 @@ class OpensshCertificateInfo:
|
|||||||
elif cert_type == "host" or cert_type == _HOST_TYPE:
|
elif cert_type == "host" or cert_type == _HOST_TYPE:
|
||||||
self._cert_type = _HOST_TYPE
|
self._cert_type = _HOST_TYPE
|
||||||
else:
|
else:
|
||||||
raise ValueError("%s is not a valid certificate type" % cert_type)
|
raise ValueError(f"{cert_type} is not a valid certificate type")
|
||||||
|
|
||||||
def signing_key_fingerprint(self):
|
def signing_key_fingerprint(self):
|
||||||
return fingerprint(self.signing_key)
|
return fingerprint(self.signing_key)
|
||||||
@@ -447,8 +442,7 @@ class OpensshECDSACertificateInfo(OpensshCertificateInfo):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Curve must be one of %s"
|
"Curve must be one of {(b','.join(_ECDSA_CURVE_IDENTIFIERS.values())).decode('UTF-8')}"
|
||||||
% (b",".join(list(_ECDSA_CURVE_IDENTIFIERS.values()))).decode("UTF-8")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# See https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
|
# See https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
|
||||||
@@ -500,13 +494,13 @@ class OpensshCertificate:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, path):
|
def load(cls, path):
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise ValueError("%s is not a valid path." % path)
|
raise ValueError(f"{path} is not a valid path.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(path, "rb") as cert_file:
|
with open(path, "rb") as cert_file:
|
||||||
data = cert_file.read()
|
data = cert_file.read()
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
raise ValueError("%s cannot be opened for reading: %s" % (path, e))
|
raise ValueError(f"{path} cannot be opened for reading: {e}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
format_identifier, b64_cert = data.split(b" ")[:2]
|
format_identifier, b64_cert = data.split(b" ")[:2]
|
||||||
@@ -520,7 +514,7 @@ class OpensshCertificate:
|
|||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Invalid certificate format identifier: %s" % format_identifier
|
f"Invalid certificate format identifier: {format_identifier}"
|
||||||
)
|
)
|
||||||
|
|
||||||
parser = OpensshParser(cert)
|
parser = OpensshParser(cert)
|
||||||
@@ -532,12 +526,11 @@ class OpensshCertificate:
|
|||||||
cert_info = cls._parse_cert_info(pub_key_type, parser)
|
cert_info = cls._parse_cert_info(pub_key_type, parser)
|
||||||
signature = parser.string()
|
signature = parser.string()
|
||||||
except (TypeError, ValueError) as e:
|
except (TypeError, ValueError) as e:
|
||||||
raise ValueError("Invalid certificate data: %s" % e)
|
raise ValueError(f"Invalid certificate data: {e}")
|
||||||
|
|
||||||
if parser.remaining_bytes():
|
if parser.remaining_bytes():
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"%s bytes of additional data was not parsed while loading %s"
|
f"{parser.remaining_bytes()} bytes of additional data was not parsed while loading {path}"
|
||||||
% (parser.remaining_bytes(), path)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
@@ -651,7 +644,7 @@ class OpensshCertificate:
|
|||||||
|
|
||||||
def apply_directives(directives):
|
def apply_directives(directives):
|
||||||
if any(d not in _DIRECTIVES for d in directives):
|
if any(d not in _DIRECTIVES for d in directives):
|
||||||
raise ValueError("directives must be one of %s" % ", ".join(_DIRECTIVES))
|
raise ValueError(f"directives must be one of {', '.join(_DIRECTIVES)}")
|
||||||
|
|
||||||
directive_to_option = {
|
directive_to_option = {
|
||||||
"no-x11-forwarding": OpensshCertificateOption(
|
"no-x11-forwarding": OpensshCertificateOption(
|
||||||
@@ -696,7 +689,7 @@ def get_cert_info_object(key_type):
|
|||||||
elif key_type == "ed25519":
|
elif key_type == "ed25519":
|
||||||
cert_info = OpensshED25519CertificateInfo()
|
cert_info = OpensshED25519CertificateInfo()
|
||||||
else:
|
else:
|
||||||
raise ValueError("%s is not a valid key type" % key_type)
|
raise ValueError(f"{key_type} is not a valid key type")
|
||||||
|
|
||||||
return cert_info
|
return cert_info
|
||||||
|
|
||||||
@@ -708,8 +701,8 @@ def get_option_type(name):
|
|||||||
result = "extension"
|
result = "extension"
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"%s is not a valid option. " % name
|
f"{name} is not a valid option. "
|
||||||
+ "Custom options must start with 'critical:' or 'extension:' to indicate type"
|
"Custom options must start with 'critical:' or 'extension:' to indicate type"
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -137,8 +137,7 @@ class AsymmetricKeypair:
|
|||||||
|
|
||||||
if keytype not in _ALGORITHM_PARAMETERS.keys():
|
if keytype not in _ALGORITHM_PARAMETERS.keys():
|
||||||
raise InvalidKeyTypeError(
|
raise InvalidKeyTypeError(
|
||||||
"%s is not a valid keytype. Valid keytypes are %s"
|
f"{keytype} is not a valid keytype. Valid keytypes are {', '.join(_ALGORITHM_PARAMETERS)}"
|
||||||
% (keytype, ", ".join(_ALGORITHM_PARAMETERS.keys()))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not size:
|
if not size:
|
||||||
@@ -146,7 +145,7 @@ class AsymmetricKeypair:
|
|||||||
else:
|
else:
|
||||||
if size not in _ALGORITHM_PARAMETERS[keytype]["valid_sizes"]:
|
if size not in _ALGORITHM_PARAMETERS[keytype]["valid_sizes"]:
|
||||||
raise InvalidKeySizeError(
|
raise InvalidKeySizeError(
|
||||||
"%s is not a valid key size for %s keys" % (size, keytype)
|
f"{size} is not a valid key size for {keytype} keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
if passphrase:
|
if passphrase:
|
||||||
@@ -229,9 +228,7 @@ class AsymmetricKeypair:
|
|||||||
elif isinstance(privatekey, Ed25519PrivateKey):
|
elif isinstance(privatekey, Ed25519PrivateKey):
|
||||||
keytype = "ed25519"
|
keytype = "ed25519"
|
||||||
else:
|
else:
|
||||||
raise InvalidKeyTypeError(
|
raise InvalidKeyTypeError(f"Key type '{type(privatekey)}' is not supported")
|
||||||
"Key type '%s' is not supported" % type(privatekey)
|
|
||||||
)
|
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
keytype=keytype,
|
keytype=keytype,
|
||||||
@@ -363,7 +360,7 @@ class OpensshKeypair:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if comment is None:
|
if comment is None:
|
||||||
comment = "%s@%s" % (getuser(), gethostname())
|
comment = f"{getuser()}@{gethostname()}"
|
||||||
|
|
||||||
asym_keypair = AsymmetricKeypair.generate(keytype, size, passphrase)
|
asym_keypair = AsymmetricKeypair.generate(keytype, size, passphrase)
|
||||||
openssh_privatekey = cls.encode_openssh_privatekey(asym_keypair, "SSH")
|
openssh_privatekey = cls.encode_openssh_privatekey(asym_keypair, "SSH")
|
||||||
@@ -457,7 +454,7 @@ class OpensshKeypair:
|
|||||||
validate_comment(comment)
|
validate_comment(comment)
|
||||||
|
|
||||||
encoded_publickey += (
|
encoded_publickey += (
|
||||||
(" %s" % comment).encode(encoding=_TEXT_ENCODING) if comment else b""
|
f" {comment}".encode(encoding=_TEXT_ENCODING) if comment else b""
|
||||||
)
|
)
|
||||||
|
|
||||||
return encoded_publickey
|
return encoded_publickey
|
||||||
@@ -541,7 +538,7 @@ class OpensshKeypair:
|
|||||||
|
|
||||||
self.__comment = comment
|
self.__comment = comment
|
||||||
encoded_comment = (
|
encoded_comment = (
|
||||||
(" %s" % self.__comment).encode(encoding=_TEXT_ENCODING)
|
f" {self.__comment}".encode(encoding=_TEXT_ENCODING)
|
||||||
if self.__comment
|
if self.__comment
|
||||||
else b""
|
else b""
|
||||||
)
|
)
|
||||||
@@ -578,12 +575,11 @@ def load_privatekey(path, passphrase, key_format):
|
|||||||
privatekey_loader = privatekey_loaders[key_format]
|
privatekey_loader = privatekey_loaders[key_format]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise InvalidKeyFormatError(
|
raise InvalidKeyFormatError(
|
||||||
"%s is not a valid key format (%s)"
|
f"{key_format} is not a valid key format ({','.join(privatekey_loaders)})"
|
||||||
% (key_format, ",".join(privatekey_loaders.keys()))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise InvalidPrivateKeyFileError("No file was found at %s" % path)
|
raise InvalidPrivateKeyFileError(f"No file was found at {path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(path, "rb") as f:
|
with open(path, "rb") as f:
|
||||||
@@ -631,12 +627,11 @@ def load_publickey(path, key_format):
|
|||||||
publickey_loader = publickey_loaders[key_format]
|
publickey_loader = publickey_loaders[key_format]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise InvalidKeyFormatError(
|
raise InvalidKeyFormatError(
|
||||||
"%s is not a valid key format (%s)"
|
f"{key_format} is not a valid key format ({','.join(publickey_loaders)})"
|
||||||
% (key_format, ",".join(publickey_loaders.keys()))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise InvalidPublicKeyFileError("No file was found at %s" % path)
|
raise InvalidPublicKeyFileError(f"No file was found at {path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(path, "rb") as f:
|
with open(path, "rb") as f:
|
||||||
@@ -689,13 +684,13 @@ def get_encryption_algorithm(passphrase):
|
|||||||
|
|
||||||
def validate_comment(comment):
|
def validate_comment(comment):
|
||||||
if not hasattr(comment, "encode"):
|
if not hasattr(comment, "encode"):
|
||||||
raise InvalidCommentError("%s cannot be encoded to text" % comment)
|
raise InvalidCommentError(f"{comment} cannot be encoded to text")
|
||||||
|
|
||||||
|
|
||||||
def extract_comment(path):
|
def extract_comment(path):
|
||||||
|
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise InvalidPublicKeyFileError("No file was found at %s" % path)
|
raise InvalidPublicKeyFileError(f"No file was found at {path}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(path, "rb") as f:
|
with open(path, "rb") as f:
|
||||||
@@ -715,6 +710,5 @@ def calculate_fingerprint(openssh_publickey):
|
|||||||
decoded_pubkey = b64decode(openssh_publickey.split(b" ")[1])
|
decoded_pubkey = b64decode(openssh_publickey.split(b" ")[1])
|
||||||
digest.update(decoded_pubkey)
|
digest.update(decoded_pubkey)
|
||||||
|
|
||||||
return "SHA256:%s" % b64encode(digest.finalize()).decode(
|
value = b64encode(digest.finalize()).decode(encoding=_TEXT_ENCODING).rstrip("=")
|
||||||
encoding=_TEXT_ENCODING
|
return f"SHA256:{value}"
|
||||||
).rstrip("=")
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class OpensshParser:
|
|||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
if not isinstance(data, (bytes, bytearray)):
|
if not isinstance(data, (bytes, bytearray)):
|
||||||
raise TypeError("Data must be bytes-like not %s" % type(data))
|
raise TypeError(f"Data must be bytes-like not {type(data)}")
|
||||||
|
|
||||||
self._data = memoryview(data) if PY3 else data
|
self._data = memoryview(data) if PY3 else data
|
||||||
self._pos = 0
|
self._pos = 0
|
||||||
@@ -174,7 +174,7 @@ class OpensshParser:
|
|||||||
|
|
||||||
def _check_position(self, offset):
|
def _check_position(self, offset):
|
||||||
if self._pos + offset > len(self._data):
|
if self._pos + offset > len(self._data):
|
||||||
raise ValueError("Insufficient data remaining at position: %s" % self._pos)
|
raise ValueError(f"Insufficient data remaining at position: {self._pos}")
|
||||||
elif self._pos + offset < 0:
|
elif self._pos + offset < 0:
|
||||||
raise ValueError("Position cannot be less than zero.")
|
raise ValueError("Position cannot be less than zero.")
|
||||||
else:
|
else:
|
||||||
@@ -210,7 +210,7 @@ class OpensshParser:
|
|||||||
signature_data["R"] = cls._big_int(signature_blob[:32], "little")
|
signature_data["R"] = cls._big_int(signature_blob[:32], "little")
|
||||||
signature_data["S"] = cls._big_int(signature_blob[32:], "little")
|
signature_data["S"] = cls._big_int(signature_blob[32:], "little")
|
||||||
else:
|
else:
|
||||||
raise ValueError("%s is not a valid signature type" % signature_type)
|
raise ValueError(f"{signature_type} is not a valid signature type")
|
||||||
|
|
||||||
signature_data["signature_type"] = signature_type
|
signature_data["signature_type"] = signature_type
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ class OpensshParser:
|
|||||||
def _big_int(cls, raw_string, byte_order, signed=False):
|
def _big_int(cls, raw_string, byte_order, signed=False):
|
||||||
if byte_order not in ("big", "little"):
|
if byte_order not in ("big", "little"):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Byte_order must be one of (big, little) not %s" % byte_order
|
f"Byte_order must be one of (big, little) not {byte_order}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if PY3:
|
if PY3:
|
||||||
@@ -279,7 +279,7 @@ class _OpensshWriter:
|
|||||||
if buffer is not None:
|
if buffer is not None:
|
||||||
if not isinstance(buffer, (bytes, bytearray)):
|
if not isinstance(buffer, (bytes, bytearray)):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"Buffer must be a bytes-like object not %s" % type(buffer)
|
f"Buffer must be a bytes-like object not {type(buffer)}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
buffer = bytearray()
|
buffer = bytearray()
|
||||||
@@ -288,7 +288,7 @@ class _OpensshWriter:
|
|||||||
|
|
||||||
def boolean(self, value):
|
def boolean(self, value):
|
||||||
if not isinstance(value, bool):
|
if not isinstance(value, bool):
|
||||||
raise TypeError("Value must be of type bool not %s" % type(value))
|
raise TypeError(f"Value must be of type bool not {type(value)}")
|
||||||
|
|
||||||
self._buff.extend(_BOOLEAN.pack(value))
|
self._buff.extend(_BOOLEAN.pack(value))
|
||||||
|
|
||||||
@@ -296,10 +296,10 @@ class _OpensshWriter:
|
|||||||
|
|
||||||
def uint32(self, value):
|
def uint32(self, value):
|
||||||
if not isinstance(value, int):
|
if not isinstance(value, int):
|
||||||
raise TypeError("Value must be of type int not %s" % type(value))
|
raise TypeError(f"Value must be of type int not {type(value)}")
|
||||||
if value < 0 or value > _UINT32_MAX:
|
if value < 0 or value > _UINT32_MAX:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Value must be a positive integer less than %s" % _UINT32_MAX
|
f"Value must be a positive integer less than {_UINT32_MAX}"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._buff.extend(_UINT32.pack(value))
|
self._buff.extend(_UINT32.pack(value))
|
||||||
@@ -308,10 +308,10 @@ class _OpensshWriter:
|
|||||||
|
|
||||||
def uint64(self, value):
|
def uint64(self, value):
|
||||||
if not isinstance(value, (long, int)):
|
if not isinstance(value, (long, int)):
|
||||||
raise TypeError("Value must be of type (long, int) not %s" % type(value))
|
raise TypeError(f"Value must be of type (long, int) not {type(value)}")
|
||||||
if value < 0 or value > _UINT64_MAX:
|
if value < 0 or value > _UINT64_MAX:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Value must be a positive integer less than %s" % _UINT64_MAX
|
f"Value must be a positive integer less than {_UINT64_MAX}"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._buff.extend(_UINT64.pack(value))
|
self._buff.extend(_UINT64.pack(value))
|
||||||
@@ -320,7 +320,7 @@ class _OpensshWriter:
|
|||||||
|
|
||||||
def string(self, value):
|
def string(self, value):
|
||||||
if not isinstance(value, (bytes, bytearray)):
|
if not isinstance(value, (bytes, bytearray)):
|
||||||
raise TypeError("Value must be bytes-like not %s" % type(value))
|
raise TypeError(f"Value must be bytes-like not {type(value)}")
|
||||||
self.uint32(len(value))
|
self.uint32(len(value))
|
||||||
self._buff.extend(value)
|
self._buff.extend(value)
|
||||||
|
|
||||||
@@ -328,7 +328,7 @@ class _OpensshWriter:
|
|||||||
|
|
||||||
def mpint(self, value):
|
def mpint(self, value):
|
||||||
if not isinstance(value, (int, long)):
|
if not isinstance(value, (int, long)):
|
||||||
raise TypeError("Value must be of type (long, int) not %s" % type(value))
|
raise TypeError(f"Value must be of type (long, int) not {type(value)}")
|
||||||
|
|
||||||
self.string(self._int_to_mpint(value))
|
self.string(self._int_to_mpint(value))
|
||||||
|
|
||||||
@@ -336,18 +336,18 @@ class _OpensshWriter:
|
|||||||
|
|
||||||
def name_list(self, value):
|
def name_list(self, value):
|
||||||
if not isinstance(value, list):
|
if not isinstance(value, list):
|
||||||
raise TypeError("Value must be a list of byte strings not %s" % type(value))
|
raise TypeError(f"Value must be a list of byte strings not {type(value)}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.string(",".join(value).encode("ASCII"))
|
self.string(",".join(value).encode("ASCII"))
|
||||||
except UnicodeEncodeError as e:
|
except UnicodeEncodeError as e:
|
||||||
raise ValueError("Name-list's must consist of US-ASCII characters: %s" % e)
|
raise ValueError(f"Name-list's must consist of US-ASCII characters: {e}")
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def string_list(self, value):
|
def string_list(self, value):
|
||||||
if not isinstance(value, list):
|
if not isinstance(value, list):
|
||||||
raise TypeError("Value must be a list of byte string not %s" % type(value))
|
raise TypeError(f"Value must be a list of byte string not {type(value)}")
|
||||||
|
|
||||||
writer = _OpensshWriter()
|
writer = _OpensshWriter()
|
||||||
for s in value:
|
for s in value:
|
||||||
|
|||||||
@@ -37,9 +37,7 @@ def parse_serial(value):
|
|||||||
raise ValueError("the value is not in range [0, 255]")
|
raise ValueError("the value is not in range [0, 255]")
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"The {idx}{th} part {part!r} is not a hexadecimal number in range [0, 255]: {exc}".format(
|
f"The {i + 1}{th(i + 1)} part {part!r} is not a hexadecimal number in range [0, 255]: {exc}"
|
||||||
idx=i + 1, th=th(i + 1), part=part, exc=exc
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
result = (result << 8) | part_value
|
result = (result << 8) | part_value
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ def get_relative_time_option(
|
|||||||
result = to_native(input_string)
|
result = to_native(input_string)
|
||||||
if result is None:
|
if result is None:
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'The timespec "%s" for %s is not valid' % input_string, input_name
|
f'The timespec "{input_string}" for {input_name} is not valid'
|
||||||
)
|
)
|
||||||
# Relative time
|
# Relative time
|
||||||
if result.startswith("+") or result.startswith("-"):
|
if result.startswith("+") or result.startswith("-"):
|
||||||
@@ -179,5 +179,5 @@ def get_relative_time_option(
|
|||||||
return add_or_remove_timezone(res, with_timezone=with_timezone)
|
return add_or_remove_timezone(res, with_timezone=with_timezone)
|
||||||
|
|
||||||
raise OpenSSLObjectError(
|
raise OpenSSLObjectError(
|
||||||
'The time spec "%s" for %s is invalid' % (input_string, input_name)
|
f'The time spec "{input_string}" for {input_name} is invalid'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -229,8 +229,7 @@ def main():
|
|||||||
base64.urlsafe_b64decode(key)
|
base64.urlsafe_b64decode(key)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Key for external_account_binding must be Base64 URL encoded (%s)"
|
msg=f"Key for external_account_binding must be Base64 URL encoded ({e})"
|
||||||
% e
|
|
||||||
)
|
)
|
||||||
module.params["external_account_binding"]["key"] = key
|
module.params["external_account_binding"]["key"] = key
|
||||||
|
|
||||||
@@ -296,7 +295,7 @@ def main():
|
|||||||
)
|
)
|
||||||
except KeyParsingError as e:
|
except KeyParsingError as e:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"Error while parsing new account key: {msg}".format(msg=e.msg)
|
f"Error while parsing new account key: {e.msg}"
|
||||||
)
|
)
|
||||||
# Verify that the account exists and has not been deactivated
|
# Verify that the account exists and has not been deactivated
|
||||||
created, account_data = account.setup_account(allow_creation=False)
|
created, account_data = account.setup_account(allow_creation=False)
|
||||||
|
|||||||
@@ -233,9 +233,7 @@ def get_orders_list(module, client, orders_url):
|
|||||||
if not res.get("orders"):
|
if not res.get("orders"):
|
||||||
if orders:
|
if orders:
|
||||||
module.warn(
|
module.warn(
|
||||||
"When retrieving orders list part {0}, got empty result list".format(
|
f"When retrieving orders list part {orders_url}, got empty result list"
|
||||||
orders_url
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
# Add order URLs to result list
|
# Add order URLs to result list
|
||||||
|
|||||||
@@ -643,9 +643,7 @@ class ACMECertificateClient:
|
|||||||
)
|
)
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
self.module.warn(
|
self.module.warn(
|
||||||
"Error while parsing criterium: {error}. Ignoring criterium.".format(
|
f"Error while parsing criterium: {exc}. Ignoring criterium."
|
||||||
error=exc
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.profile is not None:
|
if self.profile is not None:
|
||||||
@@ -654,9 +652,7 @@ class ACMECertificateClient:
|
|||||||
raise ModuleFailException(msg="The ACME CA does not support profiles.")
|
raise ModuleFailException(msg="The ACME CA does not support profiles.")
|
||||||
if self.profile not in meta_profiles:
|
if self.profile not in meta_profiles:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
msg="The ACME CA does not support selected profile {0!r}.".format(
|
msg=f"The ACME CA does not support selected profile {self.profile!r}."
|
||||||
self.profile
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Make sure account exists
|
# Make sure account exists
|
||||||
@@ -678,7 +674,7 @@ class ACMECertificateClient:
|
|||||||
self.changed = created or updated
|
self.changed = created or updated
|
||||||
|
|
||||||
if self.csr is not None and not os.path.exists(self.csr):
|
if self.csr is not None and not os.path.exists(self.csr):
|
||||||
raise ModuleFailException("CSR %s not found" % (self.csr))
|
raise ModuleFailException(f"CSR {self.csr} not found")
|
||||||
|
|
||||||
# Extract list of identifiers from CSR
|
# Extract list of identifiers from CSR
|
||||||
self.identifiers = self.client.backend.get_ordered_csr_identifiers(
|
self.identifiers = self.client.backend.get_ordered_csr_identifiers(
|
||||||
@@ -758,9 +754,7 @@ class ACMECertificateClient:
|
|||||||
and self.challenge not in data[authz.identifier]
|
and self.challenge not in data[authz.identifier]
|
||||||
):
|
):
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"Found no challenge of type '{0}' for identifier {1}!".format(
|
f"Found no challenge of type '{self.challenge}' for identifier {type_identifier}!"
|
||||||
self.challenge, type_identifier
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
# Get DNS challenge data
|
# Get DNS challenge data
|
||||||
data_dns = {}
|
data_dns = {}
|
||||||
@@ -812,9 +806,7 @@ class ACMECertificateClient:
|
|||||||
alt_cert = CertificateChain.download(self.client, alternate)
|
alt_cert = CertificateChain.download(self.client, alternate)
|
||||||
except ModuleFailException as e:
|
except ModuleFailException as e:
|
||||||
self.module.warn(
|
self.module.warn(
|
||||||
"Error while downloading alternative certificate {0}: {1}".format(
|
f"Error while downloading alternative certificate {alternate}: {e}"
|
||||||
alternate, e
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
alternate_chains.append(alt_cert)
|
alternate_chains.append(alt_cert)
|
||||||
@@ -825,7 +817,7 @@ class ACMECertificateClient:
|
|||||||
for chain in chains:
|
for chain in chains:
|
||||||
if matcher.match(chain):
|
if matcher.match(chain):
|
||||||
self.module.debug(
|
self.module.debug(
|
||||||
"Found matching chain for criterium {0}".format(criterium_idx)
|
f"Found matching chain for criterium {criterium_idx}"
|
||||||
)
|
)
|
||||||
return chain
|
return chain
|
||||||
return None
|
return None
|
||||||
@@ -844,13 +836,11 @@ class ACMECertificateClient:
|
|||||||
)
|
)
|
||||||
if authz is None:
|
if authz is None:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
'Found no authorization information for "{identifier}"!'.format(
|
f'Found no authorization information for "{combine_identifier(identifier_type, identifier)}"!'
|
||||||
identifier=combine_identifier(identifier_type, identifier)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if authz.status != "valid":
|
if authz.status != "valid":
|
||||||
authz.raise_error(
|
authz.raise_error(
|
||||||
'Status is "{status}" and not "valid"'.format(status=authz.status),
|
f'Status is "{authz.status}" and not "valid"',
|
||||||
module=self.module,
|
module=self.module,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -911,7 +901,7 @@ class ACMECertificateClient:
|
|||||||
pass
|
pass
|
||||||
if authz.status != "deactivated":
|
if authz.status != "deactivated":
|
||||||
self.module.warn(
|
self.module.warn(
|
||||||
warning="Could not deactivate authz object {0}.".format(authz.url)
|
warning=f"Could not deactivate authz object {authz.url}."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -98,9 +98,7 @@ def main():
|
|||||||
# ignore errors
|
# ignore errors
|
||||||
pass
|
pass
|
||||||
if authz.status != "deactivated":
|
if authz.status != "deactivated":
|
||||||
module.warn(
|
module.warn(warning=f"Could not deactivate authz object {authz.url}.")
|
||||||
warning="Could not deactivate authz object {0}.".format(authz.url)
|
|
||||||
)
|
|
||||||
|
|
||||||
module.exit_json(changed=changed)
|
module.exit_json(changed=changed)
|
||||||
except ModuleFailException as e:
|
except ModuleFailException as e:
|
||||||
|
|||||||
@@ -414,9 +414,7 @@ def main():
|
|||||||
)
|
)
|
||||||
if profile not in meta_profiles:
|
if profile not in meta_profiles:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
msg="The ACME CA does not support selected profile {0!r}.".format(
|
msg=f"The ACME CA does not support selected profile {profile!r}."
|
||||||
profile
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
order = None
|
order = None
|
||||||
|
|||||||
@@ -271,13 +271,10 @@ def main():
|
|||||||
|
|
||||||
missing_challenge_authzs = [k for k, v in challenges.items() if v is None]
|
missing_challenge_authzs = [k for k, v in challenges.items() if v is None]
|
||||||
if missing_challenge_authzs:
|
if missing_challenge_authzs:
|
||||||
|
missing_challenge_authzs = ", ".join(sorted(missing_challenge_authzs))
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
"The challenge parameter must be supplied if there are pending authorizations."
|
"The challenge parameter must be supplied if there are pending authorizations."
|
||||||
" The following authorizations are pending: {missing_challenge_authzs}".format(
|
f" The following authorizations are pending: {missing_challenge_authzs}"
|
||||||
missing_challenge_authzs=", ".join(
|
|
||||||
sorted(missing_challenge_authzs)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
bad_challenge_authzs = [
|
bad_challenge_authzs = [
|
||||||
@@ -286,18 +283,15 @@ def main():
|
|||||||
if authz.find_challenge(challenges[authz.combined_identifier]) is None
|
if authz.find_challenge(challenges[authz.combined_identifier]) is None
|
||||||
]
|
]
|
||||||
if bad_challenge_authzs:
|
if bad_challenge_authzs:
|
||||||
raise ModuleFailException(
|
authz_challenges_pairs = ", ".join(
|
||||||
"The following authorizations do not support the selected challenges: {authz_challenges_pairs}".format(
|
sorted(
|
||||||
authz_challenges_pairs=", ".join(
|
f"{authz} with {challenges[authz]}"
|
||||||
sorted(
|
for authz in bad_challenge_authzs
|
||||||
"{authz} with {challenge}".format(
|
|
||||||
authz=authz, challenge=challenges[authz]
|
|
||||||
)
|
|
||||||
for authz in bad_challenge_authzs
|
|
||||||
)
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
raise ModuleFailException(
|
||||||
|
f"The following authorizations do not support the selected challenges: {authz_challenges_pairs}"
|
||||||
|
)
|
||||||
|
|
||||||
really_pending_authzs = [
|
really_pending_authzs = [
|
||||||
authz
|
authz
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ def main():
|
|||||||
)
|
)
|
||||||
except ModuleFailException as e:
|
except ModuleFailException as e:
|
||||||
if module.params["treat_parsing_error_as_non_existing"]:
|
if module.params["treat_parsing_error_as_non_existing"]:
|
||||||
complete(True, msg="Certificate cannot be parsed: {0}".format(e.msg))
|
complete(True, msg=f"Certificate cannot be parsed: {e.msg}")
|
||||||
e.do_fail(module)
|
e.do_fail(module)
|
||||||
|
|
||||||
result["parsable"] = True
|
result["parsable"] = True
|
||||||
@@ -265,24 +265,18 @@ def main():
|
|||||||
)
|
)
|
||||||
msg_append = ""
|
msg_append = ""
|
||||||
if "explanationURL" in renewal_info:
|
if "explanationURL" in renewal_info:
|
||||||
msg_append = ". Information on renewal interval: {0}".format(
|
msg_append = f". Information on renewal interval: {renewal_info['explanationURL']}"
|
||||||
renewal_info["explanationURL"]
|
|
||||||
)
|
|
||||||
result["supports_ari"] = True
|
result["supports_ari"] = True
|
||||||
if now > window_end:
|
if now > window_end:
|
||||||
complete(
|
complete(
|
||||||
True,
|
True,
|
||||||
msg="The suggested renewal interval provided by ARI is in the past{0}".format(
|
msg=f"The suggested renewal interval provided by ARI is in the past{msg_append}",
|
||||||
msg_append
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
if module.params["ari_algorithm"] == "start":
|
if module.params["ari_algorithm"] == "start":
|
||||||
if now > window_start:
|
if now > window_start:
|
||||||
complete(
|
complete(
|
||||||
True,
|
True,
|
||||||
msg="The suggested renewal interval provided by ARI has begun{0}".format(
|
msg=f"The suggested renewal interval provided by ARI has begun{msg_append}",
|
||||||
msg_append
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
random_time = backend.interpolate_timestamp(
|
random_time = backend.interpolate_timestamp(
|
||||||
@@ -291,10 +285,7 @@ def main():
|
|||||||
if now > random_time:
|
if now > random_time:
|
||||||
complete(
|
complete(
|
||||||
True,
|
True,
|
||||||
msg="The picked random renewal time {0} in sugested renewal internal provided by ARI is in the past{1}".format(
|
msg=f"The picked random renewal time {random_time} in sugested renewal internal provided by ARI is in the past{msg_append}",
|
||||||
random_time,
|
|
||||||
msg_append,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if module.params["remaining_days"] is not None:
|
if module.params["remaining_days"] is not None:
|
||||||
@@ -302,7 +293,7 @@ def main():
|
|||||||
if remaining_days < module.params["remaining_days"]:
|
if remaining_days < module.params["remaining_days"]:
|
||||||
complete(
|
complete(
|
||||||
True,
|
True,
|
||||||
msg="The certificate expires in {0} days".format(remaining_days),
|
msg=f"The certificate expires in {remaining_days} days",
|
||||||
)
|
)
|
||||||
|
|
||||||
if module.params["remaining_percentage"] is not None:
|
if module.params["remaining_percentage"] is not None:
|
||||||
@@ -314,10 +305,8 @@ def main():
|
|||||||
if timestamp < now:
|
if timestamp < now:
|
||||||
complete(
|
complete(
|
||||||
True,
|
True,
|
||||||
msg="The remaining percentage {0}% of the certificate's lifespan was reached on {1}".format(
|
msg=f"The remaining percentage {module.params['remaining_percentage'] * 100}%"
|
||||||
module.params["remaining_percentage"] * 100,
|
f" of the certificate's lifespan was reached on {timestamp}",
|
||||||
timestamp,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
complete(False)
|
complete(False)
|
||||||
|
|||||||
@@ -182,9 +182,7 @@ def main():
|
|||||||
private_key, private_key_content, passphrase=passphrase
|
private_key, private_key_content, passphrase=passphrase
|
||||||
)
|
)
|
||||||
except KeyParsingError as e:
|
except KeyParsingError as e:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(f"Error while parsing private key: {e.msg}")
|
||||||
"Error while parsing private key: {msg}".format(msg=e.msg)
|
|
||||||
)
|
|
||||||
# Step 2: sign revokation request with private key
|
# Step 2: sign revokation request with private key
|
||||||
jws_header = {
|
jws_header = {
|
||||||
"alg": private_key_data["alg"],
|
"alg": private_key_data["alg"],
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ def main():
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ModuleFailException("Error while loading private key: {0}".format(e))
|
raise ModuleFailException(f"Error while loading private key: {e}")
|
||||||
|
|
||||||
# Some common attributes
|
# Some common attributes
|
||||||
domain = to_text(challenge_data["resource"])
|
domain = to_text(challenge_data["resource"])
|
||||||
@@ -276,7 +276,7 @@ def main():
|
|||||||
san = cryptography.x509.IPAddress(ipaddress.ip_address(identifier))
|
san = cryptography.x509.IPAddress(ipaddress.ip_address(identifier))
|
||||||
else:
|
else:
|
||||||
raise ModuleFailException(
|
raise ModuleFailException(
|
||||||
'Unsupported identifier type "{0}"'.format(identifier_type)
|
f'Unsupported identifier type "{identifier_type}"'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate regular self-signed certificate
|
# Generate regular self-signed certificate
|
||||||
|
|||||||
@@ -212,18 +212,16 @@ def is_parent(module, cert, potential_parent):
|
|||||||
public_key.verify(cert.cert.signature, cert.cert.tbs_certificate_bytes)
|
public_key.verify(cert.cert.signature, cert.cert.tbs_certificate_bytes)
|
||||||
else:
|
else:
|
||||||
# Unknown public key type
|
# Unknown public key type
|
||||||
module.warn('Unknown public key type "{0}"'.format(public_key))
|
module.warn(f'Unknown public key type "{public_key}"')
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
except cryptography.exceptions.InvalidSignature:
|
except cryptography.exceptions.InvalidSignature:
|
||||||
return False
|
return False
|
||||||
except cryptography.exceptions.UnsupportedAlgorithm:
|
except cryptography.exceptions.UnsupportedAlgorithm:
|
||||||
module.warn(
|
module.warn(f'Unsupported algorithm "{cert.cert.signature_hash_algorithm}"')
|
||||||
'Unsupported algorithm "{0}"'.format(cert.cert.signature_hash_algorithm)
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
module.fail_json(msg="Unknown error on signature validation: {0}".format(e))
|
module.fail_json(msg=f"Unknown error on signature validation: {e}")
|
||||||
|
|
||||||
|
|
||||||
def parse_PEM_list(module, text, source, fail_on_error=True):
|
def parse_PEM_list(module, text, source, fail_on_error=True):
|
||||||
@@ -239,9 +237,7 @@ def parse_PEM_list(module, text, source, fail_on_error=True):
|
|||||||
)
|
)
|
||||||
result.append(Certificate(cert_pem, cert))
|
result.append(Certificate(cert_pem, cert))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = "Cannot parse certificate #{0} from {1}: {2}".format(
|
msg = f"Cannot parse certificate #{len(result) + 1} from {source}: {e}"
|
||||||
len(result) + 1, source, e
|
|
||||||
)
|
|
||||||
if fail_on_error:
|
if fail_on_error:
|
||||||
module.fail_json(msg=msg)
|
module.fail_json(msg=msg)
|
||||||
else:
|
else:
|
||||||
@@ -262,7 +258,7 @@ def load_PEM_list(module, path, fail_on_error=True):
|
|||||||
fail_on_error=fail_on_error,
|
fail_on_error=fail_on_error,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = "Cannot read certificate file {0}: {1}".format(path, e)
|
msg = f"Cannot read certificate file {path}: {e}"
|
||||||
if fail_on_error:
|
if fail_on_error:
|
||||||
module.fail_json(msg=msg)
|
module.fail_json(msg=msg)
|
||||||
else:
|
else:
|
||||||
@@ -357,9 +353,9 @@ def main():
|
|||||||
if not is_parent(module, chain[i - 1], parent):
|
if not is_parent(module, chain[i - 1], parent):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=(
|
||||||
"Cannot verify input chain: certificate #{2}: {3} is not issuer "
|
f"Cannot verify input chain: certificate #{i + 1}: {format_cert(parent)} is not issuer "
|
||||||
+ "of certificate #{0}: {1}"
|
f"of certificate #{i}: {format_cert(chain[i - 1])}"
|
||||||
).format(i, format_cert(chain[i - 1]), i + 1, format_cert(parent))
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Load intermediate certificates
|
# Load intermediate certificates
|
||||||
@@ -392,9 +388,7 @@ def main():
|
|||||||
current = intermediate
|
current = intermediate
|
||||||
else:
|
else:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Cannot complete chain. Stuck at certificate {0}".format(
|
msg=f"Cannot complete chain. Stuck at certificate {format_cert(current)}"
|
||||||
format_cert(current)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Return results
|
# Return results
|
||||||
|
|||||||
@@ -665,16 +665,12 @@ class EcsCertificate:
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
except SessionConfigurationException as e:
|
except SessionConfigurationException as e:
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Failed to initialize Entrust Provider: {e}")
|
||||||
msg="Failed to initialize Entrust Provider: {0}".format(to_native(e))
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
self.ecs_client.GetAppVersion()
|
self.ecs_client.GetAppVersion()
|
||||||
except RestOperationException as e:
|
except RestOperationException as e:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Please verify credential information. Received exception when testing ECS connection: {0}".format(
|
msg=f"Please verify credential information. Received exception when testing ECS connection: {e.message}"
|
||||||
to_native(e.message)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Conversion of the fields that go into the 'tracking' parameter of the request object
|
# Conversion of the fields that go into the 'tracking' parameter of the request object
|
||||||
@@ -744,7 +740,7 @@ class EcsCertificate:
|
|||||||
try:
|
try:
|
||||||
# Use serial_number to identify if certificate is an Entrust Certificate
|
# Use serial_number to identify if certificate is an Entrust Certificate
|
||||||
# with an associated tracking ID
|
# with an associated tracking ID
|
||||||
serial_number = "{0:X}".format(self.cert.serial_number)
|
serial_number = f"{self.cert.serial_number:X}"
|
||||||
cert_results = self.ecs_client.GetCertificates(
|
cert_results = self.ecs_client.GetCertificates(
|
||||||
serialNumber=serial_number
|
serialNumber=serial_number
|
||||||
).get("certificates", {})
|
).get("certificates", {})
|
||||||
@@ -764,9 +760,7 @@ class EcsCertificate:
|
|||||||
self.cert_days = calculate_cert_days(self.cert_details.get("expiresAfter"))
|
self.cert_days = calculate_cert_days(self.cert_details.get("expiresAfter"))
|
||||||
except RestOperationException as e:
|
except RestOperationException as e:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
'Failed to get details of certificate with tracking_id="{0}", Error: '.format(
|
f'Failed to get details of certificate with tracking_id="{self.tracking_id}", Error: ',
|
||||||
self.tracking_id
|
|
||||||
),
|
|
||||||
to_native(e.message),
|
to_native(e.message),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -782,10 +776,9 @@ class EcsCertificate:
|
|||||||
and module.params["tracking_id"] != self.tracking_id
|
and module.params["tracking_id"] != self.tracking_id
|
||||||
):
|
):
|
||||||
module.warn(
|
module.warn(
|
||||||
'tracking_id parameter of "{0}" provided, but will be ignored. Valid certificate was present in path "{1}" with '
|
f'tracking_id parameter of "{module.params["tracking_id"]}" provided, but will be ignored.'
|
||||||
'tracking_id of "{2}".'.format(
|
f' Valid certificate was present in path "{self.path}" with '
|
||||||
module.params["tracking_id"], self.path, self.tracking_id
|
f'tracking_id of "{self.tracking_id}".'
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# If we did not end up setting tracking_id based on existing cert, get from module params
|
# If we did not end up setting tracking_id based on existing cert, get from module params
|
||||||
@@ -822,10 +815,10 @@ class EcsCertificate:
|
|||||||
# We will be performing a reissue operation.
|
# We will be performing a reissue operation.
|
||||||
if self.request_type != "new" and not self.tracking_id:
|
if self.request_type != "new" and not self.tracking_id:
|
||||||
module.warn(
|
module.warn(
|
||||||
'No existing Entrust certificate found in path={0} and no tracking_id was provided, setting request_type to "new" for this task'
|
f"No existing Entrust certificate found in path={self.path}"
|
||||||
"run. Future playbook runs that point to the pathination file in {1} will use request_type={2}".format(
|
' and no tracking_id was provided, setting request_type to "new" for this task'
|
||||||
self.path, self.path, self.request_type
|
"run. Future playbook runs that point to the pathination file"
|
||||||
)
|
f" in {self.path} will use request_type={self.request_type}"
|
||||||
)
|
)
|
||||||
self.request_type = "new"
|
self.request_type = "new"
|
||||||
elif self.request_type == "new" and self.tracking_id:
|
elif self.request_type == "new" and self.tracking_id:
|
||||||
@@ -860,9 +853,7 @@ class EcsCertificate:
|
|||||||
self.set_cert_details(module)
|
self.set_cert_details(module)
|
||||||
except RestOperationException as e:
|
except RestOperationException as e:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Failed to request new certificate from Entrust (ECS) {0}".format(
|
msg=f"Failed to request new certificate from Entrust (ECS) {e.message}"
|
||||||
e.message
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.request_type != "validate_only":
|
if self.request_type != "validate_only":
|
||||||
@@ -1020,9 +1011,7 @@ def main():
|
|||||||
MINIMAL_CRYPTOGRAPHY_VERSION
|
MINIMAL_CRYPTOGRAPHY_VERSION
|
||||||
):
|
):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"),
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
),
|
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1033,9 +1022,7 @@ def main():
|
|||||||
or module.params["request_type"] == "validate_only"
|
or module.params["request_type"] == "validate_only"
|
||||||
):
|
):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg='The tracking_id field is invalid when request_type="{0}".'.format(
|
msg=f'The tracking_id field is invalid when request_type="{module.params["request_type"]}".'
|
||||||
module.params["request_type"]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# A reissued request can not specify an expiration date or lifetime
|
# A reissued request can not specify an expiration date or lifetime
|
||||||
@@ -1053,15 +1040,12 @@ def main():
|
|||||||
module_params_csr = module.params["csr"]
|
module_params_csr = module.params["csr"]
|
||||||
if module_params_csr is None:
|
if module_params_csr is None:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="The csr field is required when request_type={0}".format(
|
msg=f"The csr field is required when request_type={module.params['request_type']}"
|
||||||
module.params["request_type"]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
elif not os.path.exists(module_params_csr):
|
elif not os.path.exists(module_params_csr):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="The csr field of {0} was not a valid path. csr is required when request_type={1}".format(
|
msg=f"The csr field of {module_params_csr} was not a valid path."
|
||||||
module_params_csr, module.params["request_type"]
|
f" csr is required when request_type={module.params['request_type']}"
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if module.params["ou"] and len(module.params["ou"]) > 1:
|
if module.params["ou"] and len(module.params["ou"]) > 1:
|
||||||
@@ -1088,9 +1072,7 @@ def main():
|
|||||||
if module.params["cert_expiry"]:
|
if module.params["cert_expiry"]:
|
||||||
if not validate_cert_expiry(module.params["cert_expiry"]):
|
if not validate_cert_expiry(module.params["cert_expiry"]):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg='The "cert_expiry" parameter of "{0}" is not a valid date or date-time'.format(
|
msg=f'The "cert_expiry" parameter of "{module.params["cert_expiry"]}" is not a valid date or date-time'
|
||||||
module.params["cert_expiry"]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
certificate = EcsCertificate(module)
|
certificate = EcsCertificate(module)
|
||||||
|
|||||||
@@ -275,15 +275,13 @@ class EcsDomain:
|
|||||||
)
|
)
|
||||||
except SessionConfigurationException as e:
|
except SessionConfigurationException as e:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Failed to initialize Entrust Provider: {0}".format(to_native(e))
|
msg=f"Failed to initialize Entrust Provider: {to_native(e)}"
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
self.ecs_client.GetAppVersion()
|
self.ecs_client.GetAppVersion()
|
||||||
except RestOperationException as e:
|
except RestOperationException as e:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Please verify credential information. Received exception when testing ECS connection: {0}".format(
|
msg=f"Please verify credential information. Received exception when testing ECS connection: {e.message}"
|
||||||
to_native(e.message)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_domain_details(self, domain_details):
|
def set_domain_details(self, domain_details):
|
||||||
@@ -405,9 +403,7 @@ class EcsDomain:
|
|||||||
self.set_domain_details(result)
|
self.set_domain_details(result)
|
||||||
except RestOperationException as e:
|
except RestOperationException as e:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Failed to request domain validation from Entrust (ECS) {0}".format(
|
msg=f"Failed to request domain validation from Entrust (ECS) {e.message}"
|
||||||
e.message
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def dump(self):
|
def dump(self):
|
||||||
@@ -467,9 +463,7 @@ def main():
|
|||||||
and module.params["verification_method"] != "email"
|
and module.params["verification_method"] != "email"
|
||||||
):
|
):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg='The verification_email field is invalid when verification_method="{0}".'.format(
|
msg=f'The verification_email field is invalid when verification_method="{module.params["verification_method"]}".'
|
||||||
module.params["verification_method"]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
domain = EcsDomain(module)
|
domain = EcsDomain(module)
|
||||||
|
|||||||
@@ -369,8 +369,7 @@ def main():
|
|||||||
if get_certificate_chain and sys.version_info < (3, 10):
|
if get_certificate_chain and sys.version_info < (3, 10):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="get_certificate_chain=true can only be used with Python 3.10 (Python 3.13+ officially supports this). "
|
msg="get_certificate_chain=true can only be used with Python 3.10 (Python 3.13+ officially supports this). "
|
||||||
"The Python version used to run the get_certificate module is %s"
|
f"The Python version used to run the get_certificate module is {sys.version}"
|
||||||
% sys.version
|
|
||||||
)
|
)
|
||||||
|
|
||||||
backend = module.params.get("select_crypto_backend")
|
backend = module.params.get("select_crypto_backend")
|
||||||
@@ -388,16 +387,14 @@ def main():
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect the required Python library cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
|
||||||
"Cannot detect the required Python library " "cryptography (>= {0})"
|
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
@@ -437,14 +434,12 @@ def main():
|
|||||||
# Note: get_server_certificate does not support SNI!
|
# Note: get_server_certificate does not support SNI!
|
||||||
cert = get_server_certificate((host, port), ca_certs=ca_cert)
|
cert = get_server_certificate((host, port), ca_certs=ca_cert)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Failed to get cert from {host}:{port}, error: {e}")
|
||||||
msg="Failed to get cert from {0}:{1}, error: {2}".format(host, port, e)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
# Python >= 2.7.9
|
# Python >= 2.7.9
|
||||||
try:
|
try:
|
||||||
if proxy_host:
|
if proxy_host:
|
||||||
connect = "CONNECT %s:%s HTTP/1.0\r\n\r\n" % (host, port)
|
connect = f"CONNECT {host}:{port} HTTP/1.0\r\n\r\n"
|
||||||
sock = socket()
|
sock = socket()
|
||||||
atexit.register(sock.close)
|
atexit.register(sock.close)
|
||||||
sock.connect((proxy_host, proxy_port))
|
sock.connect((proxy_host, proxy_port))
|
||||||
@@ -489,9 +484,7 @@ def main():
|
|||||||
# If tls_ctx_option_attr is not an integer
|
# If tls_ctx_option_attr is not an integer
|
||||||
else:
|
else:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Failed to determine the numeric value for {0}".format(
|
msg=f"Failed to determine the numeric value for {tls_ctx_option_str}"
|
||||||
tls_ctx_option_str
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
# If the item is an integer
|
# If the item is an integer
|
||||||
elif isinstance(tls_ctx_option, int):
|
elif isinstance(tls_ctx_option, int):
|
||||||
@@ -500,9 +493,7 @@ def main():
|
|||||||
# If the item is not a string nor integer
|
# If the item is not a string nor integer
|
||||||
else:
|
else:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="tls_ctx_options must be a string or integer, got {0!r}".format(
|
msg=f"tls_ctx_options must be a string or integer, got {tls_ctx_option!r}"
|
||||||
tls_ctx_option
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
tls_ctx_option_int = (
|
tls_ctx_option_int = (
|
||||||
0 # make pylint happy; this code is actually unreachable
|
0 # make pylint happy; this code is actually unreachable
|
||||||
@@ -513,9 +504,7 @@ def main():
|
|||||||
ctx.options |= tls_ctx_option_int
|
ctx.options |= tls_ctx_option_int
|
||||||
except Exception:
|
except Exception:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Failed to add {0} to CTX options".format(
|
msg=f"Failed to add {tls_ctx_option_str or tls_ctx_option_int} to CTX options"
|
||||||
tls_ctx_option_str or tls_ctx_option_int
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
tls_sock = ctx.wrap_socket(sock, server_hostname=server_name or host)
|
tls_sock = ctx.wrap_socket(sock, server_hostname=server_name or host)
|
||||||
@@ -568,15 +557,11 @@ def main():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
if proxy_host:
|
if proxy_host:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Failed to get cert via proxy {0}:{1} from {2}:{3}, error: {4}".format(
|
msg=f"Failed to get cert via proxy {proxy_host}:{proxy_port} from {host}:{port}, error: {e}"
|
||||||
proxy_host, proxy_port, host, port, e
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Failed to get cert from {0}:{1}, error: {2}".format(
|
msg=f"Failed to get cert from {host}:{port}, error: {e}"
|
||||||
host, port, e
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
result["cert"] = cert
|
result["cert"] = cert
|
||||||
|
|||||||
@@ -493,9 +493,7 @@ class Handler:
|
|||||||
return b64decode(to_native(passphrase))
|
return b64decode(to_native(passphrase))
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self._module.fail_json(
|
self._module.fail_json(
|
||||||
"Error while base64-decoding '{parameter_name}': {exc}".format(
|
f"Error while base64-decoding '{parameter_name}': {exc}"
|
||||||
parameter_name=parameter_name, exc=exc
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _run_command(self, command, data=None):
|
def _run_command(self, command, data=None):
|
||||||
@@ -531,10 +529,10 @@ class Handler:
|
|||||||
|
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Error while generating LUKS name for %s: %s" % (device, result[STDERR])
|
f"Error while generating LUKS name for {device}: {result[STDERR]}"
|
||||||
)
|
)
|
||||||
dev_uuid = result[STDOUT].strip()
|
dev_uuid = result[STDOUT].strip()
|
||||||
return "luks-%s" % dev_uuid
|
return f"luks-{dev_uuid}"
|
||||||
|
|
||||||
|
|
||||||
class CryptHandler(Handler):
|
class CryptHandler(Handler):
|
||||||
@@ -551,7 +549,7 @@ class CryptHandler(Handler):
|
|||||||
result = self._run_command([self._lsblk_bin, device, "-nlo", "type,name"])
|
result = self._run_command([self._lsblk_bin, device, "-nlo", "type,name"])
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Error while obtaining LUKS name for %s: %s" % (device, result[STDERR])
|
f"Error while obtaining LUKS name for {device}: {result[STDERR]}"
|
||||||
)
|
)
|
||||||
|
|
||||||
for line in result[STDOUT].splitlines(False):
|
for line in result[STDOUT].splitlines(False):
|
||||||
@@ -595,9 +593,9 @@ class CryptHandler(Handler):
|
|||||||
"""check if a keyslot is set"""
|
"""check if a keyslot is set"""
|
||||||
result = self._run_command([self._cryptsetup_bin, "luksDump", device])
|
result = self._run_command([self._cryptsetup_bin, "luksDump", device])
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError("Error while dumping LUKS header from %s" % (device,))
|
raise ValueError(f"Error while dumping LUKS header from {device}")
|
||||||
result_luks1 = "Key Slot %d: ENABLED" % (keyslot) in result[STDOUT]
|
result_luks1 = f"Key Slot {keyslot}: ENABLED" in result[STDOUT]
|
||||||
result_luks2 = " %d: luks2" % (keyslot) in result[STDOUT]
|
result_luks2 = f" {keyslot}: luks2" in result[STDOUT]
|
||||||
return result_luks1 or result_luks2
|
return result_luks1 or result_luks2
|
||||||
|
|
||||||
def _add_pbkdf_options(self, options, pbkdf):
|
def _add_pbkdf_options(self, options, pbkdf):
|
||||||
@@ -657,9 +655,7 @@ class CryptHandler(Handler):
|
|||||||
|
|
||||||
result = self._run_command(args, data=passphrase)
|
result = self._run_command(args, data=passphrase)
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError(
|
raise ValueError(f"Error while creating LUKS on {device}: {result[STDERR]}")
|
||||||
"Error while creating LUKS on %s: %s" % (device, result[STDERR])
|
|
||||||
)
|
|
||||||
|
|
||||||
def run_luks_open(
|
def run_luks_open(
|
||||||
self,
|
self,
|
||||||
@@ -696,14 +692,13 @@ class CryptHandler(Handler):
|
|||||||
result = self._run_command(args, data=passphrase)
|
result = self._run_command(args, data=passphrase)
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Error while opening LUKS container on %s: %s"
|
f"Error while opening LUKS container on {device}: {result[STDERR]}"
|
||||||
% (device, result[STDERR])
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def run_luks_close(self, name):
|
def run_luks_close(self, name):
|
||||||
result = self._run_command([self._cryptsetup_bin, "close", name])
|
result = self._run_command([self._cryptsetup_bin, "close", name])
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError("Error while closing LUKS container %s" % (name))
|
raise ValueError(f"Error while closing LUKS container {name}")
|
||||||
|
|
||||||
def run_luks_remove(self, device):
|
def run_luks_remove(self, device):
|
||||||
wipefs_bin = self._module.get_bin_path("wipefs", True)
|
wipefs_bin = self._module.get_bin_path("wipefs", True)
|
||||||
@@ -714,8 +709,7 @@ class CryptHandler(Handler):
|
|||||||
result = self._run_command([wipefs_bin, "--all", device])
|
result = self._run_command([wipefs_bin, "--all", device])
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Error while wiping LUKS container signatures for %s: %s"
|
f"Error while wiping LUKS container signatures for {device}: {result[STDERR]}"
|
||||||
% (device, result[STDERR])
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# For LUKS2, sometimes both `cryptsetup erase` and `wipefs` do **not**
|
# For LUKS2, sometimes both `cryptsetup erase` and `wipefs` do **not**
|
||||||
@@ -725,8 +719,7 @@ class CryptHandler(Handler):
|
|||||||
wipe_luks_headers(device)
|
wipe_luks_headers(device)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Error while wiping LUKS container signatures for %s: %s"
|
f"Error while wiping LUKS container signatures for {device}: {exc}"
|
||||||
% (device, exc)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def run_luks_add_key(
|
def run_luks_add_key(
|
||||||
@@ -766,8 +759,7 @@ class CryptHandler(Handler):
|
|||||||
result = self._run_command(args, data=b"".join(data) or None)
|
result = self._run_command(args, data=b"".join(data) or None)
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Error while adding new LUKS keyslot to %s: %s"
|
f"Error while adding new LUKS keyslot to {device}: {result[STDERR]}"
|
||||||
% (device, result[STDERR])
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def run_luks_remove_key(
|
def run_luks_remove_key(
|
||||||
@@ -779,7 +771,7 @@ class CryptHandler(Handler):
|
|||||||
if not force_remove_last_key:
|
if not force_remove_last_key:
|
||||||
result = self._run_command([self._cryptsetup_bin, "luksDump", device])
|
result = self._run_command([self._cryptsetup_bin, "luksDump", device])
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError("Error while dumping LUKS header from %s" % (device,))
|
raise ValueError(f"Error while dumping LUKS header from {device}")
|
||||||
keyslot_count = 0
|
keyslot_count = 0
|
||||||
keyslot_area = False
|
keyslot_area = False
|
||||||
keyslot_re = re.compile(r"^Key Slot [0-9]+: ENABLED")
|
keyslot_re = re.compile(r"^Key Slot [0-9]+: ENABLED")
|
||||||
@@ -802,9 +794,8 @@ class CryptHandler(Handler):
|
|||||||
keyslot_area = False
|
keyslot_area = False
|
||||||
if keyslot_count < 2:
|
if keyslot_count < 2:
|
||||||
self._module.fail_json(
|
self._module.fail_json(
|
||||||
msg="LUKS device %s has less than two active keyslots. "
|
msg=f"LUKS device {device} has less than two active keyslots. "
|
||||||
"To be able to remove a key, please set "
|
"To be able to remove a key, please set `force_remove_last_key` to `true`."
|
||||||
"`force_remove_last_key` to `true`." % device
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if keyslot is None:
|
if keyslot is None:
|
||||||
@@ -820,7 +811,7 @@ class CryptHandler(Handler):
|
|||||||
result = self._run_command(args, data=passphrase)
|
result = self._run_command(args, data=passphrase)
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Error while removing LUKS key from %s: %s" % (device, result[STDERR])
|
f"Error while removing LUKS key from {device}: {result[STDERR]}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def luks_test_key(self, device, keyfile, passphrase, keyslot=None):
|
def luks_test_key(self, device, keyfile, passphrase, keyslot=None):
|
||||||
@@ -859,8 +850,7 @@ class CryptHandler(Handler):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Error while testing whether keyslot exists on %s: %s"
|
f"Error while testing whether keyslot exists on {device}: {result[STDERR]}"
|
||||||
% (device, result[STDERR])
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -921,8 +911,7 @@ class ConditionsHandler(Handler):
|
|||||||
# the container is already open but with different name:
|
# the container is already open but with different name:
|
||||||
# suspicious. back off
|
# suspicious. back off
|
||||||
self._module.fail_json(
|
self._module.fail_json(
|
||||||
msg="LUKS container is already opened "
|
msg=f"LUKS container is already opened under different name '{name}'."
|
||||||
"under different name '%s'." % name
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# container is opened and the names match
|
# container is opened and the names match
|
||||||
@@ -1069,13 +1058,11 @@ class ConditionsHandler(Handler):
|
|||||||
|
|
||||||
if luks_type == "luks1" and not 0 <= self._module.params[param] <= 7:
|
if luks_type == "luks1" and not 0 <= self._module.params[param] <= 7:
|
||||||
self._module.fail_json(
|
self._module.fail_json(
|
||||||
msg="%s must be between 0 and 7 when using LUKS1."
|
msg=f"{self._module.params[param]} must be between 0 and 7 when using LUKS1."
|
||||||
% self._module.params[param]
|
|
||||||
)
|
)
|
||||||
elif luks_type == "luks2" and not 0 <= self._module.params[param] <= 31:
|
elif luks_type == "luks2" and not 0 <= self._module.params[param] <= 31:
|
||||||
self._module.fail_json(
|
self._module.fail_json(
|
||||||
msg="%s must be between 0 and 31 when using LUKS2."
|
msg=f"{self._module.params[param]} must be between 0 and 31 when using LUKS2."
|
||||||
% self._module.params[param]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -1151,7 +1138,7 @@ def run_module():
|
|||||||
statinfo = os.stat(module.params["device"])
|
statinfo = os.stat(module.params["device"])
|
||||||
mode = statinfo.st_mode
|
mode = statinfo.st_mode
|
||||||
if not stat.S_ISBLK(mode) and not stat.S_ISCHR(mode):
|
if not stat.S_ISBLK(mode) and not stat.S_ISCHR(mode):
|
||||||
raise Exception("{0} is not a device".format(module.params["device"]))
|
raise Exception(f"{module.params['device']} is not a device")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
module.fail_json(msg=str(e))
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
@@ -1202,7 +1189,7 @@ def run_module():
|
|||||||
module.params["pbkdf"],
|
module.params["pbkdf"],
|
||||||
)
|
)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
module.fail_json(msg="luks_device error: %s" % e)
|
module.fail_json(msg=f"luks_device error: {e}")
|
||||||
result["changed"] = True
|
result["changed"] = True
|
||||||
if module.check_mode:
|
if module.check_mode:
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
@@ -1219,7 +1206,7 @@ def run_module():
|
|||||||
try:
|
try:
|
||||||
name = crypt.generate_luks_name(conditions.device)
|
name = crypt.generate_luks_name(conditions.device)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
module.fail_json(msg="luks_device error: %s" % e)
|
module.fail_json(msg=f"luks_device error: {e}")
|
||||||
if not module.check_mode:
|
if not module.check_mode:
|
||||||
try:
|
try:
|
||||||
crypt.run_luks_open(
|
crypt.run_luks_open(
|
||||||
@@ -1235,7 +1222,7 @@ def run_module():
|
|||||||
name,
|
name,
|
||||||
)
|
)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
module.fail_json(msg="luks_device error: %s" % e)
|
module.fail_json(msg=f"luks_device error: {e}")
|
||||||
result["name"] = name
|
result["name"] = name
|
||||||
result["changed"] = True
|
result["changed"] = True
|
||||||
if module.check_mode:
|
if module.check_mode:
|
||||||
@@ -1247,14 +1234,14 @@ def run_module():
|
|||||||
try:
|
try:
|
||||||
name = crypt.get_container_name_by_device(conditions.device)
|
name = crypt.get_container_name_by_device(conditions.device)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
module.fail_json(msg="luks_device error: %s" % e)
|
module.fail_json(msg=f"luks_device error: {e}")
|
||||||
else:
|
else:
|
||||||
name = module.params["name"]
|
name = module.params["name"]
|
||||||
if not module.check_mode:
|
if not module.check_mode:
|
||||||
try:
|
try:
|
||||||
crypt.run_luks_close(name)
|
crypt.run_luks_close(name)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
module.fail_json(msg="luks_device error: %s" % e)
|
module.fail_json(msg=f"luks_device error: {e}")
|
||||||
result["name"] = name
|
result["name"] = name
|
||||||
result["changed"] = True
|
result["changed"] = True
|
||||||
if module.check_mode:
|
if module.check_mode:
|
||||||
@@ -1274,7 +1261,7 @@ def run_module():
|
|||||||
module.params["pbkdf"],
|
module.params["pbkdf"],
|
||||||
)
|
)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
module.fail_json(msg="luks_device error: %s" % e)
|
module.fail_json(msg=f"luks_device error: {e}")
|
||||||
result["changed"] = True
|
result["changed"] = True
|
||||||
if module.check_mode:
|
if module.check_mode:
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
@@ -1292,7 +1279,7 @@ def run_module():
|
|||||||
force_remove_last_key=last_key,
|
force_remove_last_key=last_key,
|
||||||
)
|
)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
module.fail_json(msg="luks_device error: %s" % e)
|
module.fail_json(msg=f"luks_device error: {e}")
|
||||||
result["changed"] = True
|
result["changed"] = True
|
||||||
if module.check_mode:
|
if module.check_mode:
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
@@ -1303,7 +1290,7 @@ def run_module():
|
|||||||
try:
|
try:
|
||||||
crypt.run_luks_remove(conditions.device)
|
crypt.run_luks_remove(conditions.device)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
module.fail_json(msg="luks_device error: %s" % e)
|
module.fail_json(msg=f"luks_device error: {e}")
|
||||||
result["changed"] = True
|
result["changed"] = True
|
||||||
if module.check_mode:
|
if module.check_mode:
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ class Certificate(OpensshModule):
|
|||||||
elif LooseVersion(ssh_version) < LooseVersion("7.6"):
|
elif LooseVersion(ssh_version) < LooseVersion("7.6"):
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Signing with CA key in ssh agent requires ssh 7.6 or newer."
|
msg="Signing with CA key in ssh agent requires ssh 7.6 or newer."
|
||||||
+ " Your version is: %s" % ssh_version
|
+ f" Your version is: {ssh_version}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def _exists(self):
|
def _exists(self):
|
||||||
@@ -371,10 +371,8 @@ class Certificate(OpensshModule):
|
|||||||
self.original_data = OpensshCertificate.load(self.path)
|
self.original_data = OpensshCertificate.load(self.path)
|
||||||
except (TypeError, ValueError) as e:
|
except (TypeError, ValueError) as e:
|
||||||
if self.regenerate in ("never", "fail"):
|
if self.regenerate in ("never", "fail"):
|
||||||
self.module.fail_json(
|
self.module.fail_json(msg=f"Unable to read existing certificate: {e}")
|
||||||
msg="Unable to read existing certificate: %s" % to_native(e)
|
self.module.warn(f"Unable to read existing certificate: {e}")
|
||||||
)
|
|
||||||
self.module.warn("Unable to read existing certificate: %s" % to_native(e))
|
|
||||||
|
|
||||||
def _set_time_parameters(self):
|
def _set_time_parameters(self):
|
||||||
try:
|
try:
|
||||||
@@ -486,15 +484,13 @@ class Certificate(OpensshModule):
|
|||||||
self._safe_secure_move([(temp_certificate, self.path)])
|
self._safe_secure_move([(temp_certificate, self.path)])
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Unable to write certificate to %s: %s" % (self.path, to_native(e))
|
msg=f"Unable to write certificate to {self.path}: {e}"
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.data = OpensshCertificate.load(self.path)
|
self.data = OpensshCertificate.load(self.path)
|
||||||
except (TypeError, ValueError) as e:
|
except (TypeError, ValueError) as e:
|
||||||
self.module.fail_json(
|
self.module.fail_json(msg=f"Unable to read new certificate: {e}")
|
||||||
msg="Unable to read new certificate: %s" % to_native(e)
|
|
||||||
)
|
|
||||||
|
|
||||||
def _generate_temp_certificate(self):
|
def _generate_temp_certificate(self):
|
||||||
key_copy = os.path.join(self.module.tmpdir, os.path.basename(self.public_key))
|
key_copy = os.path.join(self.module.tmpdir, os.path.basename(self.public_key))
|
||||||
@@ -502,9 +498,7 @@ class Certificate(OpensshModule):
|
|||||||
try:
|
try:
|
||||||
self.module.preserved_copy(self.public_key, key_copy)
|
self.module.preserved_copy(self.public_key, key_copy)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
self.module.fail_json(
|
self.module.fail_json(msg=f"Unable to stage temporary key: {e}")
|
||||||
msg="Unable to stage temporary key: %s" % to_native(e)
|
|
||||||
)
|
|
||||||
self.module.add_cleanup_file(key_copy)
|
self.module.add_cleanup_file(key_copy)
|
||||||
|
|
||||||
self.ssh_keygen.generate_certificate(
|
self.ssh_keygen.generate_certificate(
|
||||||
@@ -535,7 +529,7 @@ class Certificate(OpensshModule):
|
|||||||
os.remove(self.path)
|
os.remove(self.path)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Unable to remove existing certificate: %s" % to_native(e)
|
msg=f"Unable to remove existing certificate: {to_native(e)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -337,8 +337,7 @@ def main():
|
|||||||
if not os.path.isdir(base_dir):
|
if not os.path.isdir(base_dir):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
name=base_dir,
|
name=base_dir,
|
||||||
msg="The directory %s does not exist or the file is not a directory"
|
msg=f"The directory {base_dir} does not exist or the file is not a directory",
|
||||||
% base_dir,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -341,9 +341,7 @@ def main():
|
|||||||
with open(module.params["path"], "rb") as f:
|
with open(module.params["path"], "rb") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Error while reading CSR file from disk: {e}")
|
||||||
msg="Error while reading CSR file from disk: {0}".format(e)
|
|
||||||
)
|
|
||||||
|
|
||||||
backend, module_backend = select_backend(
|
backend, module_backend = select_backend(
|
||||||
module, module.params["select_crypto_backend"], data, validate_signature=True
|
module, module.params["select_crypto_backend"], data, validate_signature=True
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ class DHParameterOpenSSL(DHParameterBase):
|
|||||||
try:
|
try:
|
||||||
module.atomic_move(os.path.abspath(tmpsrc), os.path.abspath(self.path))
|
module.atomic_move(os.path.abspath(tmpsrc), os.path.abspath(self.path))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
module.fail_json(msg="Failed to write to file %s: %s" % (self.path, str(e)))
|
module.fail_json(msg=f"Failed to write to file {self.path}: {str(e)}")
|
||||||
|
|
||||||
def _check_params_valid(self, module):
|
def _check_params_valid(self, module):
|
||||||
"""Check if the params are in the correct state"""
|
"""Check if the params are in the correct state"""
|
||||||
@@ -381,8 +381,7 @@ def main():
|
|||||||
if not os.path.isdir(base_dir):
|
if not os.path.isdir(base_dir):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
name=base_dir,
|
name=base_dir,
|
||||||
msg="The directory '%s' does not exist or the file is not a directory"
|
msg=f"The directory '{base_dir}' does not exist or the file is not a directory",
|
||||||
% base_dir,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if module.params["state"] == "present":
|
if module.params["state"] == "present":
|
||||||
@@ -405,9 +404,9 @@ def main():
|
|||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=(
|
||||||
"Cannot detect either the required Python library cryptography (>= {0}) "
|
f"Cannot detect either the required Python library cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION}) "
|
||||||
"or the OpenSSL binary openssl"
|
"or the OpenSSL binary openssl"
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if backend == "openssl":
|
if backend == "openssl":
|
||||||
@@ -416,7 +415,7 @@ def main():
|
|||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -737,24 +737,20 @@ def select_backend(module, backend):
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect the required Python library cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
|
||||||
"Cannot detect the required Python library cryptography (>= {0})"
|
|
||||||
).format(
|
|
||||||
MINIMAL_CRYPTOGRAPHY_VERSION,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
return backend, PkcsCryptography(module)
|
return backend, PkcsCryptography(module)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported value for backend: {0}".format(backend))
|
raise ValueError(f"Unsupported value for backend: {backend}")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -812,8 +808,7 @@ def main():
|
|||||||
if not os.path.isdir(base_dir):
|
if not os.path.isdir(base_dir):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
name=base_dir,
|
name=base_dir,
|
||||||
msg="The directory '%s' does not exist or the path is not a directory"
|
msg=f"The directory '{base_dir}' does not exist or the path is not a directory",
|
||||||
% base_dir,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -862,7 +857,7 @@ def main():
|
|||||||
result = pkcs12.dump()
|
result = pkcs12.dump()
|
||||||
result["changed"] = changed
|
result["changed"] = changed
|
||||||
if os.path.exists(module.params["path"]):
|
if os.path.exists(module.params["path"]):
|
||||||
file_mode = "%04o" % stat.S_IMODE(os.stat(module.params["path"]).st_mode)
|
file_mode = f"{stat.S_IMODE(os.stat(module.params['path']).st_mode):04o}"
|
||||||
result["mode"] = file_mode
|
result["mode"] = file_mode
|
||||||
|
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
|
|||||||
@@ -268,8 +268,7 @@ def main():
|
|||||||
if not os.path.isdir(base_dir):
|
if not os.path.isdir(base_dir):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
name=base_dir,
|
name=base_dir,
|
||||||
msg="The directory %s does not exist or the file is not a directory"
|
msg=f"The directory {base_dir} does not exist or the file is not a directory",
|
||||||
% base_dir,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
backend, module_backend = select_backend(
|
backend, module_backend = select_backend(
|
||||||
|
|||||||
@@ -146,8 +146,7 @@ def main():
|
|||||||
if not os.path.isdir(base_dir):
|
if not os.path.isdir(base_dir):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
name=base_dir,
|
name=base_dir,
|
||||||
msg="The directory %s does not exist or the file is not a directory"
|
msg=f"The directory {base_dir} does not exist or the file is not a directory",
|
||||||
% base_dir,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
module_backend = select_backend(module=module)
|
module_backend = select_backend(module=module)
|
||||||
|
|||||||
@@ -242,8 +242,7 @@ def main():
|
|||||||
data = f.read()
|
data = f.read()
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Error while reading private key file from disk: {0}".format(e),
|
msg=f"Error while reading private key file from disk: {e}", **result
|
||||||
**result,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
result["can_load_key"] = True
|
result["can_load_key"] = True
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ class PublicKey(OpenSSLObject):
|
|||||||
|
|
||||||
if self.privatekey_content is None and not os.path.exists(self.privatekey_path):
|
if self.privatekey_content is None and not os.path.exists(self.privatekey_path):
|
||||||
raise PublicKeyError(
|
raise PublicKeyError(
|
||||||
"The private key %s does not exist" % self.privatekey_path
|
f"The private key {self.privatekey_path} does not exist"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not self.check(module, perms_required=False) or self.force:
|
if not self.check(module, perms_required=False) or self.force:
|
||||||
@@ -461,9 +461,7 @@ def main():
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect the required Python library cryptography (>= {minimal_cryptography_version})",
|
||||||
"Cannot detect the required Python library " "cryptography (>= {0})"
|
|
||||||
).format(minimal_cryptography_version)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if module.params["format"] == "OpenSSH" and backend != "cryptography":
|
if module.params["format"] == "OpenSSH" and backend != "cryptography":
|
||||||
@@ -473,7 +471,7 @@ def main():
|
|||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(minimal_cryptography_version)
|
f"cryptography >= {minimal_cryptography_version}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
@@ -482,8 +480,7 @@ def main():
|
|||||||
if not os.path.isdir(base_dir):
|
if not os.path.isdir(base_dir):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
name=base_dir,
|
name=base_dir,
|
||||||
msg="The directory '%s' does not exist or the file is not a directory"
|
msg=f"The directory '{base_dir}' does not exist or the file is not a directory",
|
||||||
% base_dir,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -190,8 +190,7 @@ def main():
|
|||||||
data = f.read()
|
data = f.read()
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Error while reading public key file from disk: {0}".format(e),
|
msg=f"Error while reading public key file from disk: {e}", **result
|
||||||
**result,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
backend, module_backend = select_backend(
|
backend, module_backend = select_backend(
|
||||||
|
|||||||
@@ -230,9 +230,7 @@ class SignatureCryptography(SignatureBase):
|
|||||||
|
|
||||||
if signature is None:
|
if signature is None:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Unsupported key type. Your cryptography version is {0}".format(
|
msg=f"Unsupported key type. Your cryptography version is {CRYPTOGRAPHY_VERSION}"
|
||||||
CRYPTOGRAPHY_VERSION
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
result["signature"] = base64.b64encode(signature)
|
result["signature"] = base64.b64encode(signature)
|
||||||
@@ -261,7 +259,7 @@ def main():
|
|||||||
if not os.path.isfile(module.params["path"]):
|
if not os.path.isfile(module.params["path"]):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
name=module.params["path"],
|
name=module.params["path"],
|
||||||
msg="The file {0} does not exist".format(module.params["path"]),
|
msg=f"The file {module.params['path']} does not exist",
|
||||||
)
|
)
|
||||||
|
|
||||||
backend = module.params["select_crypto_backend"]
|
backend = module.params["select_crypto_backend"]
|
||||||
@@ -279,16 +277,14 @@ def main():
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect the required Python library cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})",
|
||||||
"Cannot detect the required Python library " "cryptography (>= {0})"
|
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -252,9 +252,7 @@ class SignatureInfoCryptography(SignatureInfoBase):
|
|||||||
|
|
||||||
if not verified:
|
if not verified:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Unsupported key type. Your cryptography version is {0}".format(
|
msg=f"Unsupported key type. Your cryptography version is {CRYPTOGRAPHY_VERSION}"
|
||||||
CRYPTOGRAPHY_VERSION
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
result["valid"] = valid
|
result["valid"] = valid
|
||||||
return result
|
return result
|
||||||
@@ -282,7 +280,7 @@ def main():
|
|||||||
if not os.path.isfile(module.params["path"]):
|
if not os.path.isfile(module.params["path"]):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
name=module.params["path"],
|
name=module.params["path"],
|
||||||
msg="The file {0} does not exist".format(module.params["path"]),
|
msg=f"The file {module.params['path']} does not exist",
|
||||||
)
|
)
|
||||||
|
|
||||||
backend = module.params["select_crypto_backend"]
|
backend = module.params["select_crypto_backend"]
|
||||||
@@ -300,17 +298,14 @@ def main():
|
|||||||
# Success?
|
# Success?
|
||||||
if backend == "auto":
|
if backend == "auto":
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=(
|
msg=f"Cannot detect any of the required Python libraries cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
|
||||||
"Cannot detect any of the required Python libraries "
|
|
||||||
"cryptography (>= {0})"
|
|
||||||
).format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
if backend == "cryptography":
|
if backend == "cryptography":
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -386,8 +386,7 @@ def main():
|
|||||||
if not os.path.isdir(base_dir):
|
if not os.path.isdir(base_dir):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
name=base_dir,
|
name=base_dir,
|
||||||
msg="The directory %s does not exist or the file is not a directory"
|
msg=f"The directory {base_dir} does not exist or the file is not a directory",
|
||||||
% base_dir,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = module.params["provider"]
|
provider = module.params["provider"]
|
||||||
|
|||||||
@@ -152,16 +152,12 @@ def parse_certificate(input, strict=False):
|
|||||||
pems = split_pem_list(to_text(input))
|
pems = split_pem_list(to_text(input))
|
||||||
if len(pems) > 1 and strict:
|
if len(pems) > 1 and strict:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"The input contains {count} PEM objects, expecting only one since strict=true".format(
|
f"The input contains {len(pems)} PEM objects, expecting only one since strict=true"
|
||||||
count=len(pems)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
pem_header_type, content = extract_pem(pems[0], strict=strict)
|
pem_header_type, content = extract_pem(pems[0], strict=strict)
|
||||||
if strict and pem_header_type not in ("CERTIFICATE", "X509 CERTIFICATE"):
|
if strict and pem_header_type not in ("CERTIFICATE", "X509 CERTIFICATE"):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"type is {type!r}, expecting CERTIFICATE or X509 CERTIFICATE".format(
|
f"type is {pem_header_type!r}, expecting CERTIFICATE or X509 CERTIFICATE"
|
||||||
type=pem_header_type
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
input = base64.b64decode(content)
|
input = base64.b64decode(content)
|
||||||
else:
|
else:
|
||||||
@@ -187,18 +183,14 @@ class X509CertificateConvertModule(OpenSSLObject):
|
|||||||
try:
|
try:
|
||||||
self.input = base64.b64decode(self.input)
|
self.input = base64.b64decode(self.input)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Cannot Base64 decode src_content: {exc}")
|
||||||
msg="Cannot Base64 decode src_content: {exc}".format(exc=exc)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
with open(self.src_path, "rb") as f:
|
with open(self.src_path, "rb") as f:
|
||||||
self.input = f.read()
|
self.input = f.read()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Failure while reading file {fn}: {exc}".format(
|
msg=f"Failure while reading file {self.src_path}: {exc}"
|
||||||
fn=self.src_path, exc=exc
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.format = module.params["format"]
|
self.format = module.params["format"]
|
||||||
@@ -210,7 +202,7 @@ class X509CertificateConvertModule(OpenSSLObject):
|
|||||||
self.input, strict=self.strict
|
self.input, strict=self.strict
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
module.fail_json(msg="Error while parsing PEM: {exc}".format(exc=exc))
|
module.fail_json(msg=f"Error while parsing PEM: {exc}")
|
||||||
|
|
||||||
if module.params["verify_cert_parsable"]:
|
if module.params["verify_cert_parsable"]:
|
||||||
self.verify_cert_parsable(module)
|
self.verify_cert_parsable(module)
|
||||||
@@ -237,16 +229,14 @@ class X509CertificateConvertModule(OpenSSLObject):
|
|||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
|
||||||
),
|
),
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
load_der_x509_certificate(self.input, default_backend())
|
load_der_x509_certificate(self.input, default_backend())
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Error while parsing certificate: {exc}")
|
||||||
msg="Error while parsing certificate: {exc}".format(exc=exc)
|
|
||||||
)
|
|
||||||
|
|
||||||
def needs_conversion(self):
|
def needs_conversion(self):
|
||||||
if self.dest_content is None or self.dest_content_format is None:
|
if self.dest_content is None or self.dest_content_format is None:
|
||||||
@@ -263,11 +253,9 @@ class X509CertificateConvertModule(OpenSSLObject):
|
|||||||
if self.format == "der":
|
if self.format == "der":
|
||||||
return self.input
|
return self.input
|
||||||
data = to_bytes(base64.b64encode(self.input))
|
data = to_bytes(base64.b64encode(self.input))
|
||||||
lines = [to_bytes("{0}{1}{2}".format(PEM_START, self.wanted_pem_type, PEM_END))]
|
lines = [to_bytes(f"{PEM_START}{self.wanted_pem_type}{PEM_END}")]
|
||||||
lines += [data[i : i + 64] for i in range(0, len(data), 64)]
|
lines += [data[i : i + 64] for i in range(0, len(data), 64)]
|
||||||
lines.append(
|
lines.append(to_bytes(f"{PEM_END_START}{self.wanted_pem_type}{PEM_END}\n"))
|
||||||
to_bytes("{0}{1}{2}\n".format(PEM_END_START, self.wanted_pem_type, PEM_END))
|
|
||||||
)
|
|
||||||
return b"\n".join(lines)
|
return b"\n".join(lines)
|
||||||
|
|
||||||
def generate(self, module):
|
def generate(self, module):
|
||||||
@@ -323,8 +311,7 @@ def main():
|
|||||||
if not os.path.isdir(base_dir):
|
if not os.path.isdir(base_dir):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
name=base_dir,
|
name=base_dir,
|
||||||
msg="The directory %s does not exist or the file is not a directory"
|
msg=f"The directory {base_dir} does not exist or the file is not a directory",
|
||||||
% base_dir,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -431,9 +431,7 @@ def main():
|
|||||||
with open(module.params["path"], "rb") as f:
|
with open(module.params["path"], "rb") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Error while reading certificate file from disk: {e}")
|
||||||
msg="Error while reading certificate file from disk: {0}".format(e)
|
|
||||||
)
|
|
||||||
|
|
||||||
backend, module_backend = select_backend(
|
backend, module_backend = select_backend(
|
||||||
module, module.params["select_crypto_backend"], data
|
module, module.params["select_crypto_backend"], data
|
||||||
@@ -444,12 +442,10 @@ def main():
|
|||||||
for k, v in valid_at.items():
|
for k, v in valid_at.items():
|
||||||
if not isinstance(v, string_types):
|
if not isinstance(v, string_types):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="The value for valid_at.{0} must be of type string (got {1})".format(
|
msg=f"The value for valid_at.{k} must be of type string (got {type(v)})"
|
||||||
k, type(v)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
valid_at[k] = get_relative_time_option(
|
valid_at[k] = get_relative_time_option(
|
||||||
v, "valid_at.{0}".format(k), with_timezone=CRYPTOGRAPHY_TIMEZONE
|
v, f"valid_at.{k}", with_timezone=CRYPTOGRAPHY_TIMEZONE
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -560,9 +560,7 @@ class CRL(OpenSSLObject):
|
|||||||
|
|
||||||
self.digest = select_message_digest(module.params["digest"])
|
self.digest = select_message_digest(module.params["digest"])
|
||||||
if self.digest is None:
|
if self.digest is None:
|
||||||
raise CRLError(
|
raise CRLError(f'The digest "{module.params["digest"]}" is not supported')
|
||||||
'The digest "{0}" is not supported'.format(module.params["digest"])
|
|
||||||
)
|
|
||||||
|
|
||||||
self.module = module
|
self.module = module
|
||||||
|
|
||||||
@@ -578,7 +576,7 @@ class CRL(OpenSSLObject):
|
|||||||
"invalidity_date": None,
|
"invalidity_date": None,
|
||||||
"invalidity_date_critical": False,
|
"invalidity_date_critical": False,
|
||||||
}
|
}
|
||||||
path_prefix = "revoked_certificates[{0}].".format(i)
|
path_prefix = f"revoked_certificates[{i}]."
|
||||||
if rc["path"] is not None or rc["content"] is not None:
|
if rc["path"] is not None or rc["content"] is not None:
|
||||||
# Load certificate from file or content
|
# Load certificate from file or content
|
||||||
try:
|
try:
|
||||||
@@ -591,15 +589,11 @@ class CRL(OpenSSLObject):
|
|||||||
except OpenSSLObjectError as e:
|
except OpenSSLObjectError as e:
|
||||||
if rc["content"] is not None:
|
if rc["content"] is not None:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Cannot parse certificate from {0}content: {1}".format(
|
msg=f"Cannot parse certificate from {path_prefix}content: {e}"
|
||||||
path_prefix, to_native(e)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg='Cannot read certificate "{1}" from {0}path: {2}'.format(
|
msg=f'Cannot read certificate "{rc["path"]}" from {path_prefix}path: {e}'
|
||||||
path_prefix, rc["path"], to_native(e)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Specify serial_number (and potentially issuer) directly
|
# Specify serial_number (and potentially issuer) directly
|
||||||
@@ -668,23 +662,17 @@ class CRL(OpenSSLObject):
|
|||||||
return check_type_int(value)
|
return check_type_int(value)
|
||||||
except TypeError as exc:
|
except TypeError as exc:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Error while parsing revoked_certificates[{idx}].serial_number as an integer: {exc}".format(
|
msg=f"Error while parsing revoked_certificates[{index + 1}].serial_number as an integer: {exc}"
|
||||||
idx=index + 1,
|
|
||||||
exc=to_native(exc),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if self.serial_numbers_format == "hex-octets":
|
if self.serial_numbers_format == "hex-octets":
|
||||||
try:
|
try:
|
||||||
return parse_serial(check_type_str(value))
|
return parse_serial(check_type_str(value))
|
||||||
except (TypeError, ValueError) as exc:
|
except (TypeError, ValueError) as exc:
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="Error while parsing revoked_certificates[{idx}].serial_number as an colon-separated hex octet string: {exc}".format(
|
msg=f"Error while parsing revoked_certificates[{index + 1}].serial_number as an colon-separated hex octet string: {exc}"
|
||||||
idx=index + 1,
|
|
||||||
exc=to_native(exc),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Unexpected value %s of serial_numbers" % (self.serial_numbers_format,)
|
f"Unexpected value {self.serial_numbers_format} of serial_numbers"
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_info(self, data):
|
def _get_info(self, data):
|
||||||
@@ -1026,9 +1014,7 @@ def main():
|
|||||||
|
|
||||||
if not CRYPTOGRAPHY_FOUND:
|
if not CRYPTOGRAPHY_FOUND:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg=missing_required_lib(
|
msg=missing_required_lib(f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"),
|
||||||
"cryptography >= {0}".format(MINIMAL_CRYPTOGRAPHY_VERSION)
|
|
||||||
),
|
|
||||||
exception=CRYPTOGRAPHY_IMP_ERR,
|
exception=CRYPTOGRAPHY_IMP_ERR,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -207,18 +207,14 @@ def main():
|
|||||||
with open(module.params["path"], "rb") as f:
|
with open(module.params["path"], "rb") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Error while reading CRL file from disk: {e}")
|
||||||
msg="Error while reading CRL file from disk: {0}".format(e)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
data = module.params["content"].encode("utf-8")
|
data = module.params["content"].encode("utf-8")
|
||||||
if not identify_pem_format(data):
|
if not identify_pem_format(data):
|
||||||
try:
|
try:
|
||||||
data = base64.b64decode(module.params["content"])
|
data = base64.b64decode(module.params["content"])
|
||||||
except (binascii.Error, TypeError) as e:
|
except (binascii.Error, TypeError) as e:
|
||||||
module.fail_json(
|
module.fail_json(msg=f"Error while Base64 decoding content: {e}")
|
||||||
msg="Error while Base64 decoding content: {0}".format(e)
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = get_crl_info(
|
result = get_crl_info(
|
||||||
|
|||||||
@@ -99,9 +99,7 @@ class AnsibleActionModule:
|
|||||||
# Before ansible-core 2.14.2, deprecations were always for aliases:
|
# Before ansible-core 2.14.2, deprecations were always for aliases:
|
||||||
if "name" in d:
|
if "name" in d:
|
||||||
self.deprecate(
|
self.deprecate(
|
||||||
"Alias '{name}' is deprecated. See the module docs for more information".format(
|
f"Alias '{d['name']}' is deprecated. See the module docs for more information",
|
||||||
name=d["name"]
|
|
||||||
),
|
|
||||||
version=d.get("version"),
|
version=d.get("version"),
|
||||||
date=d.get("date"),
|
date=d.get("date"),
|
||||||
collection_name=d.get("collection_name"),
|
collection_name=d.get("collection_name"),
|
||||||
@@ -116,19 +114,13 @@ class AnsibleActionModule:
|
|||||||
)
|
)
|
||||||
|
|
||||||
for w in self._validation_result._warnings:
|
for w in self._validation_result._warnings:
|
||||||
self.warn(
|
self.warn(f"Both option {w['option']} and its alias {w['alias']} are set.")
|
||||||
"Both option {option} and its alias {alias} are set.".format(
|
|
||||||
option=w["option"], alias=w["alias"]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Fail for validation errors, even in check mode
|
# Fail for validation errors, even in check mode
|
||||||
if error:
|
if error:
|
||||||
msg = self._validation_result.errors.msg
|
msg = self._validation_result.errors.msg
|
||||||
if isinstance(error, UnsupportedError):
|
if isinstance(error, UnsupportedError):
|
||||||
msg = "Unsupported parameters for ({name}) {kind}: {msg}".format(
|
msg = f"Unsupported parameters for ({self._name}) module: {msg}"
|
||||||
name=self._name, kind="module", msg=msg
|
|
||||||
)
|
|
||||||
|
|
||||||
self.fail_json(msg=msg)
|
self.fail_json(msg=msg)
|
||||||
|
|
||||||
@@ -140,7 +132,7 @@ class AnsibleActionModule:
|
|||||||
if isinstance(warning, string_types):
|
if isinstance(warning, string_types):
|
||||||
self.__warnings.append(warning)
|
self.__warnings.append(warning)
|
||||||
else:
|
else:
|
||||||
raise TypeError("warn requires a string not a %s" % type(warning))
|
raise TypeError(f"warn requires a string not a {type(warning)}")
|
||||||
|
|
||||||
def deprecate(self, msg, version=None, date=None, collection_name=None):
|
def deprecate(self, msg, version=None, date=None, collection_name=None):
|
||||||
if version is not None and date is not None:
|
if version is not None and date is not None:
|
||||||
@@ -161,7 +153,7 @@ class AnsibleActionModule:
|
|||||||
{"msg": msg, "version": version, "collection_name": collection_name}
|
{"msg": msg, "version": version, "collection_name": collection_name}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise TypeError("deprecate requires a string not a %s" % type(msg))
|
raise TypeError(f"deprecate requires a string not a {type(msg)}")
|
||||||
|
|
||||||
def _return_formatted(self, kwargs):
|
def _return_formatted(self, kwargs):
|
||||||
if "invocation" not in kwargs:
|
if "invocation" not in kwargs:
|
||||||
|
|||||||
@@ -44,12 +44,9 @@ class PluginGPGRunner(GPGRunner):
|
|||||||
stdout = to_native(stdout, errors="surrogate_or_replace")
|
stdout = to_native(stdout, errors="surrogate_or_replace")
|
||||||
stderr = to_native(stderr, errors="surrogate_or_replace")
|
stderr = to_native(stderr, errors="surrogate_or_replace")
|
||||||
if check_rc and p.returncode != 0:
|
if check_rc and p.returncode != 0:
|
||||||
|
stdout_n = (to_native(stdout, errors="surrogate_or_replace"),)
|
||||||
|
stderr_n = (to_native(stderr, errors="surrogate_or_replace"),)
|
||||||
raise GPGError(
|
raise GPGError(
|
||||||
'Running {cmd} yielded return code {rc} with stdout: "{stdout}" and stderr: "{stderr}")'.format(
|
f'Running {" ".join(command)} yielded return code {p.returncode} with stdout: "{stdout_n}" and stderr: "{stderr_n}")'
|
||||||
cmd=" ".join(command),
|
|
||||||
rc=p.returncode,
|
|
||||||
stdout=to_native(stdout, errors="surrogate_or_replace"),
|
|
||||||
stderr=to_native(stderr, errors="surrogate_or_replace"),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return p.returncode, stdout, stderr
|
return p.returncode, stdout, stderr
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ TEST_CASES = [
|
|||||||
@pytest.mark.parametrize("value, expected", TEST_CASES)
|
@pytest.mark.parametrize("value, expected", TEST_CASES)
|
||||||
def test_serialize_asn1_string_as_der(value, expected):
|
def test_serialize_asn1_string_as_der(value, expected):
|
||||||
actual = serialize_asn1_string_as_der(value)
|
actual = serialize_asn1_string_as_der(value)
|
||||||
print("%s | %s" % (value, base64.b16encode(actual).decode()))
|
print(f"{value} | {base64.b16encode(actual).decode()}")
|
||||||
assert actual == expected
|
assert actual == expected
|
||||||
|
|
||||||
|
|
||||||
@@ -121,10 +121,8 @@ def test_test_cases(value, expected, tmp_path):
|
|||||||
b_data = fd.read()
|
b_data = fd.read()
|
||||||
|
|
||||||
hex_str = base64.b16encode(b_data).decode().lower()
|
hex_str = base64.b16encode(b_data).decode().lower()
|
||||||
print(
|
value = "\\x".join([hex_str[i : i + 2] for i in range(0, len(hex_str), 2)])
|
||||||
"%s | \\x%s"
|
print(f"{value} | \\x{value}")
|
||||||
% (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.
|
# This is a know edge case where openssl asn1parse does not work properly.
|
||||||
if value != "UTF8:café":
|
if value != "UTF8:café":
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ if (
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_parse_dn_component_failure(name, options, message):
|
def test_parse_dn_component_failure(name, options, message):
|
||||||
with pytest.raises(OpenSSLObjectError, match="^%s$" % re.escape(message)):
|
with pytest.raises(OpenSSLObjectError, match=f"^{re.escape(message)}$"):
|
||||||
_parse_dn_component(name, **options)
|
_parse_dn_component(name, **options)
|
||||||
|
|
||||||
|
|
||||||
@@ -245,5 +245,5 @@ def test_parse_dn(name, expected):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_parse_dn_failure(name, message):
|
def test_parse_dn_failure(name, message):
|
||||||
with pytest.raises(OpenSSLObjectError, match="^%s$" % re.escape(message)):
|
with pytest.raises(OpenSSLObjectError, match=f"^{re.escape(message)}$"):
|
||||||
_parse_dn(name)
|
_parse_dn(name)
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ def test_default_key_params(keytype, size, passphrase, comment):
|
|||||||
"ed25519": 256,
|
"ed25519": 256,
|
||||||
}
|
}
|
||||||
|
|
||||||
default_comment = "%s@%s" % (getuser(), gethostname())
|
default_comment = f"{getuser()}@{gethostname()}"
|
||||||
pair = OpensshKeypair.generate(
|
pair = OpensshKeypair.generate(
|
||||||
keytype=keytype, size=size, passphrase=passphrase, comment=comment
|
keytype=keytype, size=size, passphrase=passphrase, comment=comment
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user