Skip to content

Commit 9eb1727

Browse files
committed
Added sample filter in servlet examples. Discovered and fixed a filters bug with spring boot. This closes #67.
1 parent 4f79a99 commit 9eb1727

File tree

9 files changed

+263
-5
lines changed

9 files changed

+263
-5
lines changed

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
import javax.ws.rs.core.SecurityContext;
1212

1313
import java.time.LocalDateTime;
14+
import java.time.ZoneId;
1415
import java.time.ZoneOffset;
16+
import java.time.ZonedDateTime;
1517
import java.time.format.DateTimeFormatter;
1618
import java.time.format.DateTimeFormatterBuilder;
1719
import java.util.Locale;
@@ -55,8 +57,6 @@ public ApacheCombinedServletLogFormatter() {
5557
.optionalEnd()
5658
.appendLiteral("]")
5759
.toFormatter();
58-
//DateTimeFormatter.ofPattern("dd/MM/yyyy:hh:mm:ss Z");
59-
//DateTimeFormatter.BASIC_ISO_DATE
6060
}
6161

6262
@Override
@@ -91,9 +91,16 @@ public String format(ContainerRequestType servletRequest, ContainerResponseType
9191

9292
// %t
9393
if (gatewayContext != null) {
94-
logLineBuilder.append(dateFormat.format(LocalDateTime.ofEpochSecond(gatewayContext.getRequestTimeEpoch() / 1000, 0, ZoneOffset.UTC)));
94+
logLineBuilder.append(
95+
dateFormat.format(
96+
ZonedDateTime.of(
97+
LocalDateTime.ofEpochSecond(gatewayContext.getRequestTimeEpoch() / 1000, 0, ZoneOffset.UTC),
98+
ZoneId.systemDefault()
99+
)
100+
)
101+
);
95102
} else {
96-
logLineBuilder.append(dateFormat.format(LocalDateTime.now()));
103+
logLineBuilder.append(dateFormat.format(ZonedDateTime.now()));
97104
}
98105
logLineBuilder.append(" ");
99106

aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringBootLambdaContainerHandler.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,11 @@ protected void handleRequest(AwsProxyHttpServletRequest containerRequest, AwsHtt
134134
if (springProfiles != null && springProfiles.length > 0) {
135135
ConfigurableEnvironment springEnv = new StandardEnvironment();
136136
springEnv.setActiveProfiles(springProfiles);
137-
137+
}
138+
139+
// call the onStartup event if set to give developers a chance to set filters in the context
140+
if (startupHandler != null) {
141+
startupHandler.onStartup(getServletContext());
138142
}
139143

140144
initialized = true;

samples/spark/pet-store/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,15 @@
7777
<configuration>
7878
<artifactSet>
7979
<excludes>
80+
<!-- We exclude lots of Jetty stuff since we won't be running
81+
the HTTP server. Our primary goal is to reduce the size
82+
of the deployment package -->
8083
<exclude>org.eclipse.jetty.websocket:*</exclude>
84+
<exclude>org.eclipse.jetty:jetty-http</exclude>
85+
<exclude>org.eclipse.jetty:jetty-client</exclude>
86+
<exclude>org.eclipse.jetty:jetty-webapp</exclude>
87+
<exclude>org.eclipse.jetty:jetty-xml</exclude>
88+
<exclude>org.eclipse.jetty:jetty-io</exclude>
8189
</excludes>
8290
</artifactSet>
8391
</configuration>

samples/spark/pet-store/src/main/java/com/amazonaws/serverless/sample/spark/StreamLambdaHandler.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@
66
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
77
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
88
import com.amazonaws.serverless.proxy.spark.SparkLambdaContainerHandler;
9+
import com.amazonaws.serverless.sample.spark.filter.CognitoIdentityFilter;
910
import com.amazonaws.services.lambda.runtime.Context;
1011
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
1112

1213
import spark.Spark;
1314

15+
import javax.servlet.DispatcherType;
16+
import javax.servlet.FilterRegistration;
17+
1418
import java.io.IOException;
1519
import java.io.InputStream;
1620
import java.io.OutputStream;
21+
import java.util.EnumSet;
1722

1823

1924
public class StreamLambdaHandler implements RequestStreamHandler {
@@ -23,6 +28,12 @@ public class StreamLambdaHandler implements RequestStreamHandler {
2328
handler = SparkLambdaContainerHandler.getAwsProxyHandler();
2429
SparkResources.defineResources();
2530
Spark.awaitInitialization();
31+
32+
// we use the onStartup method of the handler to register our custom filter
33+
handler.onStartup(servletContext -> {
34+
FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class);
35+
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
36+
});
2637
} catch (ContainerInitializationException e) {
2738
// if we fail here. We re-throw the exception to force another cold start
2839
e.printStackTrace();
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.amazonaws.serverless.sample.spark.filter;
2+
3+
4+
import com.amazonaws.serverless.proxy.RequestReader;
5+
import com.amazonaws.serverless.proxy.model.ApiGatewayRequestContext;
6+
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
import javax.servlet.Filter;
11+
import javax.servlet.FilterChain;
12+
import javax.servlet.FilterConfig;
13+
import javax.servlet.ServletException;
14+
import javax.servlet.ServletRequest;
15+
import javax.servlet.ServletResponse;
16+
17+
import java.io.IOException;
18+
19+
20+
/**
21+
* Simple Filter implementation that looks for a Cognito identity id in the API Gateway request context
22+
* and stores the value in a request attribute. The filter is registered with aws-serverless-java-container
23+
* in the onStartup method from the {@link com.amazonaws.serverless.sample.spring.StreamLambdaHandler} class.
24+
*/
25+
public class CognitoIdentityFilter implements Filter {
26+
public static final String COGNITO_IDENTITY_ATTRIBUTE = "com.amazonaws.serverless.cognitoId";
27+
28+
private static Logger log = LoggerFactory.getLogger(CognitoIdentityFilter.class);
29+
30+
@Override
31+
public void init(FilterConfig filterConfig)
32+
throws ServletException {
33+
// nothing to do in init
34+
}
35+
36+
37+
@Override
38+
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
39+
throws IOException, ServletException {
40+
Object apiGwContext = servletRequest.getAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY);
41+
if (apiGwContext == null) {
42+
log.warn("API Gateway context is null");
43+
filterChain.doFilter(servletRequest, servletResponse);
44+
}
45+
if (!ApiGatewayRequestContext.class.isAssignableFrom(apiGwContext.getClass())) {
46+
log.warn("API Gateway context object is not of valid type");
47+
filterChain.doFilter(servletRequest, servletResponse);
48+
}
49+
50+
ApiGatewayRequestContext ctx = (ApiGatewayRequestContext)apiGwContext;
51+
if (ctx.getIdentity() == null) {
52+
log.warn("Identity context is null");
53+
filterChain.doFilter(servletRequest, servletResponse);
54+
}
55+
String cognitoIdentityId = ctx.getIdentity().getCognitoIdentityId();
56+
if (cognitoIdentityId == null || "".equals(cognitoIdentityId.trim())) {
57+
log.warn("Cognito identity id in request is null");
58+
}
59+
servletRequest.setAttribute(COGNITO_IDENTITY_ATTRIBUTE, cognitoIdentityId);
60+
filterChain.doFilter(servletRequest, servletResponse);
61+
}
62+
63+
64+
@Override
65+
public void destroy() {
66+
// nothing to do in destroy
67+
}
68+
}

samples/spring/pet-store/src/main/java/com/amazonaws/serverless/sample/spring/StreamLambdaHandler.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,31 @@
66
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
77
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
88
import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
9+
import com.amazonaws.serverless.sample.spring.filter.CognitoIdentityFilter;
910
import com.amazonaws.services.lambda.runtime.Context;
1011
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
1112

13+
import javax.servlet.DispatcherType;
14+
import javax.servlet.FilterRegistration;
15+
1216
import java.io.IOException;
1317
import java.io.InputStream;
1418
import java.io.OutputStream;
19+
import java.util.EnumSet;
1520

1621

1722
public class StreamLambdaHandler implements RequestStreamHandler {
1823
private static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
1924
static {
2025
try {
2126
handler = SpringLambdaContainerHandler.getAwsProxyHandler(PetStoreSpringAppConfig.class);
27+
28+
// we use the onStartup method of the handler to register our custom filter
29+
handler.onStartup(servletContext -> {
30+
FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class);
31+
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
32+
});
33+
2234
} catch (ContainerInitializationException e) {
2335
// if we fail here. We re-throw the exception to force another cold start
2436
e.printStackTrace();
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.amazonaws.serverless.sample.spring.filter;
2+
3+
4+
import com.amazonaws.serverless.proxy.RequestReader;
5+
import com.amazonaws.serverless.proxy.model.ApiGatewayRequestContext;
6+
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
import javax.servlet.Filter;
11+
import javax.servlet.FilterChain;
12+
import javax.servlet.FilterConfig;
13+
import javax.servlet.ServletException;
14+
import javax.servlet.ServletRequest;
15+
import javax.servlet.ServletResponse;
16+
import javax.servlet.http.HttpServletRequest;
17+
18+
import java.io.IOException;
19+
20+
21+
/**
22+
* Simple Filter implementation that looks for a Cognito identity id in the API Gateway request context
23+
* and stores the value in a request attribute. The filter is registered with aws-serverless-java-container
24+
* in the onStartup method from the {@link com.amazonaws.serverless.sample.spring.StreamLambdaHandler} class.
25+
*/
26+
public class CognitoIdentityFilter implements Filter {
27+
public static final String COGNITO_IDENTITY_ATTRIBUTE = "com.amazonaws.serverless.cognitoId";
28+
29+
private static Logger log = LoggerFactory.getLogger(CognitoIdentityFilter.class);
30+
31+
@Override
32+
public void init(FilterConfig filterConfig)
33+
throws ServletException {
34+
// nothing to do in init
35+
}
36+
37+
38+
@Override
39+
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
40+
throws IOException, ServletException {
41+
Object apiGwContext = servletRequest.getAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY);
42+
if (apiGwContext == null) {
43+
log.warn("API Gateway context is null");
44+
filterChain.doFilter(servletRequest, servletResponse);
45+
}
46+
if (!ApiGatewayRequestContext.class.isAssignableFrom(apiGwContext.getClass())) {
47+
log.warn("API Gateway context object is not of valid type");
48+
filterChain.doFilter(servletRequest, servletResponse);
49+
}
50+
51+
ApiGatewayRequestContext ctx = (ApiGatewayRequestContext)apiGwContext;
52+
if (ctx.getIdentity() == null) {
53+
log.warn("Identity context is null");
54+
filterChain.doFilter(servletRequest, servletResponse);
55+
}
56+
String cognitoIdentityId = ctx.getIdentity().getCognitoIdentityId();
57+
if (cognitoIdentityId == null || "".equals(cognitoIdentityId.trim())) {
58+
log.warn("Cognito identity id in request is null");
59+
}
60+
servletRequest.setAttribute(COGNITO_IDENTITY_ATTRIBUTE, cognitoIdentityId);
61+
filterChain.doFilter(servletRequest, servletResponse);
62+
}
63+
64+
65+
@Override
66+
public void destroy() {
67+
// nothing to do in destroy
68+
}
69+
}

samples/springboot/pet-store/src/main/java/com/amazonaws/serverless/sample/springboot/StreamLambdaHandler.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,30 @@
66
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
77
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
88
import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
9+
import com.amazonaws.serverless.sample.springboot.filter.CognitoIdentityFilter;
910
import com.amazonaws.services.lambda.runtime.Context;
1011
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
1112

13+
import javax.servlet.DispatcherType;
14+
import javax.servlet.FilterRegistration;
15+
1216
import java.io.IOException;
1317
import java.io.InputStream;
1418
import java.io.OutputStream;
19+
import java.util.EnumSet;
1520

1621

1722
public class StreamLambdaHandler implements RequestStreamHandler {
1823
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
1924
static {
2025
try {
2126
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class);
27+
28+
// we use the onStartup method of the handler to register our custom filter
29+
handler.onStartup(servletContext -> {
30+
FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class);
31+
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
32+
});
2233
} catch (ContainerInitializationException e) {
2334
// if we fail here. We re-throw the exception to force another cold start
2435
e.printStackTrace();
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.amazonaws.serverless.sample.springboot.filter;
2+
3+
4+
import com.amazonaws.serverless.proxy.RequestReader;
5+
import com.amazonaws.serverless.proxy.model.ApiGatewayRequestContext;
6+
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
import javax.servlet.Filter;
11+
import javax.servlet.FilterChain;
12+
import javax.servlet.FilterConfig;
13+
import javax.servlet.ServletException;
14+
import javax.servlet.ServletRequest;
15+
import javax.servlet.ServletResponse;
16+
17+
import java.io.IOException;
18+
19+
20+
/**
21+
* Simple Filter implementation that looks for a Cognito identity id in the API Gateway request context
22+
* and stores the value in a request attribute. The filter is registered with aws-serverless-java-container
23+
* in the onStartup method from the {@link com.amazonaws.serverless.sample.spring.StreamLambdaHandler} class.
24+
*/
25+
public class CognitoIdentityFilter implements Filter {
26+
public static final String COGNITO_IDENTITY_ATTRIBUTE = "com.amazonaws.serverless.cognitoId";
27+
28+
private static Logger log = LoggerFactory.getLogger(CognitoIdentityFilter.class);
29+
30+
@Override
31+
public void init(FilterConfig filterConfig)
32+
throws ServletException {
33+
// nothing to do in init
34+
}
35+
36+
37+
@Override
38+
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
39+
throws IOException, ServletException {
40+
Object apiGwContext = servletRequest.getAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY);
41+
if (apiGwContext == null) {
42+
log.warn("API Gateway context is null");
43+
filterChain.doFilter(servletRequest, servletResponse);
44+
}
45+
if (!ApiGatewayRequestContext.class.isAssignableFrom(apiGwContext.getClass())) {
46+
log.warn("API Gateway context object is not of valid type");
47+
filterChain.doFilter(servletRequest, servletResponse);
48+
}
49+
50+
ApiGatewayRequestContext ctx = (ApiGatewayRequestContext)apiGwContext;
51+
if (ctx.getIdentity() == null) {
52+
log.warn("Identity context is null");
53+
filterChain.doFilter(servletRequest, servletResponse);
54+
}
55+
String cognitoIdentityId = ctx.getIdentity().getCognitoIdentityId();
56+
if (cognitoIdentityId == null || "".equals(cognitoIdentityId.trim())) {
57+
log.warn("Cognito identity id in request is null");
58+
}
59+
servletRequest.setAttribute(COGNITO_IDENTITY_ATTRIBUTE, cognitoIdentityId);
60+
filterChain.doFilter(servletRequest, servletResponse);
61+
}
62+
63+
64+
@Override
65+
public void destroy() {
66+
// nothing to do in destroy
67+
}
68+
}

0 commit comments

Comments
 (0)