Skip to content

Commit abc09a8

Browse files
committed
migrated to APIGatewayProxyRequestEvent and ALB
1 parent 6086216 commit abc09a8

File tree

85 files changed

+2533
-1718
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2533
-1718
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.amazonaws.serverless.proxy;
2+
3+
import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
4+
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
5+
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
6+
import com.amazonaws.serverless.proxy.model.ErrorModel;
7+
import com.fasterxml.jackson.core.JsonProcessingException;
8+
import jakarta.ws.rs.InternalServerErrorException;
9+
import jakarta.ws.rs.core.HttpHeaders;
10+
import jakarta.ws.rs.core.MediaType;
11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
13+
14+
import java.io.IOException;
15+
import java.io.OutputStream;
16+
import java.util.ArrayList;
17+
import java.util.HashMap;
18+
import java.util.List;
19+
import java.util.Map;
20+
21+
public class AwsAlbExceptionHandler implements ExceptionHandler<AwsProxyResponse>{
22+
23+
private Logger log = LoggerFactory.getLogger(AwsAlbExceptionHandler.class);
24+
25+
//-------------------------------------------------------------
26+
// Constants
27+
//-------------------------------------------------------------
28+
29+
static final String INTERNAL_SERVER_ERROR = "Internal Server Error";
30+
static final String GATEWAY_TIMEOUT_ERROR = "Gateway timeout";
31+
32+
33+
//-------------------------------------------------------------
34+
// Variables - Private - Static
35+
//-------------------------------------------------------------
36+
37+
private static final Map<String, List<String>> headers = new HashMap<>();
38+
39+
//-------------------------------------------------------------
40+
// Constructors
41+
//-------------------------------------------------------------
42+
43+
static {
44+
List<String> values = new ArrayList<>();
45+
values.add(MediaType.APPLICATION_JSON);
46+
headers.put(HttpHeaders.CONTENT_TYPE, values);
47+
}
48+
@Override
49+
public AwsProxyResponse handle(Throwable ex) {
50+
log.error("Called exception handler for:", ex);
51+
52+
// adding a print stack trace in case we have no appender or we are running inside SAM local, where need the
53+
// output to go to the stderr.
54+
ex.printStackTrace();
55+
AwsProxyResponse responseEvent = new AwsProxyResponse();
56+
57+
responseEvent.setMultiValueHeaders(headers);
58+
if (ex instanceof InvalidRequestEventException || ex instanceof InternalServerErrorException) {
59+
//return new APIGatewayProxyResponseEvent(500, headers, getErrorJson(INTERNAL_SERVER_ERROR));
60+
responseEvent.setBody(getErrorJson(INTERNAL_SERVER_ERROR));
61+
responseEvent.setStatusCode(500);
62+
return responseEvent;
63+
} else {
64+
responseEvent.setBody(getErrorJson(GATEWAY_TIMEOUT_ERROR));
65+
responseEvent.setStatusCode(502);
66+
return responseEvent;
67+
}
68+
}
69+
70+
@Override
71+
public void handle(Throwable ex, OutputStream stream) throws IOException {
72+
AwsProxyResponse response = handle(ex);
73+
74+
LambdaContainerHandler.getObjectMapper().writeValue(stream, response);
75+
}
76+
77+
//-------------------------------------------------------------
78+
// Methods - Protected
79+
//-------------------------------------------------------------
80+
81+
String getErrorJson(String message) {
82+
83+
try {
84+
return LambdaContainerHandler.getObjectMapper().writeValueAsString(new ErrorModel(message));
85+
} catch (JsonProcessingException e) {
86+
log.error("Could not produce error JSON", e);
87+
return "{ \"message\": \"" + message + "\" }";
88+
}
89+
}
90+
}

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxySecurityContextWriter.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313
package com.amazonaws.serverless.proxy;
1414

1515
import com.amazonaws.serverless.proxy.internal.jaxrs.AwsProxySecurityContext;
16-
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
1716
import com.amazonaws.services.lambda.runtime.Context;
1817

18+
import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
1919
import jakarta.ws.rs.core.SecurityContext;
2020

2121
/**
2222
* Default implementation of <code>SecurityContextWriter</code>. Creates a SecurityContext object based on an API Gateway
2323
* event and the Lambda context. This returns the default <code>AwsProxySecurityContext</code> instance.
2424
*/
25-
public class AwsProxySecurityContextWriter implements SecurityContextWriter<AwsProxyRequest> {
25+
public class AwsProxySecurityContextWriter implements SecurityContextWriter<APIGatewayProxyRequestEvent> {
2626

2727
//-------------------------------------------------------------
2828
// Variables - Private - Static
@@ -36,7 +36,7 @@ public class AwsProxySecurityContextWriter implements SecurityContextWriter<AwsP
3636
//-------------------------------------------------------------
3737

3838
@Override
39-
public SecurityContext writeSecurityContext(AwsProxyRequest event, Context lambdaContext) {
39+
public SecurityContext writeSecurityContext(APIGatewayProxyRequestEvent event, Context lambdaContext) {
4040
currentContext = new AwsProxySecurityContext(lambdaContext, event);
4141

4242
return currentContext;

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/RequestReader.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ public abstract class RequestReader<RequestType, ContainerRequestType> {
5050
*/
5151
public static final String ALB_CONTEXT_PROPERTY = "com.amazonaws.alb.request.context";
5252

53+
/**
54+
* The key to store the entire Application Load Balancer event
55+
*/
56+
public static final String ALB_EVENT_PROPERTY = "com.amazonaws.alb.request";
57+
5358
/**
5459
* The key to store the entire API Gateway event
5560
*/

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/SecurityContextWriter.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
*/
1313
package com.amazonaws.serverless.proxy;
1414

15-
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
1615
import com.amazonaws.services.lambda.runtime.Context;
1716

1817
import jakarta.ws.rs.core.SecurityContext;

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsProxySecurityContext.java

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
*/
1313
package com.amazonaws.serverless.proxy.internal.jaxrs;
1414

15-
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
16-
import com.amazonaws.serverless.proxy.model.CognitoAuthorizerClaims;
1715
import com.amazonaws.services.lambda.runtime.Context;
1816

17+
import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
1918
import jakarta.ws.rs.core.SecurityContext;
2019

2120
import java.security.Principal;
21+
import java.util.Map;
2222

2323
/**
2424
* default implementation of the <code>SecurityContext</code> object. This class supports 3 API Gateway's authorization methods:
@@ -35,36 +35,38 @@ public class AwsProxySecurityContext
3535
// Constants - Package
3636
//-------------------------------------------------------------
3737

38-
static final String AUTH_SCHEME_CUSTOM = "CUSTOM_AUTHORIZER";
38+
public static final String AUTH_SCHEME_CUSTOM = "CUSTOM_AUTHORIZER";
3939
static final String AUTH_SCHEME_COGNITO_POOL = "COGNITO_USER_POOL";
4040
static final String AUTH_SCHEME_AWS_IAM = "AWS_IAM";
41-
42-
static final String ALB_ACESS_TOKEN_HEADER = "x-amzn-oidc-accesstoken";
43-
static final String ALB_IDENTITY_HEADER = "x-amzn-oidc-identity";
41+
static final String PRINCIPAL_ID_KEY = "principal_id";
42+
static final String CLAIMS_KEY = "claims";
43+
static final String SUB_KEY = "sub";
44+
public static final String ALB_ACESS_TOKEN_HEADER = "x-amzn-oidc-accesstoken";
45+
public static final String ALB_IDENTITY_HEADER = "x-amzn-oidc-identity";
4446

4547

4648
//-------------------------------------------------------------
4749
// Variables - Private
4850
//-------------------------------------------------------------
4951

5052
private Context lambdaContext;
51-
private AwsProxyRequest event;
53+
private APIGatewayProxyRequestEvent event;
5254

5355

5456
public Context getLambdaContext() {
5557
return lambdaContext;
5658
}
5759

5860

59-
public AwsProxyRequest getEvent() {
61+
public APIGatewayProxyRequestEvent getEvent() {
6062
return event;
6163
}
6264

6365
//-------------------------------------------------------------
6466
// Constructors
6567
//-------------------------------------------------------------
6668

67-
public AwsProxySecurityContext(final Context lambdaContext, final AwsProxyRequest event) {
69+
public AwsProxySecurityContext(final Context lambdaContext, final APIGatewayProxyRequestEvent event) {
6870
this.lambdaContext = lambdaContext;
6971
this.event = event;
7072
}
@@ -83,12 +85,7 @@ public Principal getUserPrincipal() {
8385
if (getAuthenticationScheme().equals(AUTH_SCHEME_CUSTOM) || getAuthenticationScheme().equals(AUTH_SCHEME_AWS_IAM)) {
8486
return () -> {
8587
if (getAuthenticationScheme().equals(AUTH_SCHEME_CUSTOM)) {
86-
switch (event.getRequestSource()) {
87-
case API_GATEWAY:
88-
return event.getRequestContext().getAuthorizer().getPrincipalId();
89-
case ALB:
90-
return event.getMultiValueHeaders().getFirst(ALB_IDENTITY_HEADER);
91-
}
88+
return event.getRequestContext().getAuthorizer().get(PRINCIPAL_ID_KEY).toString();
9289
} else if (getAuthenticationScheme().equals(AUTH_SCHEME_AWS_IAM)) {
9390
// if we received credentials from Cognito Federated Identities then we return the identity id
9491
if (event.getRequestContext().getIdentity().getCognitoIdentityId() != null) {
@@ -104,7 +101,7 @@ public Principal getUserPrincipal() {
104101
}
105102

106103
if (getAuthenticationScheme().equals(AUTH_SCHEME_COGNITO_POOL)) {
107-
return new CognitoUserPoolPrincipal(event.getRequestContext().getAuthorizer().getClaims());
104+
return new CognitoUserPoolPrincipal((Map<String, String>) event.getRequestContext().getAuthorizer().get(CLAIMS_KEY));
108105
}
109106

110107
throw new RuntimeException("Cannot recognize authorization scheme in event");
@@ -125,24 +122,15 @@ public boolean isSecure() {
125122

126123
@Override
127124
public String getAuthenticationScheme() {
128-
switch (event.getRequestSource()) {
129-
case API_GATEWAY:
130-
if (event.getRequestContext().getAuthorizer() != null && event.getRequestContext().getAuthorizer().getClaims() != null
131-
&& event.getRequestContext().getAuthorizer().getClaims().getSubject() != null) {
132-
return AUTH_SCHEME_COGNITO_POOL;
133-
} else if (event.getRequestContext().getAuthorizer() != null) {
134-
return AUTH_SCHEME_CUSTOM;
135-
} else if (event.getRequestContext().getIdentity().getAccessKey() != null) {
136-
return AUTH_SCHEME_AWS_IAM;
137-
} else {
138-
return null;
139-
}
140-
case ALB:
141-
if (event.getMultiValueHeaders().containsKey(ALB_ACESS_TOKEN_HEADER)) {
142-
return AUTH_SCHEME_CUSTOM;
143-
}
125+
if (event.getRequestContext().getAuthorizer() != null && ((Map<String, String>) event.getRequestContext().getAuthorizer().get(CLAIMS_KEY)).get(SUB_KEY) != null) {
126+
return AUTH_SCHEME_COGNITO_POOL;
127+
} else if (event.getRequestContext().getAuthorizer() != null) {
128+
return AUTH_SCHEME_CUSTOM;
129+
} else if (event.getRequestContext().getIdentity() != null && event.getRequestContext().getIdentity().getAccessKey() != null) {
130+
return AUTH_SCHEME_AWS_IAM;
131+
} else {
132+
return null;
144133
}
145-
return null;
146134
}
147135

148136

@@ -152,18 +140,18 @@ public String getAuthenticationScheme() {
152140
*/
153141
public static class CognitoUserPoolPrincipal implements Principal {
154142

155-
private CognitoAuthorizerClaims claims;
143+
private Map<String, String> claims;
156144

157-
CognitoUserPoolPrincipal(CognitoAuthorizerClaims c) {
145+
CognitoUserPoolPrincipal(Map<String, String> c) {
158146
claims = c;
159147
}
160148

161149
@Override
162150
public String getName() {
163-
return claims.getSubject();
151+
return claims.get(SUB_KEY);
164152
}
165153

166-
public CognitoAuthorizerClaims getClaims() {
154+
public Map<String, String> getClaims() {
167155
return claims;
168156
}
169157
}

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/ApacheCombinedServletLogFormatter.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
package com.amazonaws.serverless.proxy.internal.servlet;
1414

1515
import com.amazonaws.serverless.proxy.LogFormatter;
16-
import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
1716

17+
import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayProxyRequestEvent;
1818
import com.amazonaws.services.lambda.runtime.events.apigateway.APIGatewayV2HTTPEvent;
1919
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2020

@@ -78,7 +78,7 @@ public ApacheCombinedServletLogFormatter() {
7878
public String format(ContainerRequestType servletRequest, ContainerResponseType servletResponse, SecurityContext ctx) {
7979
//LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined
8080
StringBuilder logLineBuilder = new StringBuilder();
81-
AwsProxyRequestContext gatewayContext = (AwsProxyRequestContext)servletRequest.getAttribute(API_GATEWAY_CONTEXT_PROPERTY);
81+
APIGatewayProxyRequestEvent.ProxyRequestContext gatewayContext = (APIGatewayProxyRequestEvent.ProxyRequestContext)servletRequest.getAttribute(API_GATEWAY_CONTEXT_PROPERTY);
8282
APIGatewayV2HTTPEvent.RequestContext httpApiContext = (APIGatewayV2HTTPEvent.RequestContext)servletRequest.getAttribute(HTTP_API_CONTEXT_PROPERTY);
8383

8484
// %h
@@ -107,7 +107,7 @@ public String format(ContainerRequestType servletRequest, ContainerResponseType
107107

108108
// %t
109109
long timeEpoch = ZonedDateTime.now(clock).toEpochSecond();
110-
if (gatewayContext != null && gatewayContext.getRequestTimeEpoch() > 0) {
110+
if (gatewayContext != null && gatewayContext.getRequestTimeEpoch() != null && gatewayContext.getRequestTimeEpoch() > 0) {
111111
timeEpoch = gatewayContext.getRequestTimeEpoch() / 1000;
112112
} else if (httpApiContext != null && httpApiContext.getTimeEpoch() > 0) {
113113
timeEpoch = httpApiContext.getTimeEpoch() / 1000;

0 commit comments

Comments
 (0)