diff --git a/changelogs/fragments/803-fix-authorization-failure-with-mixed-case-sans.yml b/changelogs/fragments/803-fix-authorization-failure-with-mixed-case-sans.yml new file mode 100644 index 00000000..7e4e40e2 --- /dev/null +++ b/changelogs/fragments/803-fix-authorization-failure-with-mixed-case-sans.yml @@ -0,0 +1,2 @@ +bugfixes: + - acme_certificate - fix authorization failure when CSR contains SANs with mixed case (https://github.com/ansible-collections/community.crypto/pull/803). \ No newline at end of file diff --git a/plugins/module_utils/acme/challenges.py b/plugins/module_utils/acme/challenges.py index 116ca420..e37075a6 100644 --- a/plugins/module_utils/acme/challenges.py +++ b/plugins/module_utils/acme/challenges.py @@ -47,6 +47,13 @@ def combine_identifier(identifier_type, identifier): return '{type}:{identifier}'.format(type=identifier_type, identifier=identifier) +def normalize_combined_identifier(identifier): + identifier_type, identifier = split_identifier(identifier) + # Normalize DNS names and IPs + identifier = identifier.lower() + return combine_identifier(identifier_type, identifier) + + def split_identifier(identifier): parts = identifier.split(':', 1) if len(parts) != 2: diff --git a/plugins/module_utils/acme/orders.py b/plugins/module_utils/acme/orders.py index 98c28445..0724615c 100644 --- a/plugins/module_utils/acme/orders.py +++ b/plugins/module_utils/acme/orders.py @@ -21,6 +21,7 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.errors impor from ansible_collections.community.crypto.plugins.module_utils.acme.challenges import ( Authorization, + normalize_combined_identifier, ) @@ -93,7 +94,7 @@ class Order(object): def load_authorizations(self, client): for auth_uri in self.authorization_uris: authz = Authorization.from_url(client, auth_uri) - self.authorizations[authz.combined_identifier] = authz + self.authorizations[normalize_combined_identifier(authz.combined_identifier)] = authz def wait_for_finalization(self, client): while True: diff --git a/plugins/modules/acme_certificate.py b/plugins/modules/acme_certificate.py index 8729996c..228090ae 100644 --- a/plugins/modules/acme_certificate.py +++ b/plugins/modules/acme_certificate.py @@ -580,6 +580,7 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.account impo ) from ansible_collections.community.crypto.plugins.module_utils.acme.challenges import ( + normalize_combined_identifier, combine_identifier, split_identifier, wait_for_validation, @@ -721,7 +722,7 @@ class ACMECertificateClient(object): raise ModuleFailException('ACME v1 only supports DNS identifiers!') for identifier_type, identifier in self.identifiers: authz = Authorization.create(self.client, identifier_type, identifier) - self.authorizations[authz.combined_identifier] = authz + self.authorizations[normalize_combined_identifier(authz.combined_identifier)] = authz else: replaces_cert_id = None if ( @@ -755,8 +756,8 @@ class ACMECertificateClient(object): if authz.status == 'valid': continue # We drop the type from the key to preserve backwards compatibility - data[identifier] = authz.get_challenge_data(self.client) - if first_step and self.challenge is not None and self.challenge not in data[identifier]: + data[authz.identifier] = authz.get_challenge_data(self.client) + if first_step and self.challenge is not None and self.challenge not in data[authz.identifier]: raise ModuleFailException("Found no challenge of type '{0}' for identifier {1}!".format( self.challenge, type_identifier)) # Get DNS challenge data @@ -835,7 +836,7 @@ class ACMECertificateClient(object): with an error. ''' for identifier_type, identifier in self.identifiers: - authz = self.authorizations.get(combine_identifier(identifier_type, identifier)) + authz = self.authorizations.get(normalize_combined_identifier(combine_identifier(identifier_type, identifier))) if authz is None: raise ModuleFailException('Found no authorization information for "{identifier}"!'.format( identifier=combine_identifier(identifier_type, identifier))) @@ -965,7 +966,7 @@ def main(): auths = dict() for k, v in client.authorizations.items(): # Remove "type:" from key - auths[split_identifier(k)[1]] = v.to_json() + auths[v.identifier] = v.to_json() module.exit_json( changed=client.changed, authorizations=auths,