From a762b8126dec8a18ce4b8d46e423c2401e59146f Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 8 Nov 2023 18:02:34 -0500 Subject: [PATCH 01/37] Integration tests for new module Entrust_cagw_certificate Add new module to community.crypto for Entrust CA Gateway that support Entrust and other private/public PKIs. These are the integration tests for the same --- .../entrust_cagw_certificate/tasks/main.yml | 341 ++++++++++++++++++ 1 file changed, 341 insertions(+) create mode 100644 tests/integration/targets/entrust_cagw_certificate/tasks/main.yml diff --git a/tests/integration/targets/entrust_cagw_certificate/tasks/main.yml b/tests/integration/targets/entrust_cagw_certificate/tasks/main.yml new file mode 100644 index 000000000..464b5453b --- /dev/null +++ b/tests/integration/targets/entrust_cagw_certificate/tasks/main.yml @@ -0,0 +1,341 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +#################################################################### +# WARNING: These are designed specifically for Ansible tests # +# and should not be used as examples of how to write Ansible roles # +#################################################################### + +## Verify that integration_config was specified +- block: + - assert: + that: + - cagw_api_client_cert_path is defined + - cagw_api_client_cert_key_path is defined + - entrust_cagw_api_specification_path is defined + +## SET UP TEST ENVIRONMENT ######################################################################## +- name: Clear out the temporary directory for storing the API connection information + file: + path: '{{ tmpdir_path }}' + state: absent + +- name: Create a directory for storing the API connection Information + file: + path: '{{ tmpdir_path }}' + state: directory + +- name: Copy the files needed for the connection to entrust API to the host + copy: + src: '{{ cagw_api_client_cert_path }}' + dest: '{{ entrust_cagw_api_cert }}' + +- name: Copy the files needed for the connection to entrust API to the host + copy: + src: '{{ cagw_api_client_cert_key_path }}' + dest: '{{ entrust_cagw_api_cert_key }}' + +- name: Copy the files needed for the connection to entrust API to the host + copy: + src: '{{ entrust_cagw_api_specification_path }}' + dest: '{{ cagw_api_specification_path }}' + +## SETUP CSR TO REQUEST +- name: Generate a 2048 bit RSA private key + openssl_privatekey: + path: '{{ privatekey_path }}' + passphrase: '{{ privatekey_passphrase }}' + cipher: auto + type: RSA + size: 2048 + +- name: Generate a certificate signing request using the generated key + openssl_csr: + path: '{{ csr_path }}' + privatekey_path: '{{ privatekey_path }}' + privatekey_passphrase: '{{ privatekey_passphrase }}' + common_name: '{{ common_name }}' + organization_name: '{{ organization_name | default(omit) }}' + locality_name: '{{ locality_name }}' + country_name: '{{ country_name | default(omit) }}' + state_or_province_name: '{{ state_or_province_name | default(omit) }}' + digest: sha256 + +- name: Generate a certificate signing request for Microsoft CA using the generated key + openssl_csr: + path: '{{ example11_csr_path }}' + privatekey_path: '{{ privatekey_path }}' + privatekey_passphrase: '{{ privatekey_passphrase }}' + subject: 'CN=sapnaMSCA,DC=igqatestca,DC=dev,DC=datacard,DC=com' + digest: sha256 + +- block: + - name: Request a signed certificate from SM via Entrust CAGW with bare minimum parameters + entrust_cagw_certificate: + path: '{{ example1_cert_path }}' + csr: '{{ csr_path }}' + host: '{{ entrust_host }}' + port: '{{ entrust_port }}' + certificate_authority_id: '{{ example1_ca_id }}' + certificate_profile_id: '{{ example1_profile_id }}' + cagw_api_client_cert_path: '{{ entrust_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ entrust_cagw_api_cert_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + request_type: '{{ example1_request_type }}' + enrollment_format: '{{ example1_enrollment_format }}' + connector_name: SM + force: '{{ force }}' + validate_certs: '{{ validate_certs }}' + register: example1_result + + - assert: + that: + - example1_result is not failed + - example1_result.changed + - example1_result.serialNumber is string + - example1_result.message.message is match("Enrollment was successful.") + + - name: Request a signed certificate from SM via Entrust CAGW with subjectAltName and custom_field parameters + entrust_cagw_certificate: + path: '{{ example2_cert_path }}' + csr: '{{ csr_path }}' + host: '{{ entrust_host }}' + port: '{{ entrust_port }}' + certificate_authority_id: '{{ example1_ca_id }}' + certificate_profile_id: '{{ example1_profile_id }}' + cagw_api_client_cert_path: '{{ entrust_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ entrust_cagw_api_cert_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + request_type: '{{ example1_request_type }}' + enrollment_format: '{{ example1_enrollment_format }}' + connector_name: SM + subject_alt_name: + dNSName: '{{ example2_dNSName }}' + iPAddress: '{{ example2_iPAddress }}' + directoryName: '{{ example2_directoryName }}' + uniformResourceIdentifier: '{{ example2_uniformResourceIdentifier }}' + custom_fields: + text1: '{{ entrust_text1 }}' + text2: '{{ entrust_text2 }}' + number1: '{{ entrust_number1 }}' + date1: '{{ entrust_date1 }}' + email1: '{{ entrust_email1 }}' + force: '{{ force }}' + validate_certs: '{{ validate_certs }}' + register: example2_result + + - assert: + that: + - example2_result is not failed + - example2_result.changed + - example2_result.serialNumber is string + - example2_result.message.message is match("Enrollment was successful.") + + - name: Get an already issued certificate from CAGW with valid serial num in hexadecimal format + entrust_cagw_certificate: + path: '{{ example3_cert_path }}' + cagw_api_client_cert_path: '{{ entrust_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ entrust_cagw_api_cert_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + host: '{{ entrust_host }}' + port: '{{ entrust_port }}' + certificate_authority_id: '{{ example1_ca_id }}' + request_type: '{{ example3_request_type }}' + serial_no: "{{ example2_result['serialNumber'] }}" + validate_certs: '{{ validate_certs }}' + register: example3_result + + - assert: + that: + - example3_result is not failed + - example3_result.cert_details.status is match("normal") + + + - name: Request a PKCS12 from Entrust CAGW + entrust_cagw_certificate: + path: '{{ example4_cert_path }}' + dn: '{{ example4_dn }}' + host: '{{ entrust_host }}' + port: '{{ entrust_port }}' + certificate_authority_id: '{{ example4_ca_id }}' + certificate_profile_id: '{{ example4_profile_id }}' + cagw_api_client_cert_path: '{{ entrust_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ entrust_cagw_api_cert_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + request_type: '{{ example4_request_type }}' + enrollment_format: '{{ example4_enrollment_format }}' + connector_name: SM + p12_protection_password: '{{ example4_p12_password }}' + force: '{{ force }}' + validate_certs: '{{ validate_certs }}' + register: example4_result + + - assert: + that: + - example4_result is not failed + - example4_result.changed + - example4_result.cert_status is match("ACCEPTED") + - example4_result.message.message is match("Enrollment was successful.") + + - name: Request a new SSL certificate from ECS via CAGW with bare minimum parameters. Will request a new certificate + entrust_cagw_certificate: + path: '{{ example5_cert_path }}' + csr: '{{ csr_path }}' + host: '{{ entrust_host }}' + port: '{{ entrust_port }}' + certificate_authority_id: '{{ example5_ca_id }}' + certificate_profile_id: '{{ example5_profile_id }}' + cagw_api_client_cert_path: '{{ entrust_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ entrust_cagw_api_cert_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + request_type: '{{ example5_request_type }}' + enrollment_format: '{{ example5_enrollment_format }}' + connector_name: ECS + requester_name: '{{ entrust_requester_name }}' + requester_email: '{{ entrust_requester_email }}' + requester_phone: '{{ entrust_requester_phone }}' + force: '{{ force }}' + validate_certs: '{{ validate_certs }}' + register: example5_result + + - assert: + that: + - example5_result is not failed + - example5_result.changed + - example5_result.serialNumber is string + - example5_result.message.message is match("Enrollment was successful.") + + - name: Take an action(HoldAction) on certificate already recieved from CAGW + entrust_cagw_certificate: + cagw_api_client_cert_path: '{{ entrust_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ entrust_cagw_api_cert_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + host: '{{ entrust_host }}' + port: '{{ entrust_port }}' + certificate_authority_id: '{{ example1_ca_id }}' + request_type: '{{ example6_request_type }}' + action_type: '{{ example6_action_type }}' + action_reason: '{{ example6_action_reason }}' + serial_no: "{{ example2_result['serialNumber'] }}" + validate_certs: '{{ validate_certs }}' + register: example6_result + + - assert: + that: + - example6_result is not failed + - example6_result.cert_details.status is match("COMPLETED") + + - name: Take an action(UnholdAction) on certificate already recieved from CAGW + entrust_cagw_certificate: + cagw_api_client_cert_path: '{{ entrust_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ entrust_cagw_api_cert_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + host: '{{ entrust_host }}' + port: '{{ entrust_port }}' + certificate_authority_id: '{{ example1_ca_id }}' + request_type: '{{ example7_request_type }}' + action_type: '{{ example7_action_type }}' + action_reason: '{{ example7_action_reason }}' + serial_no: "{{ example2_result['serialNumber'] }}" + validate_certs: '{{ validate_certs }}' + register: example7_result + + - assert: + that: + - example7_result is not failed + - example7_result.cert_details.status is match("COMPLETED") + + - name: Take an action(RevokeAction) on certificate already recieved from CAGW + entrust_cagw_certificate: + cagw_api_client_cert_path: '{{ entrust_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ entrust_cagw_api_cert_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + host: '{{ entrust_host }}' + port: '{{ entrust_port }}' + certificate_authority_id: '{{ example1_ca_id }}' + request_type: '{{ example8_request_type }}' + action_type: '{{ example8_action_type }}' + action_reason: '{{ example8_action_reason }}' + serial_no: "{{ example1_result['serialNumber'] }}" + validate_certs: '{{ validate_certs }}' + register: example8_result + + - assert: + that: + - example8_result is not failed + - example8_result.cert_details.status is match("COMPLETED") + + - name: Get a revoked certificate from CAGW + entrust_cagw_certificate: + path: '{{ example9_cert_path }}' + cagw_api_client_cert_path: '{{ entrust_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ entrust_cagw_api_cert_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + host: '{{ entrust_host }}' + port: '{{ entrust_port }}' + certificate_authority_id: '{{ example1_ca_id }}' + request_type: '{{ example9_request_type }}' + serial_no: "{{ example1_result['serialNumber'] }}" + validate_certs: '{{ validate_certs }}' + register: example9_result + + - assert: + that: + - example9_result is not failed + - example9_result.cert_details.status is match("revoked") + + - name: Enroll a certificate from PKIaas CA via Entrust CAGW + entrust_cagw_certificate: + path: '{{ example10_cert_path }}' + csr: '{{ csr_path }}' + host: '{{ example10_entrust_host }}' + certificate_authority_id: '{{ example10_ca_id }}' + certificate_profile_id: '{{ example10_profile_id }}' + request_type: '{{ example10_request_type }}' + enrollment_format: '{{ example10_enrollment_format }}' + connector_name: PKIaaS + dn: 'CN=SapnaTestCert,O=FG Corp,OU=CHUB DEV,L=Gander,ST=Newfoundland and Labrador,C=CA' + cagw_api_client_cert_path: '{{ example10_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ example10_cagw_api_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + validate_certs: '{{ validate_certs }}' + register: example10_result + + - assert: + that: + - example10_result is not failed + - example10_result.changed + - example10_result.serialNumber is string + - example10_result.message.message is match("Enrollment was successful.") + + - name: Enroll a certificate from Microsoft CA via Entrust CAGW + entrust_cagw_certificate: + path: '{{ example11_cert_path }}' + csr: '{{ example11_csr_path }}' + host: '{{ example11_entrust_host }}' + port: '{{ example11_entrust_port }}' + certificate_authority_id: '{{ example11_ca_id }}' + certificate_profile_id: '{{ example11_profile_id }}' + request_type: '{{ example11_request_type }}' + enrollment_format: '{{ example11_enrollment_format }}' + connector_name: MSCA + cagw_api_client_cert_path: '{{ example11_cagw_api_cert }}' + cagw_api_client_cert_key_path: '{{ example11_cagw_api_key }}' + cagw_api_specification_path: '{{ cagw_api_specification_path }}' + validate_certs: '{{ validate_certs }}' + register: example11_result + + - assert: + that: + - example11_result is not failed + - example11_result.changed + - example11_result.serialNumber is string + - example11_result.message.message is match("Enrollment was successful.") + + always: + - name: clean-up temporary folder + file: + path: '{{ tmpdir_path }}' + state: absent From aa35096a0bb19d819280357ef14df05ba7c0c85e Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 8 Nov 2023 18:34:51 -0500 Subject: [PATCH 02/37] Create api.py --- plugins/module_utils/entrust_cagw/api.py | 347 +++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 plugins/module_utils/entrust_cagw/api.py diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py new file mode 100644 index 000000000..1721f8743 --- /dev/null +++ b/plugins/module_utils/entrust_cagw/api.py @@ -0,0 +1,347 @@ +# -*- coding: utf-8 -*- + +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is licensed under the +# Modified BSD License. Modules you write using this snippet, which is embedded +# dynamically by Ansible, still belong to the author of the module, and may assign +# their own license to the complete work. +# +# Copyright (c), Entrust Datacard Corporation, 2020 +# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) + +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import json +import os +import re +import time +import traceback + +from ansible.module_utils._text import to_text, to_native +from ansible.module_utils.basic import missing_required_lib +from ansible.module_utils.six.moves.urllib.parse import urlencode +from ansible.module_utils.six.moves.urllib.error import HTTPError +from ansible.module_utils.urls import Request + +YAML_IMP_ERR = None +try: + import yaml +except ImportError: + YAML_FOUND = False + YAML_IMP_ERR = traceback.format_exc() +else: + YAML_FOUND = True + +valid_file_format = re.compile(r".*(\.)(yml|yaml|json)$") + + +def cagw_client_argument_spec(): + return dict( + cagw_api_client_cert_path=dict(type='path', required=True), + cagw_api_client_cert_key_path=dict(type='path', required=True), + cagw_api_specification_path=dict(type='path'), + ) + + +class SessionConfigurationException(Exception): + """ Raised if we cannot configure a session with the API """ + + pass + + +class RestOperationException(Exception): + """ Encapsulate a REST API error """ + + def __init__(self, error): + self.status = to_native(error.get("status", None)) + self.errors = [to_native(err.get("message")) for err in error.get("errors", {})] + self.message = to_native(" ".join(self.errors)) + +def generate_docstring(operation_spec): + """Generate a docstring for an operation defined in operation_spec (swagger)""" + # Description of the operation + docs = operation_spec.get("description", "No Description") + docs += "\n\n" + + # Parameters of the operation + parameters = operation_spec.get("parameters", []) + if len(parameters) != 0: + docs += "\tArguments:\n\n" + for parameter in parameters: + docs += "{0} ({1}:{2}): {3}\n".format( + parameter.get("name"), + parameter.get("type", "No Type"), + "Required" if parameter.get("required", False) else "Not Required", + parameter.get("description"), + ) + + return docs + + +def bind(instance, method, operation_spec): + def binding_scope_fn(*args, **kwargs): + return method(instance, *args, **kwargs) + + # Make sure we don't confuse users; add the proper name and documentation to the function. + # Users can use !help() to get help on the function from interactive python or pdb + operation_name = operation_spec.get("operationId").split("Using")[0] + binding_scope_fn.__name__ = str(operation_name) + binding_scope_fn.__doc__ = generate_docstring(operation_spec) + + return binding_scope_fn + + +class RestOperation(object): + def __init__(self, session, uri, method, parameters=None): + self.session = session + self.method = method + self.uri = uri + if parameters is None: + self.parameters = {} + else: + self.parameters = parameters + self.url = "{scheme}://{host}:{port}{base_path}{uri}".format(scheme="https", host=("example.com"), port=("443"), base_path=session._spec.get("basePath"), uri=uri) + + def restmethod(self, *args, **kwargs): + """Do the hard work of making the request here""" + validate_certs_val = kwargs.get("validate_certs", True) + host = kwargs.get("host", None) + port = kwargs.get("port", None) + url = "{scheme}://{host}:{port}{base_path}{uri}".format(scheme="https", host=host, port=port, base_path=self.session._spec.get("basePath"), uri=self.uri) + # gather named path parameters and do substitution on the URL + if self.parameters: + path_parameters = {} + body_parameters = {} + query_parameters = {} + for x in self.parameters: + expected_location = x.get("in") + key_name = x.get("name", None) + key_value = kwargs.get(key_name, None) + if expected_location == "path" and key_name and key_value: + path_parameters.update({key_name: key_value}) + elif expected_location == "body" and key_name and key_value: + body_parameters.update({key_name: key_value}) + elif expected_location == "query" and key_name and key_value: + query_parameters.update({key_name: key_value}) + + if len(body_parameters.keys()) >= 1: + body_parameters = body_parameters.get(list(body_parameters.keys())[0]) + else: + body_parameters = None + else: + path_parameters = {} + query_parameters = {} + body_parameters = None + + # This will fail if we have not set path parameters with a KeyError + url = url.format(**path_parameters) + if query_parameters: + # modify the URL to add query parameters + url = url + "?" + urlencode(query_parameters) + + try: + if body_parameters: + body_parameters_json = json.dumps(body_parameters) + response = self.session.request.open(method=self.method, url=url, data=body_parameters_json, validate_certs=validate_certs_val) + else: + response = self.session.request.open(method=self.method, url=url, validate_certs=validate_certs_val) + request_error = False + except HTTPError as e: + # An HTTPError has the same methods available as a valid response from request.open + response = e + request_error = True + + # Return the result if JSON and success ({} for empty responses) + # Raise an exception if there was a failure. + try: + result_code = response.getcode() + result = json.loads(response.read()) + except ValueError: + result = {} + + if result or result == {}: + if result_code and result_code < 400: + return result + else: + raise RestOperationException(result) + + # Raise a generic RestOperationException if this fails + raise RestOperationException({"status": result_code, "errors": [{"message": "REST Operation Failed"}]}) + + +class Resource(object): + """ Implement basic CRUD operations against a path. """ + + def __init__(self, session): + self.session = session + self.parameters = {} + + for url in session._spec.get("paths").keys(): + methods = session._spec.get("paths").get(url) + for method in methods.keys(): + operation_spec = methods.get(method) + operation_name = operation_spec.get("operationId", None) + parameters = operation_spec.get("parameters") + + if not operation_name: + if method.lower() == "post": + operation_name = "Create" + elif method.lower() == "get": + operation_name = "Get" + elif method.lower() == "put": + operation_name = "Update" + elif method.lower() == "delete": + operation_name = "Delete" + elif method.lower() == "patch": + operation_name = "Patch" + else: + raise SessionConfigurationException(to_native("Invalid REST method type {0}".format(method))) + + # Get the non-parameter parts of the URL and append to the operation name + # e.g /application/version -> GetApplicationVersion + # e.g. /application/{id} -> GetApplication + # This may lead to duplicates, which we must prevent. + operation_name += re.sub(r"{(.*)}", "", url).replace("/", " ").title().replace(" ", "") + operation_spec["operationId"] = operation_name + + op = RestOperation(session, url, method, parameters) + setattr(self, operation_name, bind(self, op.restmethod, operation_spec)) + + +# Session to encapsulate the connection parameters of the module_utils Request object, the api spec, etc +class CAGWSession(object): + def __init__(self, name, **kwargs): + """ + Initialize our session + """ + + self._set_config(name, **kwargs) + + def client(self): + resource = Resource(self) + return resource + + def _set_config(self, name, **kwargs): + headers = { + "Content-Type": "application/json", + "Connection": "keep-alive", + } + self.request = Request(headers=headers, timeout=120) + + configurators = [self._read_config_vars] + for configurator in configurators: + self._config = configurator(name, **kwargs) + if self._config: + break + if self._config is None: + raise SessionConfigurationException(to_native("No Configuration Found.")) + + + # set up client certificate if passed (support all-in one or cert + key) + cagw_api_cert = self.get_config("cagw_api_cert") + cagw_api_cert_key = self.get_config("cagw_api_cert_key") + if cagw_api_cert: + self.request.client_cert = cagw_api_cert + if cagw_api_cert_key: + self.request.client_key = cagw_api_cert_key + else: + raise SessionConfigurationException(to_native("Client certificate for authentication to the API must be provided.")) + + # set up the spec + cagw_api_specification_path = self.get_config("cagw_api_specification_path") + + if not cagw_api_specification_path.startswith("http") and not os.path.isfile(cagw_api_specification_path): + raise SessionConfigurationException(to_native("OpenAPI specification was not found at location {0}.".format(cagw_api_specification_path))) + if not valid_file_format.match(cagw_api_specification_path): + raise SessionConfigurationException(to_native("OpenAPI specification filename must end in .json, .yml or .yaml")) + + self.verify = True + + if cagw_api_specification_path.startswith("http"): + try: + http_response = Request().open(method="GET", url=cagw_api_specification_path) + http_response_contents = http_response.read() + if cagw_api_specification_path.endswith(".json"): + self._spec = json.load(http_response_contents) + elif cagw_api_specification_path.endswith(".yml") or cagw_api_specification_path.endswith(".yaml"): + self._spec = yaml.safe_load(http_response_contents) + except HTTPError as e: + raise SessionConfigurationException(to_native("Error downloading specification from address '{0}', received error code '{1}'".format( + cagw_api_specification_path, e.getcode()))) + else: + with open(cagw_api_specification_path) as f: + if ".json" in cagw_api_specification_path: + self._spec = json.load(f) + elif ".yml" in cagw_api_specification_path or ".yaml" in cagw_api_specification_path: + self._spec = yaml.safe_load(f) + + def get_config(self, item): + return self._config.get(item, None) + + def _read_config_vars(self, name, **kwargs): + """ Read configuration from variables passed to the module. """ + config = {} + + cagw_api_specification_path = kwargs.get("cagw_api_specification_path") + if not cagw_api_specification_path or (not cagw_api_specification_path.startswith("http") and not os.path.isfile(cagw_api_specification_path)): + raise SessionConfigurationException( + to_native( + "Parameter provided for cagw_api_specification_path of value '{0}' was not a valid file path or HTTPS address.".format( + cagw_api_specification_path + ) + ) + ) + + for required_file in ["cagw_api_cert", "cagw_api_cert_key"]: + file_path = kwargs.get(required_file) + if not file_path or not os.path.isfile(file_path): + raise SessionConfigurationException( + to_native("Parameter provided for {0} of value '{1}' was not a valid file path.".format(required_file, file_path)) + ) + + config["cagw_api_cert"] = kwargs.get("cagw_api_cert") + config["cagw_api_cert_key"] = kwargs.get("cagw_api_cert_key") + config["cagw_api_specification_path"] = kwargs.get("cagw_api_specification_path") + + return config + + +def CAGWClient(cagw_api_cert=None, cagw_api_cert_key=None, cagw_api_specification_path=None): + """Create a CAGW client""" + + if not YAML_FOUND: + raise SessionConfigurationException(missing_required_lib("PyYAML"), exception=YAML_IMP_ERR) + + #if cagw_api_specification_path is None: + # cagw_api_specification_path = "https://cloud.entrust.net/EntrustCloud/documentation/cms-api-2.1.0.yaml" + + # Not functionally necessary with current uses of this module_util, but better to be explicit for future use cases + cagw_api_cert_key = to_text(cagw_api_cert_key) + cagw_api_specification_path = to_text(cagw_api_specification_path) + + return CAGWSession( + "entrust_cagw", + cagw_api_cert=cagw_api_cert, + cagw_api_cert_key=cagw_api_cert_key, + cagw_api_specification_path=cagw_api_specification_path, + ).client() From 366760cd8811d050b78e3487109f5d82fcd171a1 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 8 Nov 2023 18:37:00 -0500 Subject: [PATCH 03/37] Create new module for Entrust CAGW New module added to perform certificate requests and management via Certificate Authorities supported by Entrust CAGW --- plugins/modules/entrust_cagw_certificate.py | 870 ++++++++++++++++++++ 1 file changed, 870 insertions(+) create mode 100644 plugins/modules/entrust_cagw_certificate.py diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py new file mode 100644 index 000000000..ea4e8784e --- /dev/null +++ b/plugins/modules/entrust_cagw_certificate.py @@ -0,0 +1,870 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c), Entrust Datacard Corporation, 2019 +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: entrust_cagw_certificate +author: + - Sapna Jain (@jains) +short_description: Request SSL/TLS certificates with the Certificate Authority Gateway (CAGW) API +description: + - Create, get, and take actions (Hold, Unhold, Revoke certificates) with the Certificate Authority Gateway (CAGW) API. + - Requires credentials for calling the CAGW API. +notes: + - C(path) must be specified as the output location of the certificate. +requirements: + - cryptography >= 1.6 +options: + force: + description: + - If force is used, a certificate is requested regardless of whether I(path) points to an existing valid certificate. + type: bool + default: false + path: + description: + - The destination path for the generated certificate as a PEM encoded cert. + - If there is already an Entrust certificate at this location, it will be replaced always. + - If enrollment_format is PKCS12 then it will have Base64 encoded PKCS12 body + type: path + required: true when request_type is new or get + csr: + description: + - Base-64 encoded Certificate Signing Request (CSR). csr is accepted without PEM formatting around the Base-64 string. + - If no csr is provided when request_type=new and enrollment_format=X509, the certificate will not be generated and module will be failed + type: str + required: true(when request_type = new and enrollment_format = X509) + + cagw_api_client_cert_path: + description: + - Path for the Client cert issued by the same CA + type: path + required: true + + cagw_api_client_cert_key_path: + description: + - Path for the Client cert key issued by the same CA + type: path + required: true + + host: + description: + - Host or ip address for Entrust CAGW + type: string + required: true + + port: + description: + - port for Entrust CAGW + type: string + required: true + + certificate_authority_id: + description: + - Unique id for the Certificate Authority + type: string + required: true + + certificate_profile_id: + description: + - Profile id for the Certificate Authority + type: string + required: true when request_type is new + + request_type: + description: + - request type i.e. new (stands for enrollment), get (stands for get certificate), action (stands for action to be taken on the certificate) + type: string + required: true + + enrollment_format: + description: + - enrollment_format i.e. X509 or PKCS12 + type: string + required: true when request_type is new + + validate_certs: + description: + - if set to false then Server validation is skipped + type: bool + default: True + + action_type: + description: + - what action has to be taken on the certificate i.e. RevokeAction, HoldAction, UnholdAction + type: string + required: true when request_type is action + + action_reason: + description: + - reason has to be given for the action + type: string + required: true when request_type is action + + serial_no: + description: + - serial number of the already issued certificate + type: string + required: true when request_type is action or get + + p12_protection_password: + description: + - p12 password for server side generation of the private key and CSR + type: string + required: true when request_type is new and enrollment format is PKCS12 + + dn: + description: + - distinguished name used either for generation for CSR or given in the CAGW enrollment api when enrollment format is PKCS12 + type: string + required: true when request_type is new and enrollment format is PKCS12 + + cagw_api_specification_path: + description: + - path for CAGW api specification doc + type: path + required: false either doc should be available on HTTP server or copy has to be saved locally + + remaining_days: + description: + - The number of days the certificate must have left being valid. + If C(cert_days < remaining_days) then a new certificate will be obtained using I(request_type). + - The I(force) option may be used to ensure that a new certificate is always obtained. + type: int + default: 30 + + connector_name: + description: + - This parameter defines which CA type connected at the backend. Supported list of CAs include ECS, SM, PKIaaS, MSCA + type: str + required: True if I(request_type) is new + + subject_alt_name: + description: + - The subject alternative name identifiers, + type: dict + suboptions: + dNSName: + description: DNS name of the target server + type: str + iPAddress: + description: ip address of the target server + type: str + uniformResourceIdentifier: + description: URI of the target server + type: str + directoryName: + description: directoryName of the target server + type: str + rfc822Name: + description: rfc822 name of the target server + type: str + + tracking_info: + description: Free form tracking information to attach to the record for the certificate. + type: str + requester_name: + description: The requester name to associate with certificate tracking information. + type: str + required: true if I(connector_name) is ECS + requester_email: + description: The requester email to associate with certificate tracking information and receive delivery and expiry notices for the certificate. + type: str + required: true if I(connector_name) is ECS + requester_phone: + description: The requester phone number to associate with certificate tracking information. + type: str + required: true if I(connector_name) is ECS + additional_emails: + description: A list of additional email addresses to receive the delivery notice and expiry notification for the certificate. + type: list + elements: str + + custom_fields: + description: + - Mapping of custom fields to associate with the certificate request and certificate. + - Only supported if custom fields are enabled for your account. + - Each custom field specified must be a custom field you have defined for your account. + type: dict + suboptions: + text1: + description: Custom text field (maximum 500 characters) + type: str + text2: + description: Custom text field (maximum 500 characters) + type: str + text3: + description: Custom text field (maximum 500 characters) + type: str + text4: + description: Custom text field (maximum 500 characters) + type: str + text5: + description: Custom text field (maximum 500 characters) + type: str + text6: + description: Custom text field (maximum 500 characters) + type: str + text7: + description: Custom text field (maximum 500 characters) + type: str + text8: + description: Custom text field (maximum 500 characters) + type: str + text9: + description: Custom text field (maximum 500 characters) + type: str + text10: + description: Custom text field (maximum 500 characters) + type: str + text11: + description: Custom text field (maximum 500 characters) + type: str + text12: + description: Custom text field (maximum 500 characters) + type: str + text13: + description: Custom text field (maximum 500 characters) + type: str + text14: + description: Custom text field (maximum 500 characters) + type: str + text15: + description: Custom text field (maximum 500 characters) + type: str + number1: + description: Custom number field. + type: float + number2: + description: Custom number field. + type: float + number3: + description: Custom number field. + type: float + number4: + description: Custom number field. + type: float + number5: + description: Custom number field. + type: float + date1: + description: Custom date field. + type: str + date2: + description: Custom date field. + type: str + date3: + description: Custom date field. + type: str + date4: + description: Custom date field. + type: str + date5: + description: Custom date field. + type: str + email1: + description: Custom email field. + type: str + email2: + type: str + email3: + description: Custom email field. + type: str + email4: + description: Custom email field. + type: str + email5: + description: Custom email field. + type: str + dropdown1: + description: Custom dropdown field. + type: str + dropdown2: + description: Custom dropdown field. + type: str + dropdown3: + description: Custom dropdown field. + type: str + dropdown4: + description: Custom dropdown field. + type: str + dropdown5: + description: Custom dropdown field. + type: str + description: Custom email field. + +seealso: + - module: community.crypto.openssl_privatekey + description: Can be used to create private keys (both for certificates and accounts). + - module: community.crypto.openssl_csr + description: Can be used to create a Certificate Signing Request (CSR). + +''' + +EXAMPLES = r''' +- name: Request a new certificate from SM via CAGW with bare minimum parameters. Will request a new certificate + community.crypto.entrust_cagw_certificate: + path: /etc/ssl/crt/ansible.com.crt + csr: /etc/ssl/csr/ansible.com.csr + cagw_api_client_cert_path: /etc/ssl/entrust/cagw-client.crt + cagw_api_client_cert_key_path: /etc/ssl/entrust/cagw-client.key + certificate_authority_id: ca_id + certificate_profile_id: profile_id + request_type: new + enrollment_format: X509 + connector_name: SM + cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml + +- name: Request a new certificate from CAGW with subjectAltName parameters and server cert validation is false + community.crypto.entrust_cagw_certificate: + path: /etc/ssl/crt/ansible.com.crt + csr: /etc/ssl/csr/ansible.com.csr + cagw_api_client_cert_path: /etc/ssl/entrust/cagw-client.crt + cagw_api_client_cert_key_path: /etc/ssl/entrust/cagw-client.key + certificate_authority_id: ca_id + certificate_profile_id: profile_id + request_type: new + enrollment_format: X509 + connector_name: SM + cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml + subject_alt_name: + dNSName: server.example.com + iPAddress: 192.168.1.1 + directoryName: cn=john doe,o=example inc,c=us + uniformResourceIdentifier: http://example.com/ + rfc822Name: server.example.com + validate_certs: False + +- name: Get an already issued certificate from CAGW with valid serial num in hexadecimal format + community.crypto.entrust_cagw_certificate: + path: /etc/ssl/crt/ansible.com.crt + cagw_api_client_cert_path: /etc/ssl/entrust/cagw-client.crt + cagw_api_client_cert_key_path: /etc/ssl/entrust/cagw-client.key + certificate_authority_id: ca_id + request_type: get + serial_no: 5b9ba13d + cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml + +- name: Request a certificate from CAGW with enrollment format PKCS12 + community.crypto.entrust_cagw_certificate: + path: /etc/ssl/crt/ansible.com.crt + cagw_api_client_cert_path: /etc/ssl/entrust/cagw-client.crt + cagw_api_client_cert_key_path: /etc/ssl/entrust/cagw-client.key + certificate_authority_id: ca_id + certificate_profile_id: profile_id + request_type: new + enrollment_format: PKCS12 + connector_name: SM + p12_protection_password: 'Entrust@2018' + dn: /C=CA/O=iotrust/CN=CA/CN=ans-test-anurag-101 + cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml + +- name: Request a new SSL certificate from ECS via CAGW with bare minimum parameters. Will request a new certificate + community.crypto.entrust_cagw_certificate: + path: /etc/ssl/crt/ansible.com.crt + csr: /etc/ssl/csr/ansible.com.csr + cagw_api_client_cert_path: /etc/ssl/entrust/cagw-client.crt + cagw_api_client_cert_key_path: /etc/ssl/entrust/cagw-client.key + certificate_authority_id: ca_id + certificate_profile_id: profile_id + request_type: new + enrollment_format: X509 + cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml + connector_name: ECS + requester_name: Sapna-CAGW-server + requester_email: sapna.jain@entrustdatacard.com + requester_phone: 613-222-2222 + +- name: Request a new SSL certificate from ECS via CAGW with optional custom_field parameters. Will request a new certificate + community.crypto.entrust_cagw_certificate: + path: /etc/ssl/crt/ansible.com.crt + csr: /etc/ssl/csr/ansible.com.csr + cagw_api_client_cert_path: /etc/ssl/entrust/cagw-client.crt + cagw_api_client_cert_key_path: /etc/ssl/entrust/cagw-client.key + certificate_authority_id: ca_id + certificate_profile_id: profile_id + request_type: new + enrollment_format: X509 + cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml + connector_name: ECS + requester_name: Sapna-CAGW-server + requester_email: sapna.jain@entrustdatacard.com + requester_phone: 613-222-2222 + custom_fields: + text1: Admin + text2: Invoice 25 + number1: 342 + date1: '2018-01-01' + email1: sales@ansible.testcertificates.com + dropdown1: red + +- name: Take an action(HoldAction) on certificate already recieved from CAGW + community.crypto.entrust_cagw_certificate: + cagw_api_client_cert_path: /etc/ssl/entrust/cagw-client.crt + cagw_api_client_cert_key_path: /etc/ssl/entrust/cagw-client.key + certificate_authority_id: ca_id + request_type: action + action_type: HoldAction + action_reason: unspecified + serial_no: 5b9ba13d + cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml + +- name: Take an action(UnholdAction) on certificate already recieved from CAGW + community.crypto.entrust_cagw_certificate: + cagw_api_client_cert_path: /etc/ssl/entrust/cagw-client.crt + cagw_api_client_cert_key_path: /etc/ssl/entrust/cagw-client.key + certificate_authority_id: ca_id + request_type: action + action_type: UnholdAction + action_reason: unspecified + serial_no: 5b9ba13d + cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml + +- name: Take an action(RevokeAction) on certificate already recieved from CAGW + community.crypto.entrust_cagw_certificate: + cagw_api_client_cert_path: /etc/ssl/entrust/cagw-client.crt + cagw_api_client_cert_key_path: /etc/ssl/entrust/cagw-client.key + certificate_authority_id: ca_id + request_type: action + action_type: RevokeAction + action_reason: unspecified + serial_no: 5b9ba13d + cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml + +''' + +RETURN = ''' +filename: + description: The destination path for the generated certificate or PKCS12. + returned: changed or success + type: str + sample: /etc/ssl/crt/www.ansible.com.crt + +serial_number: + description: The serial number of the issued certificate. + returned: success + type: hexadecimal + sample: 5b9ba13d + +cert_days: + description: The number of days the certificate remains valid. + returned: success + type: int + sample: 253 + +cert_status: + description: + - The certificate status in CAGW. + - 'Possible values are: ACCEPTED, normal, Revoked, Held' + returned: success + type: str + +message: + description: + - Message we get from CAGW. + returned: success + type: dict + +cert_details: + description: + - The full response JSON from the New/Get Certificate call of the CAGW API. + - 'While the response contents are guaranteed to be forwards compatible with new CAGW API releases, Entrust recommends that you do not make any + playbooks take actions based on the content of this field. However it may be useful for debugging, logging, or auditing purposes.' + returned: success + type: dict + +''' + +from ansible_collections.community.crypto.plugins.module_utils.entrust_cagw.api import ( + cagw_client_argument_spec, + CAGWClient, + RestOperationException, + SessionConfigurationException, +) + +import datetime +import os +import re +import time +import traceback + +from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib +from ansible.module_utils._text import to_native, to_bytes + +from ansible_collections.community.crypto.plugins.module_utils.io import ( + write_file, +) + +from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( + load_certificate, +) + +CRYPTOGRAPHY_IMP_ERR = None +try: + import cryptography + CRYPTOGRAPHY_VERSION = LooseVersion(cryptography.__version__) +except ImportError: + CRYPTOGRAPHY_IMP_ERR = traceback.format_exc() + CRYPTOGRAPHY_FOUND = False +else: + CRYPTOGRAPHY_FOUND = True + +MINIMAL_CRYPTOGRAPHY_VERSION = '1.6' + +def calculate_cert_days(validityPeriod): + expiry = validityPeriod.split("/") + expiresAfter = expiry[1] + cert_days = 0 + if expiresAfter: + expires_after_datetime = datetime.datetime.strptime(expiresAfter, '%Y-%m-%dT%H:%M:%SZ') + cert_days = (expires_after_datetime - datetime.datetime.now()).days + return cert_days + + +class CagwCertificate(object): + ''' + CA gateway certificate class + ''' + def __init__(self, module): + self.request_type = module.params['request_type'] + self.path = module.params['path'] + self.force = module.params['force'] + + # All return values + self.changed = False + self.filename = None + self.cert_details = None + self.cert_status = None + self.serialNumber = None + self.cert_days = None + self.message = None + + self.cert = None + self.cagw_client = None + if self.path and os.path.exists(self.path): + try: + self.cert = load_certificate(self.path, backend='cryptography') + except Exception as dummy: + self.cert = None + # Instantiate the CAGW client + try: + self.cagw_client = CAGWClient( + cagw_api_cert=module.params['cagw_api_client_cert_path'], + cagw_api_cert_key=module.params['cagw_api_client_cert_key_path'], + cagw_api_specification_path=module.params['cagw_api_specification_path'] + ) + except SessionConfigurationException as e: + module.fail_json(msg='Failed to initialize Entrust Provider: {0}'.format(to_native(e))) + + def write_cert_to_file(self): + fh = open(self.path, "w") + try: + fh.write(self.cert) + finally: + fh.close() + + def update_csr(self, module): + body = {} + csr = '' + with open(module.params['csr']) as csr_file: + lines = csr_file.readlines() + # Remove first line + lines = lines[1:] + # Remove last line + lines = lines[:-1] + # Remove all linespaces + csr = "".join(line.rstrip("\n") for line in lines) + body['csr'] = csr + return body + + def update_optional_certificate_request_details(self, module): + body = {} + optionalCertificateRequestDetails = {} + optionalCertificateRequestDetails['subjectDn'] = module.params['dn'] + body['optionalCertificateRequestDetails'] = optionalCertificateRequestDetails + return body + + def update_properties(self, module): + body = {} + properties = {} + if module.params['requester_name']: + properties['tracking.requesterName'] = module.params['requester_name'] + if module.params['requester_email']: + properties['tracking.requesterEmail'] = module.params['requester_email'] + if module.params['requester_phone']: + properties['tracking.requesterPhone'] = module.params['requester_phone'] + if module.params['tracking_info']: + properties['tracking.trackingInfo'] = module.params['tracking_info'] + if module.params['additional_emails']: + properties['tracking.additionalEmails'] = module.params['additional_emails'] + if module.params['custom_fields']: + # Omit custom fields from submitted dict if not present, instead of submitting them with value of 'null' + # The ECS API does technically accept null without error, but it complicates debugging user escalations and is unnecessary bandwidth. + for k, v in module.params['custom_fields'].items(): + if v is not None: + key = "tracking.customFields.{k}".format(k=k) + properties[key] = v + body['properties'] = properties + return body + + def update_protection(self, module): + requiredFormat = {} + protection = {} + + protection['type'] = "PasswordProtection" + protection['password'] = module.params['p12_protection_password'] + + requiredFormat['protection'] = protection + return requiredFormat + + def update_required_format(self, module): + body = {} + requiredFormat = {} + module_params_format = module.params['enrollment_format'] + requiredFormat['format'] = module_params_format + if module_params_format == 'PKCS12': + requiredFormat.update(self.update_protection(module)) + body['requiredFormat'] = requiredFormat + return body + + def update_cert_subject_alt_name(self, module): + body = {} + subjectAltNames = [] + if module.params['subject_alt_name']: + for k, v in module.params['subject_alt_name'].items(): + if v is not None: + options = {} + options['type'] = k + options['value'] = v + subjectAltNames.append(options) + body['subjectAltNames'] = subjectAltNames + return body + + def update_action(self, module): + body = {} + action = {} + action['type'] = module.params['action_type'] + action['reason'] = module.params['action_reason'] + body['action'] = action + return body + + def set_cert_details(self, module): + module_params_format = module.params['enrollment_format'] + if module_params_format == 'X509': + self.serialNumber = self.cert_details.get('serialNumber') + self.validityPeriod = self.cert_details.get('validityPeriod') + self.cert_days = calculate_cert_days(self.cert_details.get('validityPeriod')) + + if self.request_type == 'new': + self.cert = self.cert_details.get('body') + elif self.request_type == 'get': + self.cert = self.cert_details.get('certificateData') + + def check(self, module): + if self.cert: + serial_number = "{0:X}".format(self.cert.serial_number) + result = self.cagw_client.GetCertificate(ca_id=module.params['certificate_authority_id'], + serial_no=serial_number, + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) + self.cert_details = result.get('certificate') + # Changing the request type to get since we are getting the certificate here on the basis of + # serial number and we need to populate the cert details on the get response only. + self.request_type = 'get' + self.set_cert_details(module) + # Changing the request back to new + self.request_type = 'new' + + module_params_connector_name = module.params['connector_name'] + #ECS CA getCertificate api through CAGW doesn't return status of the certificate + if module_params_connector_name == 'SM': + self.cert_status = self.cert_details.get('status') + if self.cert_status == 'EXPIRED' or self.cert_status == 'expired' or self.cert_status == 'SUSPENDED' or self.cert_status == 'suspended' or self.cert_status == 'REVOKED' or self.cert_status == 'revoked' or self.cert_status == 'held': + + return False + + if self.cert_days < module.params['remaining_days']: + return False + return True + return False + + def request_cert(self, module): + body = {} + begin_line = "-----BEGIN CERTIFICATE-----\n" + end_line = "\n-----END CERTIFICATE-----" + try: + if self.request_type == 'new': + if self.force or not self.check(module): + body['profileId'] = module.params['certificate_profile_id'] + body.update(self.update_required_format(module)) + body.update(self.update_cert_subject_alt_name(module)) + module_params_format = module.params['enrollment_format'] + body.update(self.update_optional_certificate_request_details(module)) + if module_params_format == 'X509': + body.update(self.update_csr(module)) + module_params_connector_name = module.params['connector_name'] + if module_params_connector_name == 'ECS': + body.update(self.update_properties(module)) + result = self.cagw_client.NewCertRequest(Body=body, ca_id=module.params['certificate_authority_id'], + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) + self.cert_details = result.get('enrollment') + self.set_cert_details(module) + if module_params_format == 'X509': + self.cert = begin_line + self.cert + end_line + self.write_cert_to_file() + self.changed = True + else: + return + elif self.request_type == 'action': + body.update(self.update_action(module)) + result = self.cagw_client.ActionOnCertificate(Body=body, ca_id=module.params['certificate_authority_id'], + serial_no=module.params['serial_no'], + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) + self.cert_details = result.get('action') + elif self.request_type == 'get': + result = self.cagw_client.GetCertificate(ca_id=module.params['certificate_authority_id'], + serial_no=module.params['serial_no'], + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) + self.cert_details = result.get('certificate') + self.set_cert_details(module) + self.cert = begin_line + self.cert + end_line + self.write_cert_to_file() + self.changed = True + except RestOperationException as e: + module.fail_json(msg='Failed to request new certificate from Entrust (CAGW) {0} Error:'.format(e.error.message)) + + self.message = result.get('message') + self.cert_status = self.cert_details.get('status') + + def dump(self): + result = { + 'changed': self.changed, + 'filename': self.path, + 'cert_status': self.cert_status, + 'serialNumber': self.serialNumber, + 'cert_days': self.cert_days, + 'cert_details': self.cert_details, + 'message': self.message, + } + return result + +def custom_fields_spec(): + return dict( + text1=dict(type='str'), + text2=dict(type='str'), + text3=dict(type='str'), + text4=dict(type='str'), + text5=dict(type='str'), + text6=dict(type='str'), + text7=dict(type='str'), + text8=dict(type='str'), + text9=dict(type='str'), + text10=dict(type='str'), + text11=dict(type='str'), + text12=dict(type='str'), + text13=dict(type='str'), + text14=dict(type='str'), + text15=dict(type='str'), + number1=dict(type='float'), + number2=dict(type='float'), + number3=dict(type='float'), + number4=dict(type='float'), + number5=dict(type='float'), + date1=dict(type='str'), + date2=dict(type='str'), + date3=dict(type='str'), + date4=dict(type='str'), + date5=dict(type='str'), + email1=dict(type='str'), + email2=dict(type='str'), + email3=dict(type='str'), + email4=dict(type='str'), + email5=dict(type='str'), + dropdown1=dict(type='str'), + dropdown2=dict(type='str'), + dropdown3=dict(type='str'), + dropdown4=dict(type='str'), + dropdown5=dict(type='str'), + ) + +def subject_alt_name_spec(): + return dict( + dNSName=dict(type='str'), + iPAddress=dict(type='str'), + directoryName=dict(type='str'), + uniformResourceIdentifier=dict(type='str'), + rfc822Name=dict(type='str'), + ) + +def entrust_cagw_certificate_argument_spec(): + return dict( + force=dict(type='bool', default=False), + path=dict(type='path'), + request_type=dict(type='str', required=True, choices=['new', 'action', 'get']), + action_type=dict(type='str', choices=['RevokeAction', 'HoldAction', 'UnholdAction']), + action_reason=dict(type='str'), + enrollment_format=dict(type='str', choices=['X509', 'PKCS12']), + host=dict(type='str', required=True), + port=dict(type='str', default=443), + certificate_authority_id=dict(type='str', required=True), + serial_no=dict(type='str'), + p12_protection_password=dict(type='str'), + dn=dict(type='str'), + certificate_profile_id=dict(type='str'), + csr=dict(type='path'), + remaining_days=dict(type='int', default=30), + connector_name=dict(type='str', choices=['SM', 'ECS', 'PKIaaS', 'MSCA']), + tracking_info=dict(type='str'), + requester_name=dict(type='str'), + requester_email=dict(type='str'), + requester_phone=dict(type='str'), + additional_emails=dict(type='list', elements='str'), + custom_fields=dict(type='dict', default=None, options=custom_fields_spec()), + subject_alt_name=dict(type='dict', default=None, options=subject_alt_name_spec()), + validate_certs=dict(type='bool', default=True), + ) + +def main(): + cagw_argument_spec = cagw_client_argument_spec() + cagw_argument_spec.update(entrust_cagw_certificate_argument_spec()) + module = AnsibleModule( + argument_spec=cagw_argument_spec, + required_if=( + ['request_type', 'new', ['path', 'enrollment_format', 'certificate_profile_id', 'connector_name']], + ['request_type', 'action', ['action_type', 'serial_no', 'action_reason']], + ['request_type', 'get', ['path', 'serial_no']], + ['enrollment_format', 'X509', ['csr']], + ['enrollment_format', 'PKCS12', ['p12_protection_password', 'dn']], + ['connector_name', 'ECS', ['requester_name', 'requester_email', 'requester_phone']], + ) + ) + if not CRYPTOGRAPHY_FOUND or CRYPTOGRAPHY_VERSION < LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION): + module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), + exception=CRYPTOGRAPHY_IMP_ERR) + + # A new x509 based enrollment request must have the csr field + if module.params['request_type'] == 'new': + module_params_format = module.params['enrollment_format'] + if module_params_format == "X509": + module_params_csr = module.params['csr'] + if not os.path.exists(module_params_csr): + module.fail_json(msg='The csr field of {0} was not a valid path. csr is required when request_type={1} with enrollment_format={2}' .format( + module_params_csr, module.params['request_type'], module_params_format)) + + certificate = CagwCertificate(module) + certificate.request_cert(module) + result = certificate.dump() + module.exit_json(**result) + +if __name__ == '__main__': + main() From 9bcd7317dca47adcdc28fa68237450f568f11162 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 8 Nov 2023 18:38:41 -0500 Subject: [PATCH 04/37] Integration tests vars file --- .../entrust_cagw_certificate/vars/main.yml | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 tests/integration/targets/entrust_cagw_certificate/vars/main.yml diff --git a/tests/integration/targets/entrust_cagw_certificate/vars/main.yml b/tests/integration/targets/entrust_cagw_certificate/vars/main.yml new file mode 100644 index 000000000..bd7274f23 --- /dev/null +++ b/tests/integration/targets/entrust_cagw_certificate/vars/main.yml @@ -0,0 +1,118 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +# vars file for test_entrust_cagw_certificate + +# Path on various hosts that cacerts need to be put as a prerequisite to API server cert validation. +# May need to be customized for some environments based on SSL implementations +# that ansible "urls" module utility is using as a backing. +cacerts_bundle_path: /etc/pki/tls/certs + +common_name: Default Company Ltd +organization_name: CEG +locality_name: Kanata +country_name: CA +state_or_province_name: ontario +privatekey_passphrase: Passphrase2525! +tmpdir_path: /tmp/entrust_cagw_cert_test/{{ ansible_date_time.epoch }} +privatekey_path: '{{ tmpdir_path }}/testcertificates.key' +entrust_cagw_api_cert: '{{ tmpdir_path }}/authcert.cer' +entrust_cagw_api_cert_key: '{{ tmpdir_path }}/authkey.cer' +csr_path: '{{ tmpdir_path }}/request.csr' +cagw_api_specification_path: '{{ tmpdir_path }}/api_spec.yml' + + +entrust_requester_name: Sapna Jain +entrust_requester_email: sapna.jain@entrust.com +entrust_requester_phone: 1-613-555-5555 # e.g. 16135555555 +entrust_tracking_info: 3-232-32 +remaining_days: 30 +force: true +entrust_text1: Admin +entrust_text2: Invoice 25 +entrust_number1: 342 +entrust_date1: 2018-01-01 +entrust_email1: sales@ansible.testcertificates.com +validate_certs: False +entrust_host: 10.1.188.25 +entrust_port: 8080 + +# TEST 1 +example1_cert_path: '{{ tmpdir_path }}/issuedcert_1.pem' +example1_request_type: new +example1_enrollment_format: X509 +#example1_ca_id: cafedbf4a48d40dd99c3ce9fba7e14e0 +#example1_profile_id: c7a08b56-5aa0-11eb-ae93-0242ac130002 +example1_ca_id: CA02 +example1_profile_id: ent_wstep_sig + +# TEST 2 +example2_cert_path: '{{ tmpdir_path }}/issuedcert_2.pem' +example2_dNSName: dmspsjAnsibleSSL.idm.dev.entrust.com +example2_iPAddress: 10.1.140.145 +example2_directoryName: cn=john doe,o=example inc,c=us +example2_uniformResourceIdentifier: http://example.com/ + +# TEST 3 +example3_cert_path: '{{ tmpdir_path }}/issuedcert_3.pem' +example3_request_type: get + +# TEST 4 +example4_cert_path: '{{ tmpdir_path }}/issuedcert_4.pem' +example4_request_type: new +example4_enrollment_format: PKCS12 +example4_ca_id: CA02 +example4_profile_id: ent_mdm_p12_enc +example4_p12_password: Entrust@2018 +example4_dn: CN=dmspsjAnsibleSSL.idm.dev.entrust.com,O=entrust,C=CA + +#TEST 5 +example5_cert_path: '{{ tmpdir_path }}/issuedcert_5.pem' +example5_request_type: new +example5_enrollment_format: X509 +example5_ca_id: ecs-ca-class3 +example5_profile_id: class3-ecs-cds-ent-lite + +#TEST 6 +example6_request_type: action +example6_action_type: HoldAction +example6_action_reason: Certificate is not valid anymore + +#TEST 7 +example7_request_type: action +example7_action_type: UnholdAction +example7_action_reason: Certificate can be unheld + +#TEST 8 +example8_request_type: action +example8_action_type: RevokeAction +example8_action_reason: unspecified + +#TEST 9 +example9_request_type: get +example9_cert_path: '{{ tmpdir_path }}/issuedcert_9.pem' + +# TEST 10 +example10_entrust_host: cagw.pkiaas.entrust.com +example10_dn: /C=CA/ST=Newfoundland\ and\ Labrador/L=Gander/O=FG\ Corp/OU=CHUB\ DEV/CN=QATestRunCreate +example10_cert_path: '{{ tmpdir_path }}/issuedcert_10.pem' +example10_request_type: new +example10_enrollment_format: X509 +example10_ca_id: ecsyv8zyvohnb7~odegsifgpbupnc +example10_profile_id: privatessl-tls-server +example10_cagw_api_cert: /tmp/cert_pkiaas.pem +example10_cagw_api_key: /tmp/key_pkiaas.pem + +# TEST 11 +example11_entrust_host: 10.1.140.40 +example11_entrust_port: 8080 +example11_csr_path: '{{ tmpdir_path }}/msca.csr' +example11_cert_path: '{{ tmpdir_path }}/issuedcert_11.pem' +example11_request_type: new +example11_enrollment_format: X509 +example11_ca_id: msca-zuosheng +example11_profile_id: IG-Dual-Usage +example11_cagw_api_cert: /tmp/cert_msca.pem +example11_cagw_api_key: /tmp/key_msca.pem From dc5c38b96fbcb591cc2d64be77310dbe063e55bb Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 8 Nov 2023 18:39:50 -0500 Subject: [PATCH 05/37] Create main.yml --- .../targets/entrust_cagw_certificate/defaults/main.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/integration/targets/entrust_cagw_certificate/defaults/main.yml diff --git a/tests/integration/targets/entrust_cagw_certificate/defaults/main.yml b/tests/integration/targets/entrust_cagw_certificate/defaults/main.yml new file mode 100644 index 000000000..2c4e9e80b --- /dev/null +++ b/tests/integration/targets/entrust_cagw_certificate/defaults/main.yml @@ -0,0 +1,6 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +# defaults file for test_entrust_cagw_certificate From 262fe735b20fd37188d86ddd9e3a6982de592296 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 8 Nov 2023 18:40:22 -0500 Subject: [PATCH 06/37] Create main.yml --- .../targets/entrust_cagw_certificate/meta/main.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/integration/targets/entrust_cagw_certificate/meta/main.yml diff --git a/tests/integration/targets/entrust_cagw_certificate/meta/main.yml b/tests/integration/targets/entrust_cagw_certificate/meta/main.yml new file mode 100644 index 000000000..b7fbb90f9 --- /dev/null +++ b/tests/integration/targets/entrust_cagw_certificate/meta/main.yml @@ -0,0 +1,8 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +dependencies: + - prepare_tests + - setup_openssl From eaa719bfdffad2370c8d979db9c7a1f3eccde783 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 8 Nov 2023 18:41:12 -0500 Subject: [PATCH 07/37] Integration test changes --- .../integration/targets/entrust_cagw_certificate/aliases | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/integration/targets/entrust_cagw_certificate/aliases diff --git a/tests/integration/targets/entrust_cagw_certificate/aliases b/tests/integration/targets/entrust_cagw_certificate/aliases new file mode 100644 index 000000000..0e959136e --- /dev/null +++ b/tests/integration/targets/entrust_cagw_certificate/aliases @@ -0,0 +1,9 @@ +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +# Example integation_config.yml +# --- +# cagw_api_client_cert_path: /var/integration-testing/publicCert.pem +# cagw_api_client_cert_key_path: /var/integration-testing/privateKey.pem +# entrust_cagw_api_specification_path: /var/integration-testing/cagw-api.yml From fc146fc33f33f3982477d5072a27e236f4f3b764 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 8 Nov 2023 19:03:40 -0500 Subject: [PATCH 08/37] fixed documentation related issue --- plugins/modules/entrust_cagw_certificate.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index ea4e8784e..035d558a8 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -32,13 +32,11 @@ - If there is already an Entrust certificate at this location, it will be replaced always. - If enrollment_format is PKCS12 then it will have Base64 encoded PKCS12 body type: path - required: true when request_type is new or get csr: description: - Base-64 encoded Certificate Signing Request (CSR). csr is accepted without PEM formatting around the Base-64 string. - If no csr is provided when request_type=new and enrollment_format=X509, the certificate will not be generated and module will be failed type: str - required: true(when request_type = new and enrollment_format = X509) cagw_api_client_cert_path: description: @@ -74,7 +72,6 @@ description: - Profile id for the Certificate Authority type: string - required: true when request_type is new request_type: description: @@ -86,7 +83,6 @@ description: - enrollment_format i.e. X509 or PKCS12 type: string - required: true when request_type is new validate_certs: description: @@ -98,37 +94,31 @@ description: - what action has to be taken on the certificate i.e. RevokeAction, HoldAction, UnholdAction type: string - required: true when request_type is action action_reason: description: - reason has to be given for the action type: string - required: true when request_type is action serial_no: description: - serial number of the already issued certificate type: string - required: true when request_type is action or get p12_protection_password: description: - p12 password for server side generation of the private key and CSR type: string - required: true when request_type is new and enrollment format is PKCS12 dn: description: - distinguished name used either for generation for CSR or given in the CAGW enrollment api when enrollment format is PKCS12 type: string - required: true when request_type is new and enrollment format is PKCS12 cagw_api_specification_path: description: - path for CAGW api specification doc type: path - required: false either doc should be available on HTTP server or copy has to be saved locally remaining_days: description: @@ -142,7 +132,6 @@ description: - This parameter defines which CA type connected at the backend. Supported list of CAs include ECS, SM, PKIaaS, MSCA type: str - required: True if I(request_type) is new subject_alt_name: description: @@ -171,15 +160,12 @@ requester_name: description: The requester name to associate with certificate tracking information. type: str - required: true if I(connector_name) is ECS requester_email: description: The requester email to associate with certificate tracking information and receive delivery and expiry notices for the certificate. type: str - required: true if I(connector_name) is ECS requester_phone: description: The requester phone number to associate with certificate tracking information. type: str - required: true if I(connector_name) is ECS additional_emails: description: A list of additional email addresses to receive the delivery notice and expiry notification for the certificate. type: list From 9b02496e3d6a9e5b99f1e58fec4b91072dc5526b Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 8 Nov 2023 19:10:57 -0500 Subject: [PATCH 09/37] Fixed for documentation --- plugins/modules/entrust_cagw_certificate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 035d558a8..670091a83 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -434,7 +434,7 @@ serial_number: description: The serial number of the issued certificate. returned: success - type: hexadecimal + type: str sample: 5b9ba13d cert_days: From 299fa614b2f3d6df5368a1cb9dd8d9283bb3b421 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 8 Nov 2023 21:15:17 -0500 Subject: [PATCH 10/37] Update entrust_cagw_certificate.py to fix errors --- plugins/modules/entrust_cagw_certificate.py | 36 ++++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 670091a83..819ca097d 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -25,7 +25,7 @@ description: - If force is used, a certificate is requested regardless of whether I(path) points to an existing valid certificate. type: bool - default: false + default: False path: description: - The destination path for the generated certificate as a PEM encoded cert. @@ -36,7 +36,7 @@ description: - Base-64 encoded Certificate Signing Request (CSR). csr is accepted without PEM formatting around the Base-64 string. - If no csr is provided when request_type=new and enrollment_format=X509, the certificate will not be generated and module will be failed - type: str + type: path cagw_api_client_cert_path: description: @@ -53,36 +53,38 @@ host: description: - Host or ip address for Entrust CAGW - type: string + type: str required: true port: description: - port for Entrust CAGW - type: string - required: true + type: str + default: 443 certificate_authority_id: description: - Unique id for the Certificate Authority - type: string + type: str required: true certificate_profile_id: description: - Profile id for the Certificate Authority - type: string + type: str request_type: description: - request type i.e. new (stands for enrollment), get (stands for get certificate), action (stands for action to be taken on the certificate) - type: string + type: str + choices: [ 'new', 'action', 'get' ] required: true enrollment_format: description: - enrollment_format i.e. X509 or PKCS12 - type: string + type: str + choices: [ 'X509', 'PKCS12' ] validate_certs: description: @@ -93,27 +95,28 @@ action_type: description: - what action has to be taken on the certificate i.e. RevokeAction, HoldAction, UnholdAction - type: string + type: str + choices: [ 'RevokeAction', 'HoldAction', 'UnholdAction'] action_reason: description: - reason has to be given for the action - type: string + type: str serial_no: description: - serial number of the already issued certificate - type: string + type: str p12_protection_password: description: - p12 password for server side generation of the private key and CSR - type: string + type: str dn: description: - distinguished name used either for generation for CSR or given in the CAGW enrollment api when enrollment format is PKCS12 - type: string + type: str cagw_api_specification_path: description: @@ -132,6 +135,7 @@ description: - This parameter defines which CA type connected at the backend. Supported list of CAs include ECS, SM, PKIaaS, MSCA type: str + choices: [ 'SM', 'ECS', 'PKIaaS', 'MSCA' ] subject_alt_name: description: @@ -258,6 +262,7 @@ type: str email2: type: str + description: Custom email field. email3: description: Custom email field. type: str @@ -282,7 +287,6 @@ dropdown5: description: Custom dropdown field. type: str - description: Custom email field. seealso: - module: community.crypto.openssl_privatekey @@ -804,7 +808,7 @@ def entrust_cagw_certificate_argument_spec(): port=dict(type='str', default=443), certificate_authority_id=dict(type='str', required=True), serial_no=dict(type='str'), - p12_protection_password=dict(type='str'), + p12_protection_password=dict(type='str', no_log=True), dn=dict(type='str'), certificate_profile_id=dict(type='str'), csr=dict(type='path'), From 7cb9643344b776abe32751db19862dadc2928263 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:20:52 -0500 Subject: [PATCH 11/37] Update plugins/modules/entrust_cagw_certificate.py Co-authored-by: Felix Fontein --- plugins/modules/entrust_cagw_certificate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 819ca097d..a4e9b68f7 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -3,6 +3,7 @@ # Copyright (c), Entrust Datacard Corporation, 2019 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later from __future__ import absolute_import, division, print_function __metaclass__ = type From e6345cf565a211f5b4ad5018be68ae796e59a447 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:21:03 -0500 Subject: [PATCH 12/37] Update tests/integration/targets/entrust_cagw_certificate/aliases Co-authored-by: Felix Fontein --- tests/integration/targets/entrust_cagw_certificate/aliases | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration/targets/entrust_cagw_certificate/aliases b/tests/integration/targets/entrust_cagw_certificate/aliases index 0e959136e..96e05fcaf 100644 --- a/tests/integration/targets/entrust_cagw_certificate/aliases +++ b/tests/integration/targets/entrust_cagw_certificate/aliases @@ -2,6 +2,8 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later +unsupported + # Example integation_config.yml # --- # cagw_api_client_cert_path: /var/integration-testing/publicCert.pem From 91b569f308baed648d72a3f9325f973868191aca Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:22:03 -0500 Subject: [PATCH 13/37] Update plugins/module_utils/entrust_cagw/api.py Co-authored-by: Felix Fontein --- plugins/module_utils/entrust_cagw/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py index 1721f8743..e7c5bd824 100644 --- a/plugins/module_utils/entrust_cagw/api.py +++ b/plugins/module_utils/entrust_cagw/api.py @@ -290,7 +290,7 @@ def _set_config(self, name, **kwargs): cagw_api_specification_path, e.getcode()))) else: with open(cagw_api_specification_path) as f: - if ".json" in cagw_api_specification_path: + if cagw_api_specification_path.endswith(".json"): self._spec = json.load(f) elif ".yml" in cagw_api_specification_path or ".yaml" in cagw_api_specification_path: self._spec = yaml.safe_load(f) From f2a809df7d567b7606c2e81a3d0d0fa930e6a0ed Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:26:30 -0500 Subject: [PATCH 14/37] Update plugins/modules/entrust_cagw_certificate.py Co-authored-by: Felix Fontein --- plugins/modules/entrust_cagw_certificate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index a4e9b68f7..d48ce249b 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -31,7 +31,7 @@ description: - The destination path for the generated certificate as a PEM encoded cert. - If there is already an Entrust certificate at this location, it will be replaced always. - - If enrollment_format is PKCS12 then it will have Base64 encoded PKCS12 body + - If O(enrollment_format=PKCS12) then it will have Base64 encoded PKCS12 body. type: path csr: description: From f9a6534e556b82a7c7e6c8e66d0229fbe790b008 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:29:40 -0500 Subject: [PATCH 15/37] Update plugins/modules/entrust_cagw_certificate.py Co-authored-by: Felix Fontein --- plugins/modules/entrust_cagw_certificate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index d48ce249b..767b44442 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -53,7 +53,7 @@ host: description: - - Host or ip address for Entrust CAGW + - Host or IP address for Entrust CAGW. type: str required: true From ca58d26424604a96eb2ec931c2528446cd3a08ac Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:44:40 -0500 Subject: [PATCH 16/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 90 +++++++++++---------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 767b44442..2e0d11216 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -36,18 +36,18 @@ csr: description: - Base-64 encoded Certificate Signing Request (CSR). csr is accepted without PEM formatting around the Base-64 string. - - If no csr is provided when request_type=new and enrollment_format=X509, the certificate will not be generated and module will be failed + - If no csr is provided when O(request_type=new) and O(enrollment_format=X509), the certificate will not be generated and module will be failed. type: path cagw_api_client_cert_path: description: - - Path for the Client cert issued by the same CA + - Path for the Client cert issued by the same CA. type: path required: true cagw_api_client_cert_key_path: description: - - Path for the Client cert key issued by the same CA + - Path for the Client cert key issued by the same CA. type: path required: true @@ -59,69 +59,71 @@ port: description: - - port for Entrust CAGW + - port for Entrust CAGW. type: str default: 443 certificate_authority_id: description: - - Unique id for the Certificate Authority + - Unique id for the Certificate Authority. type: str required: true certificate_profile_id: description: - - Profile id for the Certificate Authority + - Profile id for the Certificate Authority. type: str request_type: description: - - request type i.e. new (stands for enrollment), get (stands for get certificate), action (stands for action to be taken on the certificate) + - request type that is new (stands for enrollment), get (stands for get certificate), + action (stands for action to be taken on the certificate). type: str choices: [ 'new', 'action', 'get' ] required: true enrollment_format: description: - - enrollment_format i.e. X509 or PKCS12 + - enrollment_format that is X509 or PKCS12. type: str choices: [ 'X509', 'PKCS12' ] validate_certs: description: - - if set to false then Server validation is skipped + - if set to false then SSL validation with Server is skipped. + This should be set to false only for testing purposes. type: bool default: True action_type: description: - - what action has to be taken on the certificate i.e. RevokeAction, HoldAction, UnholdAction + - what action has to be taken on the certificate that is RevokeAction, HoldAction, UnholdAction. type: str choices: [ 'RevokeAction', 'HoldAction', 'UnholdAction'] action_reason: description: - - reason has to be given for the action + - reason has to be given for the action. type: str serial_no: description: - - serial number of the already issued certificate + - serial number of the already issued certificate. type: str p12_protection_password: description: - - p12 password for server side generation of the private key and CSR + - p12 password for server side generation of the private key and CSR. type: str dn: description: - - distinguished name used either for generation for CSR or given in the CAGW enrollment api when enrollment format is PKCS12 + - distinguished name used either for generation for CSR or given in the CAGW enrollment api when O(enrollment format=PKCS12). type: str cagw_api_specification_path: description: - - path for CAGW api specification doc + - path for CAGW api specification doc. type: path remaining_days: @@ -134,29 +136,31 @@ connector_name: description: - - This parameter defines which CA type connected at the backend. Supported list of CAs include ECS, SM, PKIaaS, MSCA + - This parameter defines which CA type connected at the backend. + Supported list of CAs include Entrust Certificate Solution(ECS), Entrust Security Manager(SM), + Entrust PKIHUB CA(PKIaaS), Microsoft CA(MSCA). type: str choices: [ 'SM', 'ECS', 'PKIaaS', 'MSCA' ] subject_alt_name: description: - - The subject alternative name identifiers, + - The subject alternative name identifiers. type: dict suboptions: dNSName: - description: DNS name of the target server + description: DNS name of the target server. type: str iPAddress: - description: ip address of the target server + description: IP address of the target server. type: str uniformResourceIdentifier: - description: URI of the target server + description: URI of the target server. type: str directoryName: - description: directoryName of the target server + description: directoryName of the target server. type: str rfc822Name: - description: rfc822 name of the target server + description: rfc822 name of the target server. type: str tracking_info: @@ -166,7 +170,8 @@ description: The requester name to associate with certificate tracking information. type: str requester_email: - description: The requester email to associate with certificate tracking information and receive delivery and expiry notices for the certificate. + description: The requester email to associate with certificate tracking information and + receive delivery and expiry notices for the certificate. type: str requester_phone: description: The requester phone number to associate with certificate tracking information. @@ -184,49 +189,49 @@ type: dict suboptions: text1: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text2: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text3: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text4: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text5: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text6: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text7: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text8: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text9: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text10: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text11: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text12: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text13: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text14: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str text15: - description: Custom text field (maximum 500 characters) + description: Custom text field (maximum 500 characters). type: str number1: description: Custom number field. @@ -290,9 +295,9 @@ type: str seealso: - - module: community.crypto.openssl_privatekey + - M(community.crypto.openssl_privatekey) description: Can be used to create private keys (both for certificates and accounts). - - module: community.crypto.openssl_csr + - M(community.crypto.openssl_csr) description: Can be used to create a Certificate Signing Request (CSR). ''' @@ -464,8 +469,9 @@ cert_details: description: - The full response JSON from the New/Get Certificate call of the CAGW API. - - 'While the response contents are guaranteed to be forwards compatible with new CAGW API releases, Entrust recommends that you do not make any - playbooks take actions based on the content of this field. However it may be useful for debugging, logging, or auditing purposes.' + - While the response contents are guaranteed to be forwards compatible with new CAGW API releases, + Entrust recommends that you do not make any playbooks take actions based on the content of this field. + However it may be useful for debugging, logging, or auditing purposes. returned: success type: dict From 9ebe1cdc562f2f719c24572600e98d6b1879638e Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:45:44 -0500 Subject: [PATCH 17/37] Update api.py --- plugins/module_utils/entrust_cagw/api.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py index e7c5bd824..4cc2fdcd4 100644 --- a/plugins/module_utils/entrust_cagw/api.py +++ b/plugins/module_utils/entrust_cagw/api.py @@ -7,7 +7,8 @@ # their own license to the complete work. # # Copyright (c), Entrust Datacard Corporation, 2020 -# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: @@ -294,6 +295,8 @@ def _set_config(self, name, **kwargs): self._spec = json.load(f) elif ".yml" in cagw_api_specification_path or ".yaml" in cagw_api_specification_path: self._spec = yaml.safe_load(f) + else: + raise SessionConfigurationException(to_native("OpenAPI specification filename must end in .json, .yml or .yaml")) def get_config(self, item): return self._config.get(item, None) From 892db8c02f9cc1c40c44132b6cc30b012bd2755f Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:50:11 -0500 Subject: [PATCH 18/37] Update api.py --- plugins/module_utils/entrust_cagw/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py index 4cc2fdcd4..197b2a459 100644 --- a/plugins/module_utils/entrust_cagw/api.py +++ b/plugins/module_utils/entrust_cagw/api.py @@ -2,7 +2,7 @@ # This code is part of Ansible, but is an independent component. # This particular file snippet, and this file snippet only, is licensed under the -# Modified BSD License. Modules you write using this snippet, which is embedded +# GNU General Public License v3.0+. Modules you write using this snippet, which is embedded # dynamically by Ansible, still belong to the author of the module, and may assign # their own license to the complete work. # From e089d49abf102f664b437073f85f884753c56941 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:05:44 -0500 Subject: [PATCH 19/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 2e0d11216..0c732f9d4 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -295,9 +295,9 @@ type: str seealso: - - M(community.crypto.openssl_privatekey) + - module: community.crypto.openssl_privatekey description: Can be used to create private keys (both for certificates and accounts). - - M(community.crypto.openssl_csr) + - module: community.crypto.openssl_csr description: Can be used to create a Certificate Signing Request (CSR). ''' From b8bffb4eb9edb8883ec4e35226bcd5ce3ea8e9b3 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:39:31 -0500 Subject: [PATCH 20/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 0c732f9d4..3c2179be7 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -118,7 +118,7 @@ dn: description: - - distinguished name used either for generation for CSR or given in the CAGW enrollment api when O(enrollment format=PKCS12). + - distinguished name used either for generation for CSR or given in the CAGW enrollment api when O(enrollment_format=PKCS12). type: str cagw_api_specification_path: From 1d9b04a536356286dafcf56effe75675d34d280a Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 13:10:50 -0500 Subject: [PATCH 21/37] Update api.py --- plugins/module_utils/entrust_cagw/api.py | 48 ++++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py index 197b2a459..e510a14ab 100644 --- a/plugins/module_utils/entrust_cagw/api.py +++ b/plugins/module_utils/entrust_cagw/api.py @@ -58,10 +58,10 @@ def cagw_client_argument_spec(): return dict( - cagw_api_client_cert_path=dict(type='path', required=True), - cagw_api_client_cert_key_path=dict(type='path', required=True), - cagw_api_specification_path=dict(type='path'), - ) + cagw_api_client_cert_path=dict(type='path', required=True), + cagw_api_client_cert_key_path=dict(type='path', required=True), + cagw_api_specification_path=dict(type='path'), + ) class SessionConfigurationException(Exception): @@ -90,11 +90,11 @@ def generate_docstring(operation_spec): docs += "\tArguments:\n\n" for parameter in parameters: docs += "{0} ({1}:{2}): {3}\n".format( - parameter.get("name"), - parameter.get("type", "No Type"), - "Required" if parameter.get("required", False) else "Not Required", - parameter.get("description"), - ) + parameter.get("name"), + parameter.get("type", "No Type"), + "Required" if parameter.get("required", False) else "Not Required", + parameter.get("description"), + ) return docs @@ -244,9 +244,9 @@ def client(self): def _set_config(self, name, **kwargs): headers = { - "Content-Type": "application/json", - "Connection": "keep-alive", - } + "Content-Type": "application/json", + "Connection": "keep-alive", + } self.request = Request(headers=headers, timeout=120) configurators = [self._read_config_vars] @@ -308,19 +308,19 @@ def _read_config_vars(self, name, **kwargs): cagw_api_specification_path = kwargs.get("cagw_api_specification_path") if not cagw_api_specification_path or (not cagw_api_specification_path.startswith("http") and not os.path.isfile(cagw_api_specification_path)): raise SessionConfigurationException( - to_native( - "Parameter provided for cagw_api_specification_path of value '{0}' was not a valid file path or HTTPS address.".format( - cagw_api_specification_path + to_native( + "Parameter provided for cagw_api_specification_path of value '{0}' was not a valid file path or HTTPS address.".format( + cagw_api_specification_path + ) + ) ) - ) - ) for required_file in ["cagw_api_cert", "cagw_api_cert_key"]: file_path = kwargs.get(required_file) if not file_path or not os.path.isfile(file_path): raise SessionConfigurationException( - to_native("Parameter provided for {0} of value '{1}' was not a valid file path.".format(required_file, file_path)) - ) + to_native("Parameter provided for {0} of value '{1}' was not a valid file path.".format(required_file, file_path)) + ) config["cagw_api_cert"] = kwargs.get("cagw_api_cert") config["cagw_api_cert_key"] = kwargs.get("cagw_api_cert_key") @@ -343,8 +343,8 @@ def CAGWClient(cagw_api_cert=None, cagw_api_cert_key=None, cagw_api_specificatio cagw_api_specification_path = to_text(cagw_api_specification_path) return CAGWSession( - "entrust_cagw", - cagw_api_cert=cagw_api_cert, - cagw_api_cert_key=cagw_api_cert_key, - cagw_api_specification_path=cagw_api_specification_path, - ).client() + "entrust_cagw", + cagw_api_cert=cagw_api_cert, + cagw_api_cert_key=cagw_api_cert_key, + cagw_api_specification_path=cagw_api_specification_path, + ).client() From 7d6dc54e8bd521f014cb07a3e9d44f4bb6c7b3fe Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 13:11:46 -0500 Subject: [PATCH 22/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 236 ++++++++++---------- 1 file changed, 118 insertions(+), 118 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 3c2179be7..036176ea9 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -478,11 +478,11 @@ ''' from ansible_collections.community.crypto.plugins.module_utils.entrust_cagw.api import ( - cagw_client_argument_spec, - CAGWClient, - RestOperationException, - SessionConfigurationException, -) + cagw_client_argument_spec, + CAGWClient, + RestOperationException, + SessionConfigurationException, + ) import datetime import os @@ -496,12 +496,12 @@ from ansible.module_utils._text import to_native, to_bytes from ansible_collections.community.crypto.plugins.module_utils.io import ( - write_file, -) + write_file, + ) from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( - load_certificate, -) + load_certificate, + ) CRYPTOGRAPHY_IMP_ERR = None try: @@ -553,25 +553,25 @@ def __init__(self, module): # Instantiate the CAGW client try: self.cagw_client = CAGWClient( - cagw_api_cert=module.params['cagw_api_client_cert_path'], - cagw_api_cert_key=module.params['cagw_api_client_cert_key_path'], - cagw_api_specification_path=module.params['cagw_api_specification_path'] - ) + cagw_api_cert=module.params['cagw_api_client_cert_path'], + cagw_api_cert_key=module.params['cagw_api_client_cert_key_path'], + cagw_api_specification_path=module.params['cagw_api_specification_path'] + ) except SessionConfigurationException as e: module.fail_json(msg='Failed to initialize Entrust Provider: {0}'.format(to_native(e))) def write_cert_to_file(self): fh = open(self.path, "w") try: - fh.write(self.cert) + fh.write(self.cert) finally: - fh.close() + fh.close() def update_csr(self, module): body = {} csr = '' with open(module.params['csr']) as csr_file: - lines = csr_file.readlines() + lines = csr_file.readlines() # Remove first line lines = lines[1:] # Remove last line @@ -660,7 +660,7 @@ def set_cert_details(self, module): self.cert_days = calculate_cert_days(self.cert_details.get('validityPeriod')) if self.request_type == 'new': - self.cert = self.cert_details.get('body') + self.cert = self.cert_details.get('body') elif self.request_type == 'get': self.cert = self.cert_details.get('certificateData') @@ -668,9 +668,9 @@ def check(self, module): if self.cert: serial_number = "{0:X}".format(self.cert.serial_number) result = self.cagw_client.GetCertificate(ca_id=module.params['certificate_authority_id'], - serial_no=serial_number, - validate_certs=module.params['validate_certs'], - host=module.params['host'], port=module.params['port']) + serial_no=serial_number, + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) self.cert_details = result.get('certificate') # Changing the request type to get since we are getting the certificate here on the basis of # serial number and we need to populate the cert details on the get response only. @@ -682,10 +682,10 @@ def check(self, module): module_params_connector_name = module.params['connector_name'] #ECS CA getCertificate api through CAGW doesn't return status of the certificate if module_params_connector_name == 'SM': - self.cert_status = self.cert_details.get('status') + self.cert_status = self.cert_details.get('status') if self.cert_status == 'EXPIRED' or self.cert_status == 'expired' or self.cert_status == 'SUSPENDED' or self.cert_status == 'suspended' or self.cert_status == 'REVOKED' or self.cert_status == 'revoked' or self.cert_status == 'held': - return False + return False if self.cert_days < module.params['remaining_days']: return False @@ -710,8 +710,8 @@ def request_cert(self, module): if module_params_connector_name == 'ECS': body.update(self.update_properties(module)) result = self.cagw_client.NewCertRequest(Body=body, ca_id=module.params['certificate_authority_id'], - validate_certs=module.params['validate_certs'], - host=module.params['host'], port=module.params['port']) + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) self.cert_details = result.get('enrollment') self.set_cert_details(module) if module_params_format == 'X509': @@ -723,15 +723,15 @@ def request_cert(self, module): elif self.request_type == 'action': body.update(self.update_action(module)) result = self.cagw_client.ActionOnCertificate(Body=body, ca_id=module.params['certificate_authority_id'], - serial_no=module.params['serial_no'], - validate_certs=module.params['validate_certs'], - host=module.params['host'], port=module.params['port']) + serial_no=module.params['serial_no'], + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) self.cert_details = result.get('action') elif self.request_type == 'get': result = self.cagw_client.GetCertificate(ca_id=module.params['certificate_authority_id'], - serial_no=module.params['serial_no'], - validate_certs=module.params['validate_certs'], - host=module.params['host'], port=module.params['port']) + serial_no=module.params['serial_no'], + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) self.cert_details = result.get('certificate') self.set_cert_details(module) self.cert = begin_line + self.cert + end_line @@ -745,109 +745,109 @@ def request_cert(self, module): def dump(self): result = { - 'changed': self.changed, - 'filename': self.path, - 'cert_status': self.cert_status, - 'serialNumber': self.serialNumber, - 'cert_days': self.cert_days, - 'cert_details': self.cert_details, - 'message': self.message, - } + 'changed': self.changed, + 'filename': self.path, + 'cert_status': self.cert_status, + 'serialNumber': self.serialNumber, + 'cert_days': self.cert_days, + 'cert_details': self.cert_details, + 'message': self.message, + } return result def custom_fields_spec(): return dict( - text1=dict(type='str'), - text2=dict(type='str'), - text3=dict(type='str'), - text4=dict(type='str'), - text5=dict(type='str'), - text6=dict(type='str'), - text7=dict(type='str'), - text8=dict(type='str'), - text9=dict(type='str'), - text10=dict(type='str'), - text11=dict(type='str'), - text12=dict(type='str'), - text13=dict(type='str'), - text14=dict(type='str'), - text15=dict(type='str'), - number1=dict(type='float'), - number2=dict(type='float'), - number3=dict(type='float'), - number4=dict(type='float'), - number5=dict(type='float'), - date1=dict(type='str'), - date2=dict(type='str'), - date3=dict(type='str'), - date4=dict(type='str'), - date5=dict(type='str'), - email1=dict(type='str'), - email2=dict(type='str'), - email3=dict(type='str'), - email4=dict(type='str'), - email5=dict(type='str'), - dropdown1=dict(type='str'), - dropdown2=dict(type='str'), - dropdown3=dict(type='str'), - dropdown4=dict(type='str'), - dropdown5=dict(type='str'), - ) + text1=dict(type='str'), + text2=dict(type='str'), + text3=dict(type='str'), + text4=dict(type='str'), + text5=dict(type='str'), + text6=dict(type='str'), + text7=dict(type='str'), + text8=dict(type='str'), + text9=dict(type='str'), + text10=dict(type='str'), + text11=dict(type='str'), + text12=dict(type='str'), + text13=dict(type='str'), + text14=dict(type='str'), + text15=dict(type='str'), + number1=dict(type='float'), + number2=dict(type='float'), + number3=dict(type='float'), + number4=dict(type='float'), + number5=dict(type='float'), + date1=dict(type='str'), + date2=dict(type='str'), + date3=dict(type='str'), + date4=dict(type='str'), + date5=dict(type='str'), + email1=dict(type='str'), + email2=dict(type='str'), + email3=dict(type='str'), + email4=dict(type='str'), + email5=dict(type='str'), + dropdown1=dict(type='str'), + dropdown2=dict(type='str'), + dropdown3=dict(type='str'), + dropdown4=dict(type='str'), + dropdown5=dict(type='str'), + ) def subject_alt_name_spec(): return dict( - dNSName=dict(type='str'), - iPAddress=dict(type='str'), - directoryName=dict(type='str'), - uniformResourceIdentifier=dict(type='str'), - rfc822Name=dict(type='str'), - ) + dNSName=dict(type='str'), + iPAddress=dict(type='str'), + directoryName=dict(type='str'), + uniformResourceIdentifier=dict(type='str'), + rfc822Name=dict(type='str'), + ) def entrust_cagw_certificate_argument_spec(): - return dict( - force=dict(type='bool', default=False), - path=dict(type='path'), - request_type=dict(type='str', required=True, choices=['new', 'action', 'get']), - action_type=dict(type='str', choices=['RevokeAction', 'HoldAction', 'UnholdAction']), - action_reason=dict(type='str'), - enrollment_format=dict(type='str', choices=['X509', 'PKCS12']), - host=dict(type='str', required=True), - port=dict(type='str', default=443), - certificate_authority_id=dict(type='str', required=True), - serial_no=dict(type='str'), - p12_protection_password=dict(type='str', no_log=True), - dn=dict(type='str'), - certificate_profile_id=dict(type='str'), - csr=dict(type='path'), - remaining_days=dict(type='int', default=30), - connector_name=dict(type='str', choices=['SM', 'ECS', 'PKIaaS', 'MSCA']), - tracking_info=dict(type='str'), - requester_name=dict(type='str'), - requester_email=dict(type='str'), - requester_phone=dict(type='str'), - additional_emails=dict(type='list', elements='str'), - custom_fields=dict(type='dict', default=None, options=custom_fields_spec()), - subject_alt_name=dict(type='dict', default=None, options=subject_alt_name_spec()), - validate_certs=dict(type='bool', default=True), + return dict( + force=dict(type='bool', default=False), + path=dict(type='path'), + request_type=dict(type='str', required=True, choices=['new', 'action', 'get']), + action_type=dict(type='str', choices=['RevokeAction', 'HoldAction', 'UnholdAction']), + action_reason=dict(type='str'), + enrollment_format=dict(type='str', choices=['X509', 'PKCS12']), + host=dict(type='str', required=True), + port=dict(type='str', default=443), + certificate_authority_id=dict(type='str', required=True), + serial_no=dict(type='str'), + p12_protection_password=dict(type='str', no_log=True), + dn=dict(type='str'), + certificate_profile_id=dict(type='str'), + csr=dict(type='path'), + remaining_days=dict(type='int', default=30), + connector_name=dict(type='str', choices=['SM', 'ECS', 'PKIaaS', 'MSCA']), + tracking_info=dict(type='str'), + requester_name=dict(type='str'), + requester_email=dict(type='str'), + requester_phone=dict(type='str'), + additional_emails=dict(type='list', elements='str'), + custom_fields=dict(type='dict', default=None, options=custom_fields_spec()), + subject_alt_name=dict(type='dict', default=None, options=subject_alt_name_spec()), + validate_certs=dict(type='bool', default=True), ) def main(): - cagw_argument_spec = cagw_client_argument_spec() + cagw_argument_spec = cagw_client_argument_spec() cagw_argument_spec.update(entrust_cagw_certificate_argument_spec()) module = AnsibleModule( - argument_spec=cagw_argument_spec, - required_if=( - ['request_type', 'new', ['path', 'enrollment_format', 'certificate_profile_id', 'connector_name']], - ['request_type', 'action', ['action_type', 'serial_no', 'action_reason']], - ['request_type', 'get', ['path', 'serial_no']], - ['enrollment_format', 'X509', ['csr']], - ['enrollment_format', 'PKCS12', ['p12_protection_password', 'dn']], - ['connector_name', 'ECS', ['requester_name', 'requester_email', 'requester_phone']], - ) - ) + argument_spec=cagw_argument_spec, + required_if=( + ['request_type', 'new', ['path', 'enrollment_format', 'certificate_profile_id', 'connector_name']], + ['request_type', 'action', ['action_type', 'serial_no', 'action_reason']], + ['request_type', 'get', ['path', 'serial_no']], + ['enrollment_format', 'X509', ['csr']], + ['enrollment_format', 'PKCS12', ['p12_protection_password', 'dn']], + ['connector_name', 'ECS', ['requester_name', 'requester_email', 'requester_phone']], + ) + ) if not CRYPTOGRAPHY_FOUND or CRYPTOGRAPHY_VERSION < LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION): module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), - exception=CRYPTOGRAPHY_IMP_ERR) + exception=CRYPTOGRAPHY_IMP_ERR) # A new x509 based enrollment request must have the csr field if module.params['request_type'] == 'new': @@ -856,7 +856,7 @@ def main(): module_params_csr = module.params['csr'] if not os.path.exists(module_params_csr): module.fail_json(msg='The csr field of {0} was not a valid path. csr is required when request_type={1} with enrollment_format={2}' .format( - module_params_csr, module.params['request_type'], module_params_format)) + module_params_csr, module.params['request_type'], module_params_format)) certificate = CagwCertificate(module) certificate.request_cert(module) From b34374820d9a4f7f14c50801b49bd7cf054387de Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:14:18 -0500 Subject: [PATCH 23/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 236 ++++++++++---------- 1 file changed, 118 insertions(+), 118 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 036176ea9..3c2179be7 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -478,11 +478,11 @@ ''' from ansible_collections.community.crypto.plugins.module_utils.entrust_cagw.api import ( - cagw_client_argument_spec, - CAGWClient, - RestOperationException, - SessionConfigurationException, - ) + cagw_client_argument_spec, + CAGWClient, + RestOperationException, + SessionConfigurationException, +) import datetime import os @@ -496,12 +496,12 @@ from ansible.module_utils._text import to_native, to_bytes from ansible_collections.community.crypto.plugins.module_utils.io import ( - write_file, - ) + write_file, +) from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( - load_certificate, - ) + load_certificate, +) CRYPTOGRAPHY_IMP_ERR = None try: @@ -553,25 +553,25 @@ def __init__(self, module): # Instantiate the CAGW client try: self.cagw_client = CAGWClient( - cagw_api_cert=module.params['cagw_api_client_cert_path'], - cagw_api_cert_key=module.params['cagw_api_client_cert_key_path'], - cagw_api_specification_path=module.params['cagw_api_specification_path'] - ) + cagw_api_cert=module.params['cagw_api_client_cert_path'], + cagw_api_cert_key=module.params['cagw_api_client_cert_key_path'], + cagw_api_specification_path=module.params['cagw_api_specification_path'] + ) except SessionConfigurationException as e: module.fail_json(msg='Failed to initialize Entrust Provider: {0}'.format(to_native(e))) def write_cert_to_file(self): fh = open(self.path, "w") try: - fh.write(self.cert) + fh.write(self.cert) finally: - fh.close() + fh.close() def update_csr(self, module): body = {} csr = '' with open(module.params['csr']) as csr_file: - lines = csr_file.readlines() + lines = csr_file.readlines() # Remove first line lines = lines[1:] # Remove last line @@ -660,7 +660,7 @@ def set_cert_details(self, module): self.cert_days = calculate_cert_days(self.cert_details.get('validityPeriod')) if self.request_type == 'new': - self.cert = self.cert_details.get('body') + self.cert = self.cert_details.get('body') elif self.request_type == 'get': self.cert = self.cert_details.get('certificateData') @@ -668,9 +668,9 @@ def check(self, module): if self.cert: serial_number = "{0:X}".format(self.cert.serial_number) result = self.cagw_client.GetCertificate(ca_id=module.params['certificate_authority_id'], - serial_no=serial_number, - validate_certs=module.params['validate_certs'], - host=module.params['host'], port=module.params['port']) + serial_no=serial_number, + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) self.cert_details = result.get('certificate') # Changing the request type to get since we are getting the certificate here on the basis of # serial number and we need to populate the cert details on the get response only. @@ -682,10 +682,10 @@ def check(self, module): module_params_connector_name = module.params['connector_name'] #ECS CA getCertificate api through CAGW doesn't return status of the certificate if module_params_connector_name == 'SM': - self.cert_status = self.cert_details.get('status') + self.cert_status = self.cert_details.get('status') if self.cert_status == 'EXPIRED' or self.cert_status == 'expired' or self.cert_status == 'SUSPENDED' or self.cert_status == 'suspended' or self.cert_status == 'REVOKED' or self.cert_status == 'revoked' or self.cert_status == 'held': - return False + return False if self.cert_days < module.params['remaining_days']: return False @@ -710,8 +710,8 @@ def request_cert(self, module): if module_params_connector_name == 'ECS': body.update(self.update_properties(module)) result = self.cagw_client.NewCertRequest(Body=body, ca_id=module.params['certificate_authority_id'], - validate_certs=module.params['validate_certs'], - host=module.params['host'], port=module.params['port']) + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) self.cert_details = result.get('enrollment') self.set_cert_details(module) if module_params_format == 'X509': @@ -723,15 +723,15 @@ def request_cert(self, module): elif self.request_type == 'action': body.update(self.update_action(module)) result = self.cagw_client.ActionOnCertificate(Body=body, ca_id=module.params['certificate_authority_id'], - serial_no=module.params['serial_no'], - validate_certs=module.params['validate_certs'], - host=module.params['host'], port=module.params['port']) + serial_no=module.params['serial_no'], + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) self.cert_details = result.get('action') elif self.request_type == 'get': result = self.cagw_client.GetCertificate(ca_id=module.params['certificate_authority_id'], - serial_no=module.params['serial_no'], - validate_certs=module.params['validate_certs'], - host=module.params['host'], port=module.params['port']) + serial_no=module.params['serial_no'], + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) self.cert_details = result.get('certificate') self.set_cert_details(module) self.cert = begin_line + self.cert + end_line @@ -745,109 +745,109 @@ def request_cert(self, module): def dump(self): result = { - 'changed': self.changed, - 'filename': self.path, - 'cert_status': self.cert_status, - 'serialNumber': self.serialNumber, - 'cert_days': self.cert_days, - 'cert_details': self.cert_details, - 'message': self.message, - } + 'changed': self.changed, + 'filename': self.path, + 'cert_status': self.cert_status, + 'serialNumber': self.serialNumber, + 'cert_days': self.cert_days, + 'cert_details': self.cert_details, + 'message': self.message, + } return result def custom_fields_spec(): return dict( - text1=dict(type='str'), - text2=dict(type='str'), - text3=dict(type='str'), - text4=dict(type='str'), - text5=dict(type='str'), - text6=dict(type='str'), - text7=dict(type='str'), - text8=dict(type='str'), - text9=dict(type='str'), - text10=dict(type='str'), - text11=dict(type='str'), - text12=dict(type='str'), - text13=dict(type='str'), - text14=dict(type='str'), - text15=dict(type='str'), - number1=dict(type='float'), - number2=dict(type='float'), - number3=dict(type='float'), - number4=dict(type='float'), - number5=dict(type='float'), - date1=dict(type='str'), - date2=dict(type='str'), - date3=dict(type='str'), - date4=dict(type='str'), - date5=dict(type='str'), - email1=dict(type='str'), - email2=dict(type='str'), - email3=dict(type='str'), - email4=dict(type='str'), - email5=dict(type='str'), - dropdown1=dict(type='str'), - dropdown2=dict(type='str'), - dropdown3=dict(type='str'), - dropdown4=dict(type='str'), - dropdown5=dict(type='str'), - ) + text1=dict(type='str'), + text2=dict(type='str'), + text3=dict(type='str'), + text4=dict(type='str'), + text5=dict(type='str'), + text6=dict(type='str'), + text7=dict(type='str'), + text8=dict(type='str'), + text9=dict(type='str'), + text10=dict(type='str'), + text11=dict(type='str'), + text12=dict(type='str'), + text13=dict(type='str'), + text14=dict(type='str'), + text15=dict(type='str'), + number1=dict(type='float'), + number2=dict(type='float'), + number3=dict(type='float'), + number4=dict(type='float'), + number5=dict(type='float'), + date1=dict(type='str'), + date2=dict(type='str'), + date3=dict(type='str'), + date4=dict(type='str'), + date5=dict(type='str'), + email1=dict(type='str'), + email2=dict(type='str'), + email3=dict(type='str'), + email4=dict(type='str'), + email5=dict(type='str'), + dropdown1=dict(type='str'), + dropdown2=dict(type='str'), + dropdown3=dict(type='str'), + dropdown4=dict(type='str'), + dropdown5=dict(type='str'), + ) def subject_alt_name_spec(): return dict( - dNSName=dict(type='str'), - iPAddress=dict(type='str'), - directoryName=dict(type='str'), - uniformResourceIdentifier=dict(type='str'), - rfc822Name=dict(type='str'), - ) + dNSName=dict(type='str'), + iPAddress=dict(type='str'), + directoryName=dict(type='str'), + uniformResourceIdentifier=dict(type='str'), + rfc822Name=dict(type='str'), + ) def entrust_cagw_certificate_argument_spec(): - return dict( - force=dict(type='bool', default=False), - path=dict(type='path'), - request_type=dict(type='str', required=True, choices=['new', 'action', 'get']), - action_type=dict(type='str', choices=['RevokeAction', 'HoldAction', 'UnholdAction']), - action_reason=dict(type='str'), - enrollment_format=dict(type='str', choices=['X509', 'PKCS12']), - host=dict(type='str', required=True), - port=dict(type='str', default=443), - certificate_authority_id=dict(type='str', required=True), - serial_no=dict(type='str'), - p12_protection_password=dict(type='str', no_log=True), - dn=dict(type='str'), - certificate_profile_id=dict(type='str'), - csr=dict(type='path'), - remaining_days=dict(type='int', default=30), - connector_name=dict(type='str', choices=['SM', 'ECS', 'PKIaaS', 'MSCA']), - tracking_info=dict(type='str'), - requester_name=dict(type='str'), - requester_email=dict(type='str'), - requester_phone=dict(type='str'), - additional_emails=dict(type='list', elements='str'), - custom_fields=dict(type='dict', default=None, options=custom_fields_spec()), - subject_alt_name=dict(type='dict', default=None, options=subject_alt_name_spec()), - validate_certs=dict(type='bool', default=True), + return dict( + force=dict(type='bool', default=False), + path=dict(type='path'), + request_type=dict(type='str', required=True, choices=['new', 'action', 'get']), + action_type=dict(type='str', choices=['RevokeAction', 'HoldAction', 'UnholdAction']), + action_reason=dict(type='str'), + enrollment_format=dict(type='str', choices=['X509', 'PKCS12']), + host=dict(type='str', required=True), + port=dict(type='str', default=443), + certificate_authority_id=dict(type='str', required=True), + serial_no=dict(type='str'), + p12_protection_password=dict(type='str', no_log=True), + dn=dict(type='str'), + certificate_profile_id=dict(type='str'), + csr=dict(type='path'), + remaining_days=dict(type='int', default=30), + connector_name=dict(type='str', choices=['SM', 'ECS', 'PKIaaS', 'MSCA']), + tracking_info=dict(type='str'), + requester_name=dict(type='str'), + requester_email=dict(type='str'), + requester_phone=dict(type='str'), + additional_emails=dict(type='list', elements='str'), + custom_fields=dict(type='dict', default=None, options=custom_fields_spec()), + subject_alt_name=dict(type='dict', default=None, options=subject_alt_name_spec()), + validate_certs=dict(type='bool', default=True), ) def main(): - cagw_argument_spec = cagw_client_argument_spec() + cagw_argument_spec = cagw_client_argument_spec() cagw_argument_spec.update(entrust_cagw_certificate_argument_spec()) module = AnsibleModule( - argument_spec=cagw_argument_spec, - required_if=( - ['request_type', 'new', ['path', 'enrollment_format', 'certificate_profile_id', 'connector_name']], - ['request_type', 'action', ['action_type', 'serial_no', 'action_reason']], - ['request_type', 'get', ['path', 'serial_no']], - ['enrollment_format', 'X509', ['csr']], - ['enrollment_format', 'PKCS12', ['p12_protection_password', 'dn']], - ['connector_name', 'ECS', ['requester_name', 'requester_email', 'requester_phone']], - ) - ) + argument_spec=cagw_argument_spec, + required_if=( + ['request_type', 'new', ['path', 'enrollment_format', 'certificate_profile_id', 'connector_name']], + ['request_type', 'action', ['action_type', 'serial_no', 'action_reason']], + ['request_type', 'get', ['path', 'serial_no']], + ['enrollment_format', 'X509', ['csr']], + ['enrollment_format', 'PKCS12', ['p12_protection_password', 'dn']], + ['connector_name', 'ECS', ['requester_name', 'requester_email', 'requester_phone']], + ) + ) if not CRYPTOGRAPHY_FOUND or CRYPTOGRAPHY_VERSION < LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION): module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), - exception=CRYPTOGRAPHY_IMP_ERR) + exception=CRYPTOGRAPHY_IMP_ERR) # A new x509 based enrollment request must have the csr field if module.params['request_type'] == 'new': @@ -856,7 +856,7 @@ def main(): module_params_csr = module.params['csr'] if not os.path.exists(module_params_csr): module.fail_json(msg='The csr field of {0} was not a valid path. csr is required when request_type={1} with enrollment_format={2}' .format( - module_params_csr, module.params['request_type'], module_params_format)) + module_params_csr, module.params['request_type'], module_params_format)) certificate = CagwCertificate(module) certificate.request_cert(module) From 28ee821a36d331a0ef224d9c180cabf4b971bfde Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:14:44 -0500 Subject: [PATCH 24/37] Update api.py --- plugins/module_utils/entrust_cagw/api.py | 48 ++++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py index e510a14ab..197b2a459 100644 --- a/plugins/module_utils/entrust_cagw/api.py +++ b/plugins/module_utils/entrust_cagw/api.py @@ -58,10 +58,10 @@ def cagw_client_argument_spec(): return dict( - cagw_api_client_cert_path=dict(type='path', required=True), - cagw_api_client_cert_key_path=dict(type='path', required=True), - cagw_api_specification_path=dict(type='path'), - ) + cagw_api_client_cert_path=dict(type='path', required=True), + cagw_api_client_cert_key_path=dict(type='path', required=True), + cagw_api_specification_path=dict(type='path'), + ) class SessionConfigurationException(Exception): @@ -90,11 +90,11 @@ def generate_docstring(operation_spec): docs += "\tArguments:\n\n" for parameter in parameters: docs += "{0} ({1}:{2}): {3}\n".format( - parameter.get("name"), - parameter.get("type", "No Type"), - "Required" if parameter.get("required", False) else "Not Required", - parameter.get("description"), - ) + parameter.get("name"), + parameter.get("type", "No Type"), + "Required" if parameter.get("required", False) else "Not Required", + parameter.get("description"), + ) return docs @@ -244,9 +244,9 @@ def client(self): def _set_config(self, name, **kwargs): headers = { - "Content-Type": "application/json", - "Connection": "keep-alive", - } + "Content-Type": "application/json", + "Connection": "keep-alive", + } self.request = Request(headers=headers, timeout=120) configurators = [self._read_config_vars] @@ -308,19 +308,19 @@ def _read_config_vars(self, name, **kwargs): cagw_api_specification_path = kwargs.get("cagw_api_specification_path") if not cagw_api_specification_path or (not cagw_api_specification_path.startswith("http") and not os.path.isfile(cagw_api_specification_path)): raise SessionConfigurationException( - to_native( - "Parameter provided for cagw_api_specification_path of value '{0}' was not a valid file path or HTTPS address.".format( - cagw_api_specification_path - ) - ) + to_native( + "Parameter provided for cagw_api_specification_path of value '{0}' was not a valid file path or HTTPS address.".format( + cagw_api_specification_path ) + ) + ) for required_file in ["cagw_api_cert", "cagw_api_cert_key"]: file_path = kwargs.get(required_file) if not file_path or not os.path.isfile(file_path): raise SessionConfigurationException( - to_native("Parameter provided for {0} of value '{1}' was not a valid file path.".format(required_file, file_path)) - ) + to_native("Parameter provided for {0} of value '{1}' was not a valid file path.".format(required_file, file_path)) + ) config["cagw_api_cert"] = kwargs.get("cagw_api_cert") config["cagw_api_cert_key"] = kwargs.get("cagw_api_cert_key") @@ -343,8 +343,8 @@ def CAGWClient(cagw_api_cert=None, cagw_api_cert_key=None, cagw_api_specificatio cagw_api_specification_path = to_text(cagw_api_specification_path) return CAGWSession( - "entrust_cagw", - cagw_api_cert=cagw_api_cert, - cagw_api_cert_key=cagw_api_cert_key, - cagw_api_specification_path=cagw_api_specification_path, - ).client() + "entrust_cagw", + cagw_api_cert=cagw_api_cert, + cagw_api_cert_key=cagw_api_cert_key, + cagw_api_specification_path=cagw_api_specification_path, + ).client() From 419e08a4145b93067ab7fcf8c0141c15ab3f6beb Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:37:54 -0500 Subject: [PATCH 25/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 116 +++++++++++--------- 1 file changed, 62 insertions(+), 54 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 3c2179be7..79b2ec6d2 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -373,7 +373,7 @@ cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml connector_name: ECS requester_name: Sapna-CAGW-server - requester_email: sapna.jain@entrustdatacard.com + requester_email: sapna.jain@entrustdatacard.com requester_phone: 613-222-2222 - name: Request a new SSL certificate from ECS via CAGW with optional custom_field parameters. Will request a new certificate @@ -515,8 +515,9 @@ MINIMAL_CRYPTOGRAPHY_VERSION = '1.6' + def calculate_cert_days(validityPeriod): - expiry = validityPeriod.split("/") + expiry = validityPeriod.split("/") expiresAfter = expiry[1] cert_days = 0 if expiresAfter: @@ -563,21 +564,21 @@ def __init__(self, module): def write_cert_to_file(self): fh = open(self.path, "w") try: - fh.write(self.cert) + fh.write(self.cert) finally: - fh.close() + fh.close() def update_csr(self, module): body = {} csr = '' with open(module.params['csr']) as csr_file: - lines = csr_file.readlines() - # Remove first line - lines = lines[1:] - # Remove last line - lines = lines[:-1] - # Remove all linespaces - csr = "".join(line.rstrip("\n") for line in lines) + lines = csr_file.readlines() + # Remove first line + lines = lines[1:] + # Remove last line + lines = lines[:-1] + # Remove all linespaces + csr = "".join(line.rstrip("\n") for line in lines) body['csr'] = csr return body @@ -638,8 +639,8 @@ def update_cert_subject_alt_name(self, module): for k, v in module.params['subject_alt_name'].items(): if v is not None: options = {} - options['type'] = k - options['value'] = v + options['type'] = k + options['value'] = v subjectAltNames.append(options) body['subjectAltNames'] = subjectAltNames return body @@ -660,7 +661,7 @@ def set_cert_details(self, module): self.cert_days = calculate_cert_days(self.cert_details.get('validityPeriod')) if self.request_type == 'new': - self.cert = self.cert_details.get('body') + self.cert = self.cert_details.get('body') elif self.request_type == 'get': self.cert = self.cert_details.get('certificateData') @@ -680,16 +681,19 @@ def check(self, module): self.request_type = 'new' module_params_connector_name = module.params['connector_name'] - #ECS CA getCertificate api through CAGW doesn't return status of the certificate + # ECS CA getCertificate api through CAGW doesn't return status of the certificate if module_params_connector_name == 'SM': - self.cert_status = self.cert_details.get('status') - if self.cert_status == 'EXPIRED' or self.cert_status == 'expired' or self.cert_status == 'SUSPENDED' or self.cert_status == 'suspended' or self.cert_status == 'REVOKED' or self.cert_status == 'revoked' or self.cert_status == 'held': - + self.cert_status = self.cert_details.get('status') + if self.cert_status == 'EXPIRED' or self.cert_status == 'expired' or \ + self.cert_status == 'SUSPENDED' or self.cert_status == 'suspended' or \ + self.cert_status == 'REVOKED' or self.cert_status == 'revoked' or self.cert_status == 'held': return False if self.cert_days < module.params['remaining_days']: return False + return True + return False def request_cert(self, module): @@ -723,15 +727,15 @@ def request_cert(self, module): elif self.request_type == 'action': body.update(self.update_action(module)) result = self.cagw_client.ActionOnCertificate(Body=body, ca_id=module.params['certificate_authority_id'], - serial_no=module.params['serial_no'], - validate_certs=module.params['validate_certs'], - host=module.params['host'], port=module.params['port']) + serial_no=module.params['serial_no'], + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) self.cert_details = result.get('action') elif self.request_type == 'get': result = self.cagw_client.GetCertificate(ca_id=module.params['certificate_authority_id'], - serial_no=module.params['serial_no'], - validate_certs=module.params['validate_certs'], - host=module.params['host'], port=module.params['port']) + serial_no=module.params['serial_no'], + validate_certs=module.params['validate_certs'], + host=module.params['host'], port=module.params['port']) self.cert_details = result.get('certificate') self.set_cert_details(module) self.cert = begin_line + self.cert + end_line @@ -755,6 +759,7 @@ def dump(self): } return result + def custom_fields_spec(): return dict( text1=dict(type='str'), @@ -794,6 +799,7 @@ def custom_fields_spec(): dropdown5=dict(type='str'), ) + def subject_alt_name_spec(): return dict( dNSName=dict(type='str'), @@ -803,8 +809,9 @@ def subject_alt_name_spec(): rfc822Name=dict(type='str'), ) + def entrust_cagw_certificate_argument_spec(): - return dict( + return dict( force=dict(type='bool', default=False), path=dict(type='path'), request_type=dict(type='str', required=True, choices=['new', 'action', 'get']), @@ -831,37 +838,38 @@ def entrust_cagw_certificate_argument_spec(): validate_certs=dict(type='bool', default=True), ) + def main(): - cagw_argument_spec = cagw_client_argument_spec() - cagw_argument_spec.update(entrust_cagw_certificate_argument_spec()) - module = AnsibleModule( - argument_spec=cagw_argument_spec, - required_if=( - ['request_type', 'new', ['path', 'enrollment_format', 'certificate_profile_id', 'connector_name']], - ['request_type', 'action', ['action_type', 'serial_no', 'action_reason']], - ['request_type', 'get', ['path', 'serial_no']], - ['enrollment_format', 'X509', ['csr']], - ['enrollment_format', 'PKCS12', ['p12_protection_password', 'dn']], - ['connector_name', 'ECS', ['requester_name', 'requester_email', 'requester_phone']], - ) + cagw_argument_spec = cagw_client_argument_spec() + cagw_argument_spec.update(entrust_cagw_certificate_argument_spec()) + module = AnsibleModule( + argument_spec=cagw_argument_spec, + required_if=( + ['request_type', 'new', ['path', 'enrollment_format', 'certificate_profile_id', 'connector_name']], + ['request_type', 'action', ['action_type', 'serial_no', 'action_reason']], + ['request_type', 'get', ['path', 'serial_no']], + ['enrollment_format', 'X509', ['csr']], + ['enrollment_format', 'PKCS12', ['p12_protection_password', 'dn']], + ['connector_name', 'ECS', ['requester_name', 'requester_email', 'requester_phone']], ) - if not CRYPTOGRAPHY_FOUND or CRYPTOGRAPHY_VERSION < LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION): - module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), - exception=CRYPTOGRAPHY_IMP_ERR) - - # A new x509 based enrollment request must have the csr field - if module.params['request_type'] == 'new': - module_params_format = module.params['enrollment_format'] - if module_params_format == "X509": - module_params_csr = module.params['csr'] - if not os.path.exists(module_params_csr): - module.fail_json(msg='The csr field of {0} was not a valid path. csr is required when request_type={1} with enrollment_format={2}' .format( - module_params_csr, module.params['request_type'], module_params_format)) - - certificate = CagwCertificate(module) - certificate.request_cert(module) - result = certificate.dump() - module.exit_json(**result) + ) + if not CRYPTOGRAPHY_FOUND or CRYPTOGRAPHY_VERSION < LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION): + module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), + exception=CRYPTOGRAPHY_IMP_ERR) + + # A new x509 based enrollment request must have the csr field + if module.params['request_type'] == 'new': + module_params_format = module.params['enrollment_format'] + if module_params_format == "X509": + module_params_csr = module.params['csr'] + if not os.path.exists(module_params_csr): + module.fail_json(msg='The csr field of {0} was not a valid path.'.format(module_params_csr)) + + certificate = CagwCertificate(module) + certificate.request_cert(module) + result = certificate.dump() + module.exit_json(**result) + if __name__ == '__main__': main() From 58b0e049eafa96a7ba03f3381fd0661da6ef6e3e Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:38:54 -0500 Subject: [PATCH 26/37] Update api.py --- plugins/module_utils/entrust_cagw/api.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py index 197b2a459..7af19d0fb 100644 --- a/plugins/module_utils/entrust_cagw/api.py +++ b/plugins/module_utils/entrust_cagw/api.py @@ -78,6 +78,7 @@ def __init__(self, error): self.errors = [to_native(err.get("message")) for err in error.get("errors", {})] self.message = to_native(" ".join(self.errors)) + def generate_docstring(operation_spec): """Generate a docstring for an operation defined in operation_spec (swagger)""" # Description of the operation @@ -121,14 +122,19 @@ def __init__(self, session, uri, method, parameters=None): self.parameters = {} else: self.parameters = parameters - self.url = "{scheme}://{host}:{port}{base_path}{uri}".format(scheme="https", host=("example.com"), port=("443"), base_path=session._spec.get("basePath"), uri=uri) + self.url = "{scheme}://{host}:{port}{base_path}{uri}".format(scheme="https", host=("example.com"), + port=("443"), + base_path=session._spec.get("basePath"), uri=uri) def restmethod(self, *args, **kwargs): """Do the hard work of making the request here""" validate_certs_val = kwargs.get("validate_certs", True) host = kwargs.get("host", None) port = kwargs.get("port", None) - url = "{scheme}://{host}:{port}{base_path}{uri}".format(scheme="https", host=host, port=port, base_path=self.session._spec.get("basePath"), uri=self.uri) + url = "{scheme}://{host}:{port}{base_path}{uri}".format(scheme="https", + host=host, port=port, + base_path=self.session._spec.get("basePath"), + uri=self.uri) # gather named path parameters and do substitution on the URL if self.parameters: path_parameters = {} @@ -257,7 +263,6 @@ def _set_config(self, name, **kwargs): if self._config is None: raise SessionConfigurationException(to_native("No Configuration Found.")) - # set up client certificate if passed (support all-in one or cert + key) cagw_api_cert = self.get_config("cagw_api_cert") cagw_api_cert_key = self.get_config("cagw_api_cert_key") @@ -335,10 +340,6 @@ def CAGWClient(cagw_api_cert=None, cagw_api_cert_key=None, cagw_api_specificatio if not YAML_FOUND: raise SessionConfigurationException(missing_required_lib("PyYAML"), exception=YAML_IMP_ERR) - #if cagw_api_specification_path is None: - # cagw_api_specification_path = "https://cloud.entrust.net/EntrustCloud/documentation/cms-api-2.1.0.yaml" - - # Not functionally necessary with current uses of this module_util, but better to be explicit for future use cases cagw_api_cert_key = to_text(cagw_api_cert_key) cagw_api_specification_path = to_text(cagw_api_specification_path) From 7d714fd85a3c24c597f7b4aed52e86bc5a30b5e7 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 16:23:58 -0500 Subject: [PATCH 27/37] Update api.py --- plugins/module_utils/entrust_cagw/api.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py index 7af19d0fb..466d8426b 100644 --- a/plugins/module_utils/entrust_cagw/api.py +++ b/plugins/module_utils/entrust_cagw/api.py @@ -122,7 +122,8 @@ def __init__(self, session, uri, method, parameters=None): self.parameters = {} else: self.parameters = parameters - self.url = "{scheme}://{host}:{port}{base_path}{uri}".format(scheme="https", host=("example.com"), + self.url = "{scheme}://{host}:{port}{base_path}{uri}".format(scheme=session._spec.get("schemes")[0], + host=("example.com"), port=("443"), base_path=session._spec.get("basePath"), uri=uri) @@ -131,10 +132,11 @@ def restmethod(self, *args, **kwargs): validate_certs_val = kwargs.get("validate_certs", True) host = kwargs.get("host", None) port = kwargs.get("port", None) - url = "{scheme}://{host}:{port}{base_path}{uri}".format(scheme="https", + url = "{scheme}://{host}:{port}{base_path}{uri}".format(scheme=self.session._spec.get("schemes")[0], host=host, port=port, base_path=self.session._spec.get("basePath"), uri=self.uri) + print(url); # gather named path parameters and do substitution on the URL if self.parameters: path_parameters = {} From 9600210cb49762948006c7f859b35245d07c3656 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 16:24:11 -0500 Subject: [PATCH 28/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 79b2ec6d2..5fd3b9101 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -60,7 +60,7 @@ port: description: - port for Entrust CAGW. - type: str + type: int default: 443 certificate_authority_id: @@ -819,7 +819,7 @@ def entrust_cagw_certificate_argument_spec(): action_reason=dict(type='str'), enrollment_format=dict(type='str', choices=['X509', 'PKCS12']), host=dict(type='str', required=True), - port=dict(type='str', default=443), + port=dict(type='int', default=443), certificate_authority_id=dict(type='str', required=True), serial_no=dict(type='str'), p12_protection_password=dict(type='str', no_log=True), From 6ac60b39c028fe25b5515a1245e399b9895eb039 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 16:30:26 -0500 Subject: [PATCH 29/37] Update api.py --- plugins/module_utils/entrust_cagw/api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py index 466d8426b..848843790 100644 --- a/plugins/module_utils/entrust_cagw/api.py +++ b/plugins/module_utils/entrust_cagw/api.py @@ -136,7 +136,6 @@ def restmethod(self, *args, **kwargs): host=host, port=port, base_path=self.session._spec.get("basePath"), uri=self.uri) - print(url); # gather named path parameters and do substitution on the URL if self.parameters: path_parameters = {} From 6b4aee96273e7acc4d767690829eb93ff0885251 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Wed, 15 Nov 2023 17:06:10 -0500 Subject: [PATCH 30/37] Update aliases --- tests/integration/targets/entrust_cagw_certificate/aliases | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/targets/entrust_cagw_certificate/aliases b/tests/integration/targets/entrust_cagw_certificate/aliases index 96e05fcaf..07650ef78 100644 --- a/tests/integration/targets/entrust_cagw_certificate/aliases +++ b/tests/integration/targets/entrust_cagw_certificate/aliases @@ -2,10 +2,10 @@ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later -unsupported - +# Not enabled due to lack of access to test environments. May be enabled using custom integration_config.yml # Example integation_config.yml # --- # cagw_api_client_cert_path: /var/integration-testing/publicCert.pem # cagw_api_client_cert_key_path: /var/integration-testing/privateKey.pem # entrust_cagw_api_specification_path: /var/integration-testing/cagw-api.yml +unsupported From abe167fc316893b9d7cf5878d66638be2f230946 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Thu, 16 Nov 2023 07:20:58 -0500 Subject: [PATCH 31/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 42 ++++++++++++--------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 5fd3b9101..8131e54b2 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -24,19 +24,22 @@ options: force: description: - - If force is used, a certificate is requested regardless of whether I(path) points to an existing valid certificate. + - If O(force=True) then a certificate is requested regardless of whether I(path) points to an existing valid certificate. type: bool default: False path: description: - The destination path for the generated certificate as a PEM encoded cert. - - If there is already an Entrust certificate at this location, it will be replaced always. + - If there is already a certificate at the I(path) and O(force=True) then it will be replaced always. + but if I(force) is not specified then we get the certificate validity for existing certificate from Entrust CAGW. + If C(cert_days < remaining_days) then only a new certificate will be obtained. - If O(enrollment_format=PKCS12) then it will have Base64 encoded PKCS12 body. type: path csr: description: - Base-64 encoded Certificate Signing Request (CSR). csr is accepted without PEM formatting around the Base-64 string. - - If no csr is provided when O(request_type=new) and O(enrollment_format=X509), the certificate will not be generated and module will be failed. + - If no csr is provided when O(request_type=new) and O(enrollment_format=X509), + the certificate will not be generated and module will be failed. type: path cagw_api_client_cert_path: @@ -59,7 +62,7 @@ port: description: - - port for Entrust CAGW. + - Port for Entrust CAGW. type: int default: 443 @@ -76,7 +79,7 @@ request_type: description: - - request type that is new (stands for enrollment), get (stands for get certificate), + - Request type that is new (stands for enrollment), get (stands for get certificate), action (stands for action to be taken on the certificate). type: str choices: [ 'new', 'action', 'get' ] @@ -90,47 +93,49 @@ validate_certs: description: - - if set to false then SSL validation with Server is skipped. + - If set to false then SSL validation with Server is skipped. This should be set to false only for testing purposes. type: bool default: True action_type: description: - - what action has to be taken on the certificate that is RevokeAction, HoldAction, UnholdAction. + - What action has to be taken on the certificate that is RevokeAction, HoldAction, UnholdAction. type: str choices: [ 'RevokeAction', 'HoldAction', 'UnholdAction'] action_reason: description: - - reason has to be given for the action. + - Reason has to be given for the action. type: str serial_no: description: - - serial number of the already issued certificate. + - Serial number of the already issued certificate. type: str p12_protection_password: description: - - p12 password for server side generation of the private key and CSR. + - PKCS12 password for server side generation of the private key and CSR. type: str dn: description: - - distinguished name used either for generation for CSR or given in the CAGW enrollment api when O(enrollment_format=PKCS12). + - Distinguished name given for the enrollment. type: str cagw_api_specification_path: description: - - path for CAGW api specification doc. + - Path for CAGW api specification doc. type: path remaining_days: description: - The number of days the certificate must have left being valid. - If C(cert_days < remaining_days) then a new certificate will be obtained using I(request_type). - - The I(force) option may be used to ensure that a new certificate is always obtained. + If a certificate is already present at the I(path) and I(force) is not specified then + we get the certificate validity for existing certificate from Entrust CAGW. + If C(cert_days < remaining_days) then a new certificate will be obtained. + - The O(force=True) option may be used to ensure that a new certificate is always obtained. type: int default: 30 @@ -139,6 +144,7 @@ - This parameter defines which CA type connected at the backend. Supported list of CAs include Entrust Certificate Solution(ECS), Entrust Security Manager(SM), Entrust PKIHUB CA(PKIaaS), Microsoft CA(MSCA). + - If connector_name is not provided when O(request_type=new), module will be failed. type: str choices: [ 'SM', 'ECS', 'PKIaaS', 'MSCA' ] @@ -372,8 +378,8 @@ enrollment_format: X509 cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml connector_name: ECS - requester_name: Sapna-CAGW-server - requester_email: sapna.jain@entrustdatacard.com + requester_name: Sapna-Jain + requester_email: sapna.jain@entrust.com requester_phone: 613-222-2222 - name: Request a new SSL certificate from ECS via CAGW with optional custom_field parameters. Will request a new certificate @@ -388,8 +394,8 @@ enrollment_format: X509 cagw_api_specification_path: /etc/ssl/entrust/cagw-api.yaml connector_name: ECS - requester_name: Sapna-CAGW-server - requester_email: sapna.jain@entrustdatacard.com + requester_name: Sapna-Jain + requester_email: sapna.jain@entrust.com requester_phone: 613-222-2222 custom_fields: text1: Admin From 274c9f3b8df1757c9653a7231b65d89cd244e1ad Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Thu, 16 Nov 2023 07:34:20 -0500 Subject: [PATCH 32/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 8131e54b2..d26f1eff0 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -30,7 +30,7 @@ path: description: - The destination path for the generated certificate as a PEM encoded cert. - - If there is already a certificate at the I(path) and O(force=True) then it will be replaced always. + - If there is already a certificate at this location and O(force=True) then it will be replaced always. but if I(force) is not specified then we get the certificate validity for existing certificate from Entrust CAGW. If C(cert_days < remaining_days) then only a new certificate will be obtained. - If O(enrollment_format=PKCS12) then it will have Base64 encoded PKCS12 body. From 8c149741777a0be2eb0d04a53fb4f81a73e704cb Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:16:07 -0500 Subject: [PATCH 33/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index d26f1eff0..6a0bba11a 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -492,18 +492,12 @@ import datetime import os -import re -import time import traceback from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from ansible.module_utils._text import to_native, to_bytes - -from ansible_collections.community.crypto.plugins.module_utils.io import ( - write_file, -) +from ansible.module_utils._text import to_native from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( load_certificate, From b5bca148a830b11e19b301075b87cacd2fa1cc62 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:16:39 -0500 Subject: [PATCH 34/37] Update api.py --- plugins/module_utils/entrust_cagw/api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py index 848843790..83915fd6f 100644 --- a/plugins/module_utils/entrust_cagw/api.py +++ b/plugins/module_utils/entrust_cagw/api.py @@ -35,7 +35,6 @@ import json import os import re -import time import traceback from ansible.module_utils._text import to_text, to_native From b3f6345b6175eb20ca726b7a71b5bfab1fbf51ee Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:46:38 -0500 Subject: [PATCH 35/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 6a0bba11a..604b55ccd 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -24,13 +24,13 @@ options: force: description: - - If O(force=True) then a certificate is requested regardless of whether I(path) points to an existing valid certificate. + - If O(force=true) then a certificate is requested regardless of whether I(path) points to an existing valid certificate. type: bool default: False path: description: - The destination path for the generated certificate as a PEM encoded cert. - - If there is already a certificate at this location and O(force=True) then it will be replaced always. + - If there is already a certificate at this location and O(force=true) then it will be replaced always. but if I(force) is not specified then we get the certificate validity for existing certificate from Entrust CAGW. If C(cert_days < remaining_days) then only a new certificate will be obtained. - If O(enrollment_format=PKCS12) then it will have Base64 encoded PKCS12 body. @@ -135,7 +135,7 @@ If a certificate is already present at the I(path) and I(force) is not specified then we get the certificate validity for existing certificate from Entrust CAGW. If C(cert_days < remaining_days) then a new certificate will be obtained. - - The O(force=True) option may be used to ensure that a new certificate is always obtained. + - The O(force=true) option may be used to ensure that a new certificate is always obtained. type: int default: 30 From d23b0f5fe1719b320a448d240f154db343fcb0e0 Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:29:40 -0500 Subject: [PATCH 36/37] Update entrust_cagw_certificate.py --- plugins/modules/entrust_cagw_certificate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/modules/entrust_cagw_certificate.py b/plugins/modules/entrust_cagw_certificate.py index 604b55ccd..91c027d7a 100644 --- a/plugins/modules/entrust_cagw_certificate.py +++ b/plugins/modules/entrust_cagw_certificate.py @@ -128,6 +128,7 @@ description: - Path for CAGW api specification doc. type: path + required: true remaining_days: description: From 8f005d7563b6c3738b1efeaec193fb1a6e3225bc Mon Sep 17 00:00:00 2001 From: sapnajainEntrust <149614151+sapnajainEntrust@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:30:19 -0500 Subject: [PATCH 37/37] Update api.py --- plugins/module_utils/entrust_cagw/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/module_utils/entrust_cagw/api.py b/plugins/module_utils/entrust_cagw/api.py index 83915fd6f..037273f68 100644 --- a/plugins/module_utils/entrust_cagw/api.py +++ b/plugins/module_utils/entrust_cagw/api.py @@ -58,8 +58,8 @@ def cagw_client_argument_spec(): return dict( cagw_api_client_cert_path=dict(type='path', required=True), - cagw_api_client_cert_key_path=dict(type='path', required=True), - cagw_api_specification_path=dict(type='path'), + cagw_api_client_cert_key_path=dict(type='path', required=True, no_log=True), + cagw_api_specification_path=dict(type='path', required=True), )