From bae68010a8ee07e89cfe160ada60fddf5297e8c0 Mon Sep 17 00:00:00 2001 From: Jonathan Ifegunni Date: Tue, 26 Mar 2024 15:44:51 -0700 Subject: [PATCH] Add support for Iam Authorizer --- .../proxy/model/HttpApiV2AuthorizerMap.java | 32 ++++++- .../proxy/model/HttpApiV2IamAuthorizer.java | 68 +++++++++++++++ .../model/HttpApiV2ProxyRequestTest.java | 85 +++++++++++++++++-- 3 files changed, 176 insertions(+), 9 deletions(-) create mode 100644 aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2IamAuthorizer.java diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2AuthorizerMap.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2AuthorizerMap.java index 4fff028c4..2cf6d77a6 100644 --- a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2AuthorizerMap.java +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2AuthorizerMap.java @@ -34,16 +34,21 @@ public class HttpApiV2AuthorizerMap extends HashMap { private static final String JWT_KEY = "jwt"; private static final String LAMBDA_KEY = "lambda"; + private static final String IAM_KEY = "iam"; private static final long serialVersionUID = 42L; public HttpApiV2JwtAuthorizer getJwtAuthorizer() { - return (HttpApiV2JwtAuthorizer)get(JWT_KEY); + return (HttpApiV2JwtAuthorizer) get(JWT_KEY); } public Map getLambdaAuthorizerContext() { return (Map) get(LAMBDA_KEY); } + public HttpApiV2IamAuthorizer getIamAuthorizer() { + return (HttpApiV2IamAuthorizer) get(IAM_KEY); + } + public boolean isJwt() { return containsKey(JWT_KEY); } @@ -52,10 +57,18 @@ public boolean isLambda() { return containsKey(LAMBDA_KEY); } + public boolean isIam() { + return containsKey(IAM_KEY); + } + public void putJwtAuthorizer(HttpApiV2JwtAuthorizer jwt) { put(JWT_KEY, jwt); } + public void putIamAuthorizer(HttpApiV2IamAuthorizer iam) { + put(IAM_KEY, iam); + } + public static class HttpApiV2AuthorizerDeserializer extends StdDeserializer { private static final long serialVersionUID = 42L; @@ -64,11 +77,13 @@ public HttpApiV2AuthorizerDeserializer() { } @Override - public HttpApiV2AuthorizerMap deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + public HttpApiV2AuthorizerMap deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException, JsonProcessingException { HttpApiV2AuthorizerMap map = new HttpApiV2AuthorizerMap(); JsonNode node = jsonParser.getCodec().readTree(jsonParser); if (node.has(JWT_KEY)) { - HttpApiV2JwtAuthorizer authorizer = LambdaContainerHandler.getObjectMapper().treeToValue(node.get(JWT_KEY), HttpApiV2JwtAuthorizer.class); + HttpApiV2JwtAuthorizer authorizer = LambdaContainerHandler.getObjectMapper() + .treeToValue(node.get(JWT_KEY), HttpApiV2JwtAuthorizer.class); map.putJwtAuthorizer(authorizer); } if (node.has(LAMBDA_KEY)) { @@ -76,6 +91,11 @@ public HttpApiV2AuthorizerMap deserialize(JsonParser jsonParser, Deserialization TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, Object.class)); map.put(LAMBDA_KEY, context); } + if (node.has(IAM_KEY)) { + HttpApiV2IamAuthorizer iam_authorizer = LambdaContainerHandler.getObjectMapper() + .treeToValue(node.get(IAM_KEY), HttpApiV2IamAuthorizer.class); + map.putIamAuthorizer(iam_authorizer); + } // we ignore other, unknown values return map; } @@ -89,7 +109,8 @@ public HttpApiV2AuthorizerSerializer() { } @Override - public void serialize(HttpApiV2AuthorizerMap httpApiV2AuthorizerMap, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + public void serialize(HttpApiV2AuthorizerMap httpApiV2AuthorizerMap, JsonGenerator jsonGenerator, + SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeStartObject(); if (httpApiV2AuthorizerMap.isJwt()) { jsonGenerator.writeObjectField(JWT_KEY, httpApiV2AuthorizerMap.getJwtAuthorizer()); @@ -97,6 +118,9 @@ public void serialize(HttpApiV2AuthorizerMap httpApiV2AuthorizerMap, JsonGenerat if (httpApiV2AuthorizerMap.isLambda()) { jsonGenerator.writeObjectField(LAMBDA_KEY, httpApiV2AuthorizerMap.getLambdaAuthorizerContext()); } + if (httpApiV2AuthorizerMap.isIam()) { + jsonGenerator.writeObjectField(IAM_KEY, httpApiV2AuthorizerMap.get(IAM_KEY)); + } jsonGenerator.writeEndObject(); } } diff --git a/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2IamAuthorizer.java b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2IamAuthorizer.java new file mode 100644 index 000000000..d2a0952ec --- /dev/null +++ b/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2IamAuthorizer.java @@ -0,0 +1,68 @@ +package com.amazonaws.serverless.proxy.model; + +public class HttpApiV2IamAuthorizer { + public String accessKey; + public String accountId; + public String callerId; + public String cognitoIdentity; + public String principalOrgId; + public String userArn; + public String userId; + + public String getAccessKey() { + return accessKey; + } + + public String getAccountId() { + return accountId; + } + + public String getCallerId() { + return callerId; + } + + public String getCognitoIdentity() { + return cognitoIdentity; + } + + public String getPrincipalOrgId() { + return principalOrgId; + } + + public String getUserArn() { + return userArn; + } + + public String getUserId() { + return userId; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + public void setCallerId(String callerId) { + this.callerId = callerId; + } + + public void setCognitoIdentity(String cognitoIdentity) { + this.cognitoIdentity = cognitoIdentity; + } + + public void setPrincipalOrgId(String principalOrgId) { + this.principalOrgId = principalOrgId; + } + + public void setUserArn(String userArn) { + this.userArn = userArn; + } + + public void setUserId(String userId) { + this.userId = userId; + } + +} \ No newline at end of file diff --git a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestTest.java b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestTest.java index 3aa7cfdfc..20ff4dff2 100644 --- a/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestTest.java +++ b/aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/model/HttpApiV2ProxyRequestTest.java @@ -129,11 +129,55 @@ public class HttpApiV2ProxyRequestTest { " \"isBase64Encoded\": false,\n" + " \"stageVariables\": {\"stageVariable1\": \"value1\", \"stageVariable2\": \"value2\"}\n" + " }\n"; + private static final String IAM_AUTHORIZER = "{\n" + + " \"version\": \"2.0\",\n" + + " \"routeKey\": \"$default\",\n" + + " \"rawPath\": \"/my/path\",\n" + + " \"rawQueryString\": \"parameter1=value1¶meter1=value2¶meter2=value\",\n" + + " \"cookies\": [ \"cookie1\", \"cookie2\" ],\n" + + " \"headers\": {\n" + + " \"Header1\": \"value1\",\n" + + " \"Header2\": \"value2\"\n" + + " },\n" + + " \"queryStringParameters\": { \"parameter1\": \"value1,value2\", \"parameter2\": \"value\" },\n" + + " \"requestContext\": {\n" + + " \"accountId\": \"123456789012\",\n" + + " \"apiId\": \"api-id\",\n" + + " \"authorizer\": { \"iam\": {\n" + + " \"accessKey\": \"AKIAIOSFODNN7EXAMPLE\",\n" + + " \"accountId\": \"123456789012\",\n" + + " \"callerId\": \"AIDACKCEVSQ6C2EXAMPLE\",\n" + + " \"cognitoIdentity\": null,\n" + + " \"principalOrgId\": \"AIDACKCEVSQORGEXAMPLE\",\n" + + " \"userArn\": \"arn:aws:iam::111122223333:user/example-user\",\n" + + " \"userId\": \"AIDACOSFODNN7EXAMPLE2\"\n" + + " }" + + " },\n" + + " \"domainName\": \"id.execute-api.us-east-1.amazonaws.com\",\n" + + " \"domainPrefix\": \"id\",\n" + + " \"http\": {\n" + + " \"method\": \"POST\",\n" + + " \"path\": \"/my/path\",\n" + + " \"protocol\": \"HTTP/1.1\",\n" + + " \"sourceIp\": \"IP\",\n" + + " \"userAgent\": \"agent\"\n" + + " },\n" + + " \"requestId\": \"id\",\n" + + " \"routeKey\": \"$default\",\n" + + " \"stage\": \"$default\",\n" + + " \"time\": \"12/Mar/2020:19:03:58 +0000\",\n" + + " \"timeEpoch\": 1583348638390\n" + + " },\n" + + " \"body\": \"Hello from Lambda\",\n" + + " \"isBase64Encoded\": false,\n" + + " \"stageVariables\": {\"stageVariable1\": \"value1\", \"stageVariable2\": \"value2\"}\n" + + " }\n"; @Test void deserialize_fromJsonString_authorizerPopulatedCorrectly() { try { - HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(BASE_PROXY_REQUEST, HttpApiV2ProxyRequest.class); + HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(BASE_PROXY_REQUEST, + HttpApiV2ProxyRequest.class); assertTrue(req.getRequestContext().getAuthorizer().getJwtAuthorizer().getClaims().containsKey("claim1")); assertEquals(2, req.getRequestContext().getAuthorizer().getJwtAuthorizer().getScopes().size()); assertEquals(RequestSource.API_GATEWAY, req.getRequestSource()); @@ -146,10 +190,12 @@ void deserialize_fromJsonString_authorizerPopulatedCorrectly() { @Test void deserialize_fromJsonString_authorizerEmptyMap() { try { - HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(NO_AUTH_PROXY, HttpApiV2ProxyRequest.class); + HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(NO_AUTH_PROXY, + HttpApiV2ProxyRequest.class); assertNotNull(req.getRequestContext().getAuthorizer()); assertFalse(req.getRequestContext().getAuthorizer().isJwt()); assertFalse(req.getRequestContext().getAuthorizer().isLambda()); + assertFalse(req.getRequestContext().getAuthorizer().isIam()); } catch (JsonProcessingException e) { e.printStackTrace(); fail("Exception while parsing request" + e.getMessage()); @@ -159,7 +205,8 @@ void deserialize_fromJsonString_authorizerEmptyMap() { @Test void deserialize_fromJsonString_lambdaAuthorizer() { try { - HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(LAMBDA_AUTHORIZER, HttpApiV2ProxyRequest.class); + HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(LAMBDA_AUTHORIZER, + HttpApiV2ProxyRequest.class); assertNotNull(req.getRequestContext().getAuthorizer()); assertFalse(req.getRequestContext().getAuthorizer().isJwt()); assertTrue(req.getRequestContext().getAuthorizer().isLambda()); @@ -171,10 +218,38 @@ void deserialize_fromJsonString_lambdaAuthorizer() { } } + @Test + void deserialize_fromJsonString_iamAuthorizer() { + try { + HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(IAM_AUTHORIZER, + HttpApiV2ProxyRequest.class); + assertNotNull(req.getRequestContext().getAuthorizer()); + assertFalse(req.getRequestContext().getAuthorizer().isJwt()); + assertFalse(req.getRequestContext().getAuthorizer().isLambda()); + assertTrue(req.getRequestContext().getAuthorizer().isIam()); + assertEquals("AKIAIOSFODNN7EXAMPLE", + req.getRequestContext().getAuthorizer().getIamAuthorizer().getAccessKey()); + assertEquals("123456789012", req.getRequestContext().getAuthorizer().getIamAuthorizer().getAccountId()); + assertEquals("AIDACKCEVSQ6C2EXAMPLE", + req.getRequestContext().getAuthorizer().getIamAuthorizer().getCallerId()); + assertNull(req.getRequestContext().getAuthorizer().getIamAuthorizer().getCognitoIdentity()); + assertEquals("AIDACKCEVSQORGEXAMPLE", + req.getRequestContext().getAuthorizer().getIamAuthorizer().getPrincipalOrgId()); + assertEquals("arn:aws:iam::111122223333:user/example-user", + req.getRequestContext().getAuthorizer().getIamAuthorizer().getUserArn()); + assertEquals("AIDACOSFODNN7EXAMPLE2", + req.getRequestContext().getAuthorizer().getIamAuthorizer().getUserId()); + } catch (JsonProcessingException e) { + e.printStackTrace(); + fail("Exception while parsing request" + e.getMessage()); + } + } + @Test void deserialize_fromJsonString_isBase64EncodedPopulates() { try { - HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(BASE_PROXY_REQUEST, HttpApiV2ProxyRequest.class); + HttpApiV2ProxyRequest req = LambdaContainerHandler.getObjectMapper().readValue(BASE_PROXY_REQUEST, + HttpApiV2ProxyRequest.class); assertFalse(req.isBase64Encoded()); req = LambdaContainerHandler.getObjectMapper().readValue(NO_AUTH_PROXY, HttpApiV2ProxyRequest.class); assertTrue(req.isBase64Encoded()); @@ -207,4 +282,4 @@ void serialize_toJsonString_authorizerPopulatesCorrectly() { fail("Exception while serializing request" + e.getMessage()); } } -} +} \ No newline at end of file