diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayClientCertificate.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayClientCertificate.java new file mode 100644 index 000000000..a6ba3c0f2 --- /dev/null +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayClientCertificate.java @@ -0,0 +1,92 @@ +/* + * Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://aws.amazon.com/apache2.0/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.amazonaws.serverless.proxy.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Client certificate metadata included in API Gateway proxy request events when mutual TLS is enabled. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class ApiGatewayClientCertificate { + private String clientCertPem; + private String subjectDN; + private String issuerDN; + private String serialNumber; + private Validity validity; + + public String getClientCertPem() { + return clientCertPem; + } + + public void setClientCertPem(String clientCertPem) { + this.clientCertPem = clientCertPem; + } + + public String getSubjectDN() { + return subjectDN; + } + + public void setSubjectDN(String subjectDN) { + this.subjectDN = subjectDN; + } + + public String getIssuerDN() { + return issuerDN; + } + + public void setIssuerDN(String issuerDN) { + this.issuerDN = issuerDN; + } + + public String getSerialNumber() { + return serialNumber; + } + + public void setSerialNumber(String serialNumber) { + this.serialNumber = serialNumber; + } + + public Validity getValidity() { + return validity; + } + + public void setValidity(Validity validity) { + this.validity = validity; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Validity { + private String notBefore; + private String notAfter; + + public String getNotBefore() { + return notBefore; + } + + public void setNotBefore(String notBefore) { + this.notBefore = notBefore; + } + + public String getNotAfter() { + return notAfter; + } + + public void setNotAfter(String notAfter) { + this.notAfter = notAfter; + } + } +} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayRequestIdentity.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayRequestIdentity.java index 89b1ea2a4..2ef071571 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayRequestIdentity.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/ApiGatewayRequestIdentity.java @@ -45,6 +45,7 @@ public class ApiGatewayRequestIdentity { private String sourceIp; private String accountId; private String accessKey; + private ApiGatewayClientCertificate clientCert; //------------------------------------------------------------- @@ -179,4 +180,14 @@ public String getAccessKey() { public void setAccessKey(String accessKey) { this.accessKey = accessKey; } + + + public ApiGatewayClientCertificate getClientCert() { + return clientCert; + } + + + public void setClientCert(ApiGatewayClientCertificate clientCert) { + this.clientCert = clientCert; + } } diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2Authentication.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2Authentication.java new file mode 100644 index 000000000..6b3e0de08 --- /dev/null +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2Authentication.java @@ -0,0 +1,34 @@ +/* + * Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://aws.amazon.com/apache2.0/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.amazonaws.serverless.proxy.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * Authentication metadata included in an API Gateway HTTP API v2 request context. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class HttpApiV2Authentication { + private ApiGatewayClientCertificate clientCert; + + public ApiGatewayClientCertificate getClientCert() { + return clientCert; + } + + public void setClientCert(ApiGatewayClientCertificate clientCert) { + this.clientCert = clientCert; + } +} diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestContext.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestContext.java index e5a5b9d2d..808001c8d 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestContext.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestContext.java @@ -29,6 +29,7 @@ public class HttpApiV2ProxyRequestContext { private HttpApiV2HttpContext http; private HttpApiV2AuthorizerMap authorizer; + private HttpApiV2Authentication authentication; public String getAccountId() { return accountId; @@ -118,6 +119,14 @@ public void setAuthorizer(HttpApiV2AuthorizerMap authorizer) { this.authorizer = authorizer; } + public HttpApiV2Authentication getAuthentication() { + return authentication; + } + + public void setAuthentication(HttpApiV2Authentication authentication) { + this.authentication = authentication; + } + public AlbContext getElb() { return this.elb; } diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/ApiGatewayClientCertificateTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/ApiGatewayClientCertificateTest.java new file mode 100644 index 000000000..e26272b30 --- /dev/null +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/ApiGatewayClientCertificateTest.java @@ -0,0 +1,51 @@ +package com.amazonaws.serverless.proxy.model; + +import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler; +import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class ApiGatewayClientCertificateTest { + private static final String CERTIFICATE_JSON = "\"clientCert\": {" + + "\"clientCertPem\": \"-----BEGIN CERTIFICATE-----\\ncertificate\\n-----END CERTIFICATE-----\"," + + "\"subjectDN\": \"CN=client\"," + + "\"issuerDN\": \"CN=issuer\"," + + "\"serialNumber\": \"01:02:03\"," + + "\"validity\": {\"notBefore\": \"May 28 12:30:02 2019 GMT\"," + + "\"notAfter\": \"Aug 5 09:36:04 2021 GMT\"}" + + "}"; + + @Test + void deserialize_restApiIdentityClientCertificate() throws Exception { + String requestJson = "{\"requestContext\": {\"identity\": {" + CERTIFICATE_JSON + "}}}"; + + AwsProxyRequest request = new AwsProxyRequestBuilder().fromJsonString(requestJson).build(); + ApiGatewayClientCertificate certificate = request.getRequestContext().getIdentity().getClientCert(); + + assertCertificate(certificate); + } + + @Test + void deserialize_httpApiV2AuthenticationClientCertificate() throws Exception { + String requestJson = "{\"requestContext\": {\"authentication\": {" + CERTIFICATE_JSON + "}}}"; + + HttpApiV2ProxyRequest request = LambdaContainerHandler.getObjectMapper() + .readValue(requestJson, HttpApiV2ProxyRequest.class); + ApiGatewayClientCertificate certificate = request.getRequestContext().getAuthentication().getClientCert(); + + assertCertificate(certificate); + } + + private void assertCertificate(ApiGatewayClientCertificate certificate) { + assertNotNull(certificate); + assertEquals("-----BEGIN CERTIFICATE-----\ncertificate\n-----END CERTIFICATE-----", certificate.getClientCertPem()); + assertEquals("CN=client", certificate.getSubjectDN()); + assertEquals("CN=issuer", certificate.getIssuerDN()); + assertEquals("01:02:03", certificate.getSerialNumber()); + assertNotNull(certificate.getValidity()); + assertEquals("May 28 12:30:02 2019 GMT", certificate.getValidity().getNotBefore()); + assertEquals("Aug 5 09:36:04 2021 GMT", certificate.getValidity().getNotAfter()); + } +}