From 3ae4c23c236841bf44d0f6374dbab35e5891909a Mon Sep 17 00:00:00 2001 From: Sahil Shah <53784576+sahilshah6196@users.noreply.github.com> Date: Thu, 1 Jul 2021 11:25:40 -0400 Subject: [PATCH] Transform certificates in listener in expected XML (#4049) --- moto/elbv2/models.py | 57 +++++++++++++++------------------- tests/test_elbv2/test_elbv2.py | 16 +++++----- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/moto/elbv2/models.py b/moto/elbv2/models.py index 178dc72b4..3033680ec 100644 --- a/moto/elbv2/models.py +++ b/moto/elbv2/models.py @@ -265,6 +265,7 @@ class FakeListener(CloudFormationModel): certificates = properties.get("Certificates") default_actions = elbv2_backend.convert_and_validate_properties(properties) + certificates = elbv2_backend.convert_and_validate_certificates(certificates) listener = elbv2_backend.create_listener( load_balancer_arn, protocol, port, ssl_policy, certificates, default_actions ) @@ -283,6 +284,7 @@ class FakeListener(CloudFormationModel): certificates = properties.get("Certificates") default_actions = elbv2_backend.convert_and_validate_properties(properties) + certificates = elbv2_backend.convert_and_validate_certificates(certificates) listener = elbv2_backend.modify_listener( original_resource.arn, port, @@ -833,6 +835,14 @@ Member must satisfy regular expression pattern: {}".format( self.target_groups[target_group.arn] = target_group return target_group + def convert_and_validate_certificates(self, certificates): + + # transform default certificate to conform with the rest of the code and XML templates + for cert in certificates or []: + cert["certificate_arn"] = cert["CertificateArn"] + + return certificates + def convert_and_validate_properties(self, properties): # transform default actions to confirm with the rest of the code and XML templates @@ -1308,41 +1318,24 @@ Member must satisfy regular expression pattern: {}".format( # HTTPS checks if protocol == "HTTPS": - # HTTPS - - # Might already be HTTPS so may not provide certs - if certificates is None and listener.protocol != "HTTPS": - raise RESTError( - "InvalidConfigurationRequest", - "Certificates must be provided for HTTPS", - ) - # Check certificates exist - if certificates is not None: - default_cert = None - all_certs = set() # for SNI - for cert in certificates: - if cert["is_default"] == "true": - default_cert = cert["certificate_arn"] - try: - self.acm_backend.get_certificate(cert["certificate_arn"]) - except Exception: - raise RESTError( - "CertificateNotFound", - "Certificate {0} not found".format( - cert["certificate_arn"] - ), - ) - - all_certs.add(cert["certificate_arn"]) - - if default_cert is None: + if certificates: + default_cert = certificates[0] + default_cert_arn = default_cert["certificate_arn"] + try: + self.acm_backend.get_certificate(default_cert_arn) + except Exception: raise RESTError( - "InvalidConfigurationRequest", "No default certificate" + "CertificateNotFound", + "Certificate {0} not found".format(default_cert_arn), ) - - listener.certificate = default_cert - listener.certificates = list(all_certs) + listener.certificate = default_cert_arn + listener.certificates = certificates + else: + raise RESTError( + "CertificateWereNotPassed", + "You must provide a list containing exactly one certificate if the listener protocol is HTTPS.", + ) listener.protocol = protocol diff --git a/tests/test_elbv2/test_elbv2.py b/tests/test_elbv2/test_elbv2.py index 2c3e53c19..1f1d8a74c 100644 --- a/tests/test_elbv2/test_elbv2.py +++ b/tests/test_elbv2/test_elbv2.py @@ -1767,10 +1767,7 @@ def test_modify_listener_http_to_https(): Port=443, Protocol="HTTPS", SslPolicy="ELBSecurityPolicy-TLS-1-2-2017-01", - Certificates=[ - {"CertificateArn": google_arn, "IsDefault": False}, - {"CertificateArn": yahoo_arn, "IsDefault": True}, - ], + Certificates=[{"CertificateArn": yahoo_arn,},], DefaultActions=[{"Type": "forward", "TargetGroupArn": target_group_arn}], ) response["Listeners"][0]["Port"].should.equal(443) @@ -1778,7 +1775,7 @@ def test_modify_listener_http_to_https(): response["Listeners"][0]["SslPolicy"].should.equal( "ELBSecurityPolicy-TLS-1-2-2017-01" ) - len(response["Listeners"][0]["Certificates"]).should.equal(2) + len(response["Listeners"][0]["Certificates"]).should.equal(1) # Check default cert, can't do this in server mode if os.environ.get("TEST_SERVER_MODE", "false").lower() == "false": @@ -1790,15 +1787,20 @@ def test_modify_listener_http_to_https(): listener.certificate.should.equal(yahoo_arn) # No default cert - with pytest.raises(ClientError): + with pytest.raises(ClientError) as ex: client.modify_listener( ListenerArn=listener_arn, Port=443, Protocol="HTTPS", SslPolicy="ELBSecurityPolicy-TLS-1-2-2017-01", - Certificates=[{"CertificateArn": google_arn, "IsDefault": False}], + Certificates=[], DefaultActions=[{"Type": "forward", "TargetGroupArn": target_group_arn}], ) + err = ex.value.response["Error"] + err["Code"].should.equal("CertificateWereNotPassed") + err["Message"].should.equal( + "You must provide a list containing exactly one certificate if the listener protocol is HTTPS." + ) # Bad cert with pytest.raises(ClientError):