From 84b5d33c62f938754f421dd9a203c11fdf10ec41 Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Fri, 21 Jun 2024 19:23:07 +0200 Subject: [PATCH 1/5] ansible_freeipa_module: New function convert_input_certificates Certificates given by ansible could have leading and trailing white space, but also multi line input is possible that also could have leading and training white space and newlines. New function: - convert_input_certificates(module, certs, state) --- .../module_utils/ansible_freeipa_module.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py index 2f0ebff6..36cc4566 100644 --- a/plugins/module_utils/ansible_freeipa_module.py +++ b/plugins/module_utils/ansible_freeipa_module.py @@ -54,6 +54,7 @@ import tempfile import shutil import socket import base64 +import binascii import ast import time from datetime import datetime @@ -644,6 +645,7 @@ def encode_certificate(cert): Encode a certificate using base64. It also takes FreeIPA and Python versions into account. + This is used to convert the certificates returned by find and show. """ if isinstance(cert, (str, unicode, bytes)): encoded = base64.b64encode(cert) @@ -654,6 +656,33 @@ def encode_certificate(cert): return encoded +def convert_input_certificates(module, certs, state): + """ + Convert certificates. + + Remove all newlines and white spaces from the certificates. + This is used on input parameter certificates of modules. + """ + if certs is None: + return None + + _certs = [] + for cert in certs: + try: + _cert = base64.b64encode(base64.b64decode(cert)).decode("ascii") + except (TypeError, binascii.Error) as e: + # Idempotency: Do not fail for an invalid cert for state absent. + # The invalid certificate can not be set in FreeIPA. + if state == "absent": + continue + module.fail_json( + msg="Certificate %s: Base64 decoding failed: %s" % + (repr(cert), str(e))) + _certs.append(_cert) + + return _certs + + def load_cert_from_str(cert): cert = cert.strip() if not cert.startswith("-----BEGIN CERTIFICATE-----"): From b64da1dbb781e43c8054af9061ea0bec2305e672 Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Fri, 21 Jun 2024 19:24:03 +0200 Subject: [PATCH 2/5] ipaservice: Use new convert_input_certificates Certificates given by ansible could have leading and trailing white space, but also multi line input is possible that also could have leading and training white space and newlines. --- plugins/modules/ipaservice.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/plugins/modules/ipaservice.py b/plugins/modules/ipaservice.py index 6a2e5eb7..c1e9309d 100644 --- a/plugins/modules/ipaservice.py +++ b/plugins/modules/ipaservice.py @@ -378,7 +378,7 @@ RETURN = """ from ansible.module_utils.ansible_freeipa_module import \ IPAAnsibleModule, compare_args_ipa, encode_certificate, \ gen_add_del_lists, gen_add_list, gen_intersection_list, ipalib_errors, \ - api_get_realm, to_text + api_get_realm, to_text, convert_input_certificates from ansible.module_utils import six if six.PY3: unicode = str @@ -601,12 +601,6 @@ def main(): # service attributes principal = ansible_module.params_get("principal") certificate = ansible_module.params_get("certificate") - # Any leading or trailing whitespace is removed while adding the - # certificate with serive_add_cert. To be able to compare the results - # from service_show with the given certificates we have to remove the - # white space also. - if certificate is not None: - certificate = [cert.strip() for cert in certificate] pac_type = ansible_module.params_get( "pac_type", allow_empty_list_item=True) auth_ind = ansible_module.params_get( @@ -636,6 +630,8 @@ def main(): ansible_module.fail_json(msg="At least one name or services is " "required") check_parameters(ansible_module, state, action, names) + certificate = convert_input_certificates(ansible_module, certificate, + state) # Use services if names is None if services is not None: @@ -669,12 +665,8 @@ def main(): service_set.add(name) principal = service.get("principal") certificate = service.get("certificate") - # Any leading or trailing whitespace is removed while adding - # the certificate with serive_add_cert. To be able to compare - # the results from service_show with the given certificates - # we have to remove the white space also. - if certificate is not None: - certificate = [cert.strip() for cert in certificate] + certificate = convert_input_certificates(ansible_module, + certificate, state) pac_type = service.get("pac_type") auth_ind = service.get("auth_ind") check_authind(ansible_module, auth_ind) From 0dc58be3f6556cfe5e920647056716e398ec740b Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Fri, 21 Jun 2024 19:26:07 +0200 Subject: [PATCH 3/5] ipahost: Use new convert_input_certificates Certificates given by ansible could have leading and trailing white space, but also multi line input is possible that also could have leading and training white space and newlines. --- plugins/modules/ipahost.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py index 6600d81d..24acaa36 100644 --- a/plugins/modules/ipahost.py +++ b/plugins/modules/ipahost.py @@ -510,7 +510,8 @@ host: from ansible.module_utils.ansible_freeipa_module import \ IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, \ encode_certificate, is_ipv4_addr, is_ipv6_addr, ipalib_errors, \ - gen_add_list, gen_intersection_list, normalize_sshpubkey + gen_add_list, gen_intersection_list, normalize_sshpubkey, \ + convert_input_certificates from ansible.module_utils import six if six.PY3: unicode = str @@ -682,13 +683,6 @@ def check_authind(module, auth_ind): "by your IPA version" % "','".join(_invalid)) -def convert_certificate(certificate): - if certificate is None: - return None - - return [cert.strip() for cert in certificate] - - # pylint: disable=unused-argument def result_handler(module, result, command, name, args, exit_args, single_host): @@ -894,7 +888,8 @@ def main(): auth_ind, requires_pre_auth, ok_as_delegate, ok_to_auth_as_delegate, force, reverse, ip_address, update_dns, update_password) - certificate = convert_certificate(certificate) + certificate = convert_input_certificates(ansible_module, certificate, + state) if sshpubkey is not None: sshpubkey = [str(normalize_sshpubkey(key)) for key in sshpubkey] @@ -982,7 +977,8 @@ def main(): ok_to_auth_as_delegate, force, reverse, ip_address, update_dns, update_password) - certificate = convert_certificate(certificate) + certificate = convert_input_certificates(ansible_module, + certificate, state) if sshpubkey is not None: sshpubkey = [str(normalize_sshpubkey(key)) for From ef94b703dfb363079f89f98b876dfbbaec0598e4 Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Fri, 21 Jun 2024 19:26:36 +0200 Subject: [PATCH 4/5] ipaidoverrideusere: Use new convert_input_certificates Certificates given by ansible could have leading and trailing white space, but also multi line input is possible that also could have leading and training white space and newlines. --- plugins/modules/ipaidoverrideuser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/modules/ipaidoverrideuser.py b/plugins/modules/ipaidoverrideuser.py index 6714265f..49412ebd 100644 --- a/plugins/modules/ipaidoverrideuser.py +++ b/plugins/modules/ipaidoverrideuser.py @@ -315,7 +315,7 @@ RETURN = """ from ansible.module_utils.ansible_freeipa_module import \ IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, gen_add_list, \ - gen_intersection_list, encode_certificate + gen_intersection_list, encode_certificate, convert_input_certificates from ansible.module_utils import six if six.PY3: @@ -479,8 +479,8 @@ def main(): ansible_module.params_fail_used_invalid(invalid, state, action) - if certificate is not None: - certificate = [cert.strip() for cert in certificate] + certificate = convert_input_certificates(ansible_module, certificate, + state) # Init From b7ccd8fed5453c982e2400838449bf45a2fc251d Mon Sep 17 00:00:00 2001 From: Thomas Woerner Date: Fri, 21 Jun 2024 19:26:54 +0200 Subject: [PATCH 5/5] ipauser: Use new convert_input_certificates Certificates given by ansible could have leading and trailing white space, but also multi line input is possible that also could have leading and training white space and newlines. --- plugins/modules/ipauser.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/plugins/modules/ipauser.py b/plugins/modules/ipauser.py index 36372c4a..f78f23ed 100644 --- a/plugins/modules/ipauser.py +++ b/plugins/modules/ipauser.py @@ -741,7 +741,8 @@ user: from ansible.module_utils.ansible_freeipa_module import \ IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, date_format, \ encode_certificate, load_cert_from_str, DN_x500_text, to_text, \ - ipalib_errors, gen_add_list, gen_intersection_list + ipalib_errors, gen_add_list, gen_intersection_list, \ + convert_input_certificates from ansible.module_utils import six if six.PY3: unicode = str @@ -961,13 +962,6 @@ def extend_emails(email, default_email_domain): return email -def convert_certificate(certificate): - if certificate is None: - return None - - return [cert.strip() for cert in certificate] - - def convert_certmapdata(certmapdata): if certmapdata is None: return None @@ -1260,7 +1254,8 @@ def main(): preserve, update_password, smb_logon_script, smb_profile_path, smb_home_dir, smb_home_drive, idp, idp_user_id, rename, ) - certificate = convert_certificate(certificate) + certificate = convert_input_certificates(ansible_module, certificate, + state) certmapdata = convert_certmapdata(certmapdata) # Init @@ -1371,7 +1366,8 @@ def main(): update_password, smb_logon_script, smb_profile_path, smb_home_dir, smb_home_drive, idp, idp_user_id, rename, ) - certificate = convert_certificate(certificate) + certificate = convert_input_certificates(ansible_module, + certificate, state) certmapdata = convert_certmapdata(certmapdata) # Check API specific parameters