Coder Social home page Coder Social logo

aws / serverless-java-container Goto Github PK

View Code? Open in Web Editor NEW
1.4K 74.0 546.0 2.89 MB

A Java wrapper to run Spring, Spring Boot, Jersey, and other apps inside AWS Lambda.

Home Page: https://aws.amazon.com/serverless/

License: Apache License 2.0

Java 99.71% HTML 0.02% Shell 0.28%
jersey api-gateway aws-lambda spring serverless aws api api-server rest-api sparkjava

serverless-java-container's Introduction

Serverless Java container Build Status Maven Central Help

The aws-serverless-java-container makes it easy to run Java applications written with frameworks such as Spring, Spring Boot, Apache Struts, Jersey, or Spark in AWS Lambda.

Serverless Java Container natively supports API Gateway's proxy integration models for requests and responses, you can create and inject custom models for methods that use custom mappings.

Currently the following versions are maintained:

Version Branch Java Enterprise support Spring versions JAX-RS/ Jersey version Struts support Spark support
1.x 1.x Java EE (javax.*) 5.x (Boot 2.x) 2.x
2.x main Jakarta EE (jakarta.*) 6.x (Boot 3.x) 3.x

Follow the quick start guides in our wiki to integrate Serverless Java Container with your project:

Below is the most basic AWS Lambda handler example that launches a Spring application. You can also take a look at the samples in this repository, our main wiki page includes a step-by-step guide on how to deploy the various sample applications using Maven and SAM.

public class StreamLambdaHandler implements RequestStreamHandler {
    private static final SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;

    static {
        try {
            handler = SpringLambdaContainerHandler.getAwsProxyHandler(PetStoreSpringAppConfig.class);
        } catch (ContainerInitializationException e) {
            // if we fail here. We re-throw the exception to force another cold start
            e.printStackTrace();
            throw new RuntimeException("Could not initialize Spring framework", e);
        }
    }

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
            throws IOException {
        handler.proxyStream(inputStream, outputStream, context);
    }
}

Public Examples

Blogs

Workshops

Videos

Java samples with different frameworks

serverless-java-container's People

Contributors

2012160085 avatar artur- avatar billrobertson42 avatar deki avatar dependabot[bot] avatar driverpt avatar eranation avatar jancona avatar joeyvmason avatar jogep avatar jonife avatar jschwartz73 avatar jt0 avatar kerkhofsd avatar larmog avatar maschnetwork avatar mattcorey avatar mbfreder avatar neves97 avatar olegz avatar orozcoadrian avatar richarddavison avatar salmansharifov avatar sapessi avatar sergioescala avatar sullis avatar tjordahl avatar valerena avatar vkuptcov avatar yyolk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

serverless-java-container's Issues

Principal.getName with federated cognito user not returning identityId

Hi,
I am using spring with Api gateway and lamba proxy.
When i Inject the principal on my controller it does not return the cognito identity with federated user.
The principale getName method now return the temporary user generated by the assume role call.

before the 0.5 my getAuthentificationScheme was AUTH_SCHEME_COGNITO, but now it fall into the AUTH_SCHEME_AWS_IAM

4f1e773#diff-dd23022884ed5861d345f0b5f36b2cc7

seen with @sapessi in gittter

Inject ServletContext and HttpServletResponse automatically

Having hundrerds of Jersey endpoints where ServletContext and HttpServletResponse is inyected, when using 'aws-serverless-java-container' I have to modify the code in order to obtain the Servlet context from the Request.

Could be simpler if the ServletContext and HttpServletResponse could be inyected as HttpServletRequest is.

@Context
   private ServletContext myContext;
   @Context
   private javax.servlet.http.HttpServletRequest myServletRequest;
   @Context
   private javax.servlet.http.HttpServletResponse myServletResponse;
   @POST
   @Consumes({MediaType.APPLICATION_JSON})
   @Produces({MediaType.APPLICATION_JSON + ";charset=UTF-8"})
   public Response execute( com.awslambdatest.simpletest_RESTInterfaceIN entity )
   {
..
..
}

I'm already inyecting HttpServletRequest this way:
https://github.com/awslabs/aws-serverless-java-container#jersey-servlet-request

addCookie in HttpServletResponse not working correctly

From Gitter chat:

((HttpServletResponse) response).addCookie(ck); does not set cookie at a given domain (root domain for example) also it does not set it as secure & HTTPOnly. However if I use ((HttpServletResponse) response).addHeader("Set-Cookie", cookie); it works okay.. any suggestions on why its behaving in such a manner?

Jersey HttpServletResponse Injection

From the docs, I can inject an HttpServletRequest using the following:

ResourceConfig app = new ResourceConfig()
    .packages("com.amazonaws.serverless.proxy.test.jersey")
    .register(new AbstractBinder() {
        @Override
        protected void configure() {
            bindFactory(AwsProxyServletRequestFactory.class)
                .to(HttpServletRequest.class)
                .in(RequestScoped.class);
            bindFactory(AwsProxyServletContextFactory.class)
                .to(ServletContext.class)
                .in(RequestScoped.class);
        }
    });

And I can access the HttpServletRequest using:

@Path("/my-servlet") @GET
public String echoServletHeaders(@Context HttpServletRequest context) {
    Enumeration<String> headerNames = context.getHeaderNames();
    while (headerNames.hasMoreElements()) {
        String headerName = headerNames.nextElement();
    }
    return "servlet";
}

However, I have not found a way to inject the HttpServletResponse. It would be nice to bind a factory method like:

bindFactory(AwsProxyServletResponseFactory.class)
                .to(HttpServletResponse.class)
                .in(RequestScoped.class);

So that I can access the HttpServletResponse using the @context object, e.g. something like:

@Path("/my-servlet") @GET
public String echoServletHeaders(@Context HttpServletRequest request, @Context HttpServletResponse) {
//stuff
}

If this is not possible, is there another way to inject the HttpServletResponse? I tried using the @context above the @path, but the HttpServletResponse always returns null. Here is a snippet of what I tried:

@Context private ServletContext myContext;
    @Context private HttpServletResponse httpResponse;
    @Path("/saml")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public Response processSAML(@Context HttpServletRequest httpRequest) {
//httpResponse is null

Spring Boot unable to load ServletContext

Taking the PetStore example and updating it with the suggestions from the readme to launch spring-boot, the springBootApplication.run() line continues to fail with "A ServletContext is required to configure default servlet handling". I've tried multiple various configurations and continue to get this exception. Could we get a working example of spring-boot included in the checked in examples?

New release?

Any way we can get a new release with the recent changes? Are there any other roadmap items you have in mind for this library?

Spring exception message missing in API gateway response

Hi,
When you throw an exception with @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) annotation.
API gateway answer with the right status code but the exception message is gone.

sample code to reproduce :

@RestController
@EnableWebMvc
class MyController {
   @RequestMapping(path = "Hello", method = RequestMethod.GET)
    public void coucou() {
        throw new YourException("Hello");
    }
}

@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public class YourException extends RuntimeException {
    public YourException(String message) {
        super(message);
    }
}

isBase64Encoded() is not mapped.

How to reproduce:

Enable binary support in the API Gateway:

Place following code in the handler:

import com.amazonaws.serverless.exceptions.ContainerInitializationException;
import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.internal.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.amazonaws.util.Base64;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.maciejtreder.aws.webpush.AwsWebPushApp;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;


public class HttpHandler implements RequestStreamHandler {
    private SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
    private static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); //work-around for another issue
    }

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
            throws IOException {

        String theString = IOUtils.toString(inputStream, "UTF-8");
        System.out.println(theString);

        if (handler == null) {
            try {
                handler = SpringLambdaContainerHandler.getAwsProxyHandler(AwsWebPushApp.class);
            } catch (ContainerInitializationException e) {
                e.printStackTrace();
                outputStream.close();
            }
        }


        AwsProxyRequest request = mapper.readValue(theString, AwsProxyRequest.class);

        System.out.println("is encoded");
        System.out.println(request.isBase64Encoded());

        if (request.getBody() != null) { //here we should be able to use isBase64Encode()
            byte[] decoded = Base64.decode(request.getBody());
            request.setBody(new String(decoded, "utf-8"));
        }

        AwsProxyResponse resp = handler.proxy(request, context);

        mapper.writeValue(outputStream, resp);
        // just in case it wasn't closed by the mapper
        outputStream.close();
    }
}

Output is (in my particular case):

{
    "resource": "/{proxy+}",
    "path": "/webpush/vapid/subscribe",
    "httpMethod": "POST",
    "headers": {
        "Accept": "application/json, text/plain, */*",
        "Accept-Encoding": "gzip, deflate, br",
        "Accept-Language": "en-US,en;q=0.8,pl;q=0.6",
        "CloudFront-Forwarded-Proto": "https",
        "CloudFront-Is-Desktop-Viewer": "true",
        "CloudFront-Is-Mobile-Viewer": "false",
        "CloudFront-Is-SmartTV-Viewer": "false",
        "CloudFront-Is-Tablet-Viewer": "false",
        "CloudFront-Viewer-Country": "PL",
        "content-type": "application/json",
        "Host": "api.angular-universal-serverless.maciejtreder.com",
        "origin": "https://www.angular-universal-serverless.maciejtreder.com",
        "Referer": "https://www.angular-universal-serverless.maciejtreder.com/",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
        "Via": "2.0 68ef8323f03e69804fe5d491909ddb85.cloudfront.net (CloudFront)",
        "X-Amz-Cf-Id": "VcChAC1vhVs1NUb35-PrvGufKXN7am-rQZMBuM4UPBIvom8-0sbFSQ==",
        "X-Amzn-Trace-Id": "Root=1-597497c0-13985d331f52e70f27a3edfb",
        "X-Forwarded-For": "89.64.35.4, 54.239.171.8",
        "X-Forwarded-Port": "443",
        "X-Forwarded-Proto": "https"
    },
    "queryStringParameters": null,
    "pathParameters": {
        "proxy": "vapid/subscribe"
    },
    "stageVariables": null,
    "requestContext": {
        "path": "/webpush/vapid/subscribe",
        "accountId": "548199570266",
        "resourceId": "pep2vp",
        "stage": "production",
        "requestId": "38ece18e-6fa3-11e7-8105-8f56ec1e5e01",
        "identity": {
            "cognitoIdentityPoolId": null,
            "accountId": null,
            "cognitoIdentityId": null,
            "caller": null,
            "apiKey": "",
            "sourceIp": "89.64.35.4",
            "accessKey": null,
            "cognitoAuthenticationType": null,
            "cognitoAuthenticationProvider": null,
            "userArn": null,
            "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
            "user": null
        },
        "resourcePath": "/{proxy+}",
        "httpMethod": "POST",
        "apiId": "k5nsma1gc6"
    },
    "body": "eyJlbmRwb2ludCI6Imh0dHBzOi8vZmNtLmdvb2dsZWFwaXMuY29tL2ZjbS9zZW5kL2MtWjB2RzBRRFN3OkFQQTkxYkgxZW1lRDVJdFhuazN6eGR0aTNldWNhdjNISHBITnJGRHRwcnIzYkd2SWRvSHFfRlotQkp6UjRHc0Jtc3dGaVFVeWNWUzZuNi1LNEtJTnVybjQwcDlSTERTZGV3amJwXzJuakpBdXE0X19EVFNXSXpxanlOWUpLRndmb1FUVU11RUMzLU5KIiwia2V5cyI6eyJwMjU2ZGgiOiJCRmxRS255WFk5eFVTQ2FuTkJNQkZ3TnJ4em9qMThXcDNpaVg2TmpSNWNhcXNYY2czbGJRSC1GUUZFUm5KbTMyX0JjSFFzX3lkekprR19sRm1DNmpZYTA9IiwiYXV0aCI6IlVqRkVkU1JlWW12LWRUYTNlSkw5MEE9PSJ9fQ==",
    "isBase64Encoded": true
}

is encoded
false

As you can see in JSON object, the property isBase64Encoded is set to true, and output from request.isBase64Encoded() gives false (default boolean value).

Same issue occurs for class which implements RequestHandler<AwsProxyRequest, AwsProxyResponse>

AwsServletContext requiring Context in ctor is a pain

I know that this isn't your use-case, but...

... I'm using the Servlet interfaces to build a binding between Lambda and web-abstractions that overlay routing on top of a single servlet.

So I need an AwsServletContext to pass to the init() of their servlet. But I can't have one until the first request is made, because AwsServletContext needs Context. But only for logging, which doesn't seem a good coupling to me.

Could you break this dependency somehow?

Unified logging interface

At the moment the library uses the Lambda Context, where it is available, to access the Logger object. This doesn't scale well and results in "hidden" exceptions in a few places. We should introduce a logger

Spring Lambda load time issue

Apologies if this is wrong place for this query.

I am building Spring Lambda function with and with out Spring Boot. I observe Lambda function takes considerable load time and at times timing out (taking more than 15secs).

Any suggestions on improving the startup times?

Bug - Filter called only once per URL

Summary
Filters are not working as expected (at least for SpringLambdaContainerHandler). Filters are called only the first time a URL is called. I used the sample pet-store for Spring and added a filter as described in the documentation.
First time I called an URL (i.e. /pets/1), the filter is executed as expected. If I call the same URL again, the filter is not executed.
If I call another URL, (i.e. /pets/2), the filter is executed the first time, but not executed for the subsequent calls to that same URL.

Steps to reproduce
From aws-serverless-java-container-master\samples\spring\pet-store, modify LambdaHandler.java to add a filter, named TestFilter which will only logged (into CloudWatch) when the doFilter method is called (see in attachments).

try {
handler = SpringLambdaContainerHandler.getAwsProxyHandler(PetStoreSpringAppConfig.class);
handler.onStartup(c -> {
FilterRegistration.Dynamic registration = c.addFilter("TestFilter", TestFilter.class);
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
});
} catch (ContainerInitializationException e) {

Add the TestFilter class (see in attachments):

public class TestFilter implements Filter {
@Override
public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException {
System.out.println("DoFilter TestFilter");
chain.doFilter(req, res);
}

Expected Result
I expected the TestFilter doFilter() method to be executed each time I access any URL

Actual Result
First time I called an URL (i.e. /pets/1), the filter is executed as expected. If I call the same URL again, the filter is not executed.
If I call another URL, (i.e. /pets/2), the filter is executed the first time, but not executed for the subsequent calls to that same URL.

aws-serverless-spring-sample-with-filter.zip

Inject request principal with Spring framework

The request principal is not automatically injected using the Spring framework.

@RequestMapping(value = "/word-cloud",
            method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody
    WordCloud getWordCloudForTopicId(@RequestParam params,
                                     Principal principal) {

Application Properties Not Loading for Spring Boot

I am having issues loading the application.properties files for my spring boot application I get the following error message. I am trying to include JPA so I connect my lambda function up to an RDS instance.

Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (the profiles "local" are currently active).

Unable to config @Valid for bean validation in spring

If you annotate your project with @EnableWebMvc and you add the hibernate-validator to your classpath, you should be able to use @Valid in your controller to validate the annotated bean...

Unfortunately this is not working...

Any idea why, or a workaround?

Regards

Problems with 403 Forbidden and 405 Method Not Allowed

Hi,
I'm having an issue trying to get a single Java Lambda to handle all HTTP Methods.

Here's my interface:

public interface ContactResource
{
	@DELETE
	@Consumes({MediaType.APPLICATION_JSON})
	@Produces({MediaType.APPLICATION_JSON})
	@Path("/{id}")
	public Response deleteContact(@PathParam("id") String id);

	@POST
	@Consumes({MediaType.APPLICATION_JSON})
	@Produces({MediaType.APPLICATION_JSON})
	public Response createContact(ContactObject co);

	...
}

And my implementation class:

@Path("/contacts")
public class ContactResourceImpl implements ContactResource
{
	@Override
	public Response deleteContact(@PathParam("id") String id)
	{
		return deleteContact(id, null);
	}

	@Override
	public Response createContact(ContactObject co)
	{
		LOG.debug("Entering contacts::POST");
		try
		{
			...
		}
	}
}

Yet when I try to use Postman to call POST on /contacts (actually /TEST/contacts because TEST is my stage name), I get the 403 Forbidden error.

And when I try to use DELETE on /contacts/12345 - where I should receive a 404 Not Found because Contact with id 12345 doesn't exist - I get 405 Method Not Allowed. I also get a return header of "Allow={GET,OPTIONS,PUT}".

Any help would be greatly appreciated!

Thanks,
David

Incorrect use of ServletFileUpload (common-fileupload) results in NPE

We implemented a lambda function (proxy to API Gateway method which consumes multipart content) using the aws-serverless-java-container library.
However, during the testing we found out that it didn't work: all requests were failing with java.lang.NullPointerException: No FileItemFactory has been set.
It seems like the no-args constructor was used in https://github.com/awslabs/aws-serverless-java-container/blob/master/aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java#L658
ServletFileUpload upload = new ServletFileUpload();
Javadoc of that constructior says:
Constructs an uninitialised instance of this class. A factory must be
configured, using setFileItemFactory(), before attempting
to parse requests.

However, we haven't found any setFileItemFactory() calls in the code.

So we changed line 658 to ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); and it worked fine.
Can you confirm if that is a problem/bug?
Also it would be great to add a test case for this code.

Thanks,
Greg

Issue with API GW authentication using Cognito authorizer

I get this in CloudWatch when I call a service configured to use my Cognito Authorizer in API GW. I'm passing a new, valid token received from Cognito in the appropriate header field. I'm using 0.5-SNAPSHOT build I pulled down today from github.

An error occurred during JSON parsing: java.lang.RuntimeException
java.lang.RuntimeException: An error occurred during JSON parsing
Caused by: java.io.UncheckedIOException: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: lambdainternal.util.NativeMemoryAsInputStream@2bec854f; line: 1, column: 1976] (through reference chain: com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest["requestContext"]->com.amazonaws.serverless.proxy.internal.model.ApiGatewayRequestContext["authorizer"]->com.amazonaws.serverless.proxy.internal.model.ApiGatewayAuthorizerContext["claims"])
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: lambdainternal.util.NativeMemoryAsInputStream@2bec854f; line: 1, column: 1976] (through reference chain: com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest["requestContext"]->com.amazonaws.serverless.proxy.internal.model.ApiGatewayRequestContext["authorizer"]->com.amazonaws.serverless.proxy.internal.model.ApiGatewayAuthorizerContext["claims"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:857)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:62)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringMap(MapDeserializer.java:495)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:341)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:520)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:95)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:258)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:125)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:520)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:95)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:258)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:125)
at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1511)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1102)

Error when trying to register a container request filter through a lambda

Hello,

I'm currently working on an authentication filter with aws-serverless-java-container. I've created the filter and registered it in my Handler but when I try and run it in a lambda I get the following error message:

{
"errorMessage": "A MultiException has 3 exceptions. They are:\n1. java.lang.IllegalStateException: A descriptor SystemDescriptor(\n\timplementation=org.glassfish.jersey.server.internal.process.ServerProcessingBinder$UriRoutingContextFactory\n\tcontracts={org.glassfish.jersey.server.ExtendedUriInfo,javax.ws.rs.container.ResourceInfo,javax.ws.rs.core.UriInfo}\n\tscope=org.glassfish.jersey.process.internal.RequestScoped\n\tqualifiers={}\n\tdescriptorType=PROVIDE_METHOD\n\tdescriptorVisibility=NORMAL\n\tmetadata=\n\trank=0\n\tloader=org.glassfish.hk2.utilities.binding.AbstractBinder$2@649d209a\n\tproxiable=true\n\tproxyForSameScope=false\n\tanalysisName=null\n\tid=16\n\tlocatorId=0\n\tidentityHashCode=1792845110\n\treified=true) requires a proxy, but the proxyable library is not on the classpath\n2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of test.AuthenticationFilter errors were found\n3. java.lang.IllegalStateException: Unable to perform operation: resolve on test.AuthenticationFilter\n",
"errorType": "org.glassfish.hk2.api.MultiException"
}

I've previously registered a ContainerResponseFilter and that works perfectly fine. Is there any reason why my request filter isn't working the same way? I'm able to run the code locally and only get the error message when running it in a lambda.

This is my handler, the filter I’m trying to register is called "AuthenticationFilter"

public class ApplicationHandler implements RequestHandler<AwsProxyRequest, AwsProxyResponse> {
private ResourceConfig jerseyApplication = new ResourceConfig()
.packages("test")
.register(AuthenticationFilter.class)
.register(JacksonFeature.class)
.register(CORSResponseFilter.class);
private JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler
= JerseyLambdaContainerHandler.getAwsProxyHandler(jerseyApplication);

@Override
public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
    return handler.proxy(awsProxyRequest, context);
}

}

Any help will be appreciated.

Feature request - configurable Principal field

At the moment in a Spring scenario, if you inject the Principal and use Cognito auth, you get the cognito sub (Subject). If you need the username, you must either do a lookup request to Cognito, or fish the ApiGatewayRequestContext and grab it via .getAuthorizer().getClaims().getUsername()

It would be nice if the field that is mapped to the Principal name can be configurable so that one can point it to the username instead of the sub.

Query Parameters with space.

Not sure if this is the right place to ask this question, but I can’t seem to find much help on the subject. We’ve been using the container now for months and everything works great. We’ve used this for a simple API which only contains a single Query Parameter. We’ve noticed that when we put a space into the parameter then the API Gateway returns an Internal Server Error immediately. So for example

/search?identifier=XXXXX (works fine)
/search?identifier=XXX XXX (internal server error)

If I run the API from the AWS Console test facility and replace the space with %20 then it works. So XXX%20XXX, but if I test the API from Postman, then with the space or the %20 I get the internal server error.

From looking at the logs, it appears that the request is being sent to the Lambda. At first we assumed it was the gateway returning the error straight away, but it looks like it might be the way the Lambda is handling the space in the param.

Hope someone can help because we’re stumped. From reading some stuff online, for a non Proxy API the suggestion is to use a message template on the parameters and use the $util.urlEncode(), but I can’t see how to apply this with a proxy.

Is there something we have to put into the Java code to take care of this?

Spring RequestBody injection throws NPE

From the Gitter room.

for @RequestBody(required = false) and if the client does not pass RequestBody, AWS serverless throws NPE.. Here is the stacktrace,

java.lang.NullPointerException: null
at com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest.getInputStream(AwsProxyHttpServletRequest.java:385)
at org.springframework.http.server.ServletServerHttpRequest.getBody(ServletServerHttpRequest.java:176)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver$EmptyBodyCheckingHttpInputMessage.<init>(AbstractMessageConverterMethodArgumentResolver.java:313)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:189)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:150)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:128)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at com.amazonaws.serverless.proxy.spring.LambdaSpringApplicationInitializer.dispatch(LambdaSpringApplicationInitializer.java:98)

enable cors in container

It is possible to modify sam.yaml to enable cors without adding swagger.yaml or manually enable cors in APIGateway? If not how to dynamically add the lambda function name to swagger. The lambda function will be FUNCTION_NAME-XXXXXXX "XXXXXX" is random hash.

Spark integration fails due to web sockets not being supported

I have a working hello-world-ish local Spark server, but when trying to run it on Lambda it throws the UnsupportedOperationException when the embedded server tries to configure web sockets.

Here's the exact error I'm getting:

START RequestId: <request_id_redacted> Version: $LATEST
[main] INFO <class_redacted> - Initializing routes
[Thread-0] ERROR spark.Spark - ignite failed
java.lang.UnsupportedOperationException
	at com.amazonaws.serverless.proxy.spark.embeddedserver.LambdaEmbeddedServer.configureWebSockets(LambdaEmbeddedServer.java:65)
	at spark.Service.lambda$init$2(Service.java:502)
	at java.lang.Thread.run(Thread.java:745)
END RequestId: <request_id_redacted>
REPORT RequestId: <request_id_redacted>	Duration: 1501.41 ms	Billed Duration: 1600 ms 	Memory Size: 512 MB	Max Memory Used: 54 MB	
RequestId: <request_id_redacted> Process exited before completing request

I can't see a current workaround other than some crazy reflection magic. I guess there are some potential fixes like:

  • change LambdaEmbeddedServer.configureWebSockets() to not throw an exception
  • use a custom initExceptionHandler on the Spark.Service instance to ignore the exception

Thoughts?

Field "path" not in AwsProxyRequest

When trying to deserialize the AwsProxyRequest within a StreamHandler-derived class, I get:

Unrecognized field "path" (class com.amazonaws.serverless.proxy.internal.model.ApiGatewayRequestContext), not marked as ignorable (9 known properties: "resourcePath", "apiId", "accountId", "resourceId", "requestId", "identity", "httpMethod", "stage", "authorizer"])
From:

AwsProxyRequest request = mapper.readValue(input, AwsProxyRequest.class);

Thanks,
David

HttpServletRequest.getRequestUrl is incorrect

When running in AWS using the Spring integration, fronted by an API Gateway in AWS Proxy mode, calling HttpServletRequest returns a StringBuffer of the following format:

<api-gateway-host>//<requestPath>

It should return something like the following:

<scheme>://<api-gateway-host>/<stage>/<requestPath>

The primary visible impact of this is when using the Spring Data REST with auto-generated Controllers from Repositories - this creates HATEAOS-based Entities with self references, however all of the references are wrong. The ALPS metadata at the 'profile' endpoints are all incorrect as well.

There is a Dependency convergence within your project

I am working with your jersey samples and I have been notices some Dependency convergence issues:
Dependency convergence error for javax.ws.rs:javax.ws.rs-api:2.1-m01 paths to dependency are:
+-com.amazonaws.serverless:aws-serverless-java-container-jersey:0.5.1
+-com.amazonaws.serverless:aws-serverless-java-container-core:0.5.1
+-javax.ws.rs:javax.ws.rs-api:2.1-m01
and
+-com.amazonaws.serverless:aws-serverless-java-container-jersey:0.5.1
+-org.glassfish.jersey.core:jersey-server:2.24
+-org.glassfish.jersey.core:jersey-client:2.24
+-javax.ws.rs:javax.ws.rs-api:2.0.1
and
+-com.sunrun.fem.interval:fem-interval-rest:1.0.0-SNAPSHOT
+-com.amazonaws.serverless:aws-serverless-java-container-jersey:0.5.1
+-org.glassfish.jersey.core:jersey-server:2.24
+-javax.ws.rs:javax.ws.rs-api:2.0.1

I think it would be fixed if in your https://github.com/awslabs/aws-serverless-java-container/blob/master/aws-serverless-java-container-core/pom.xml#L36e

would refer to version:

<dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>javax.ws.rs-api</artifactId>
    <version>2.1-m05</version>
</dependency>

and if the following line would refer to the library:
https://github.com/awslabs/aws-serverless-java-container/blob/master/aws-serverless-java-container-jersey/pom.xml#L19

<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>2.26-b03</version>
</dependency>

there are also some Dependency convergence issues with the samples as well. I will submit an issue if i can find a simple solution. The latest version does not work since org.glassfish.hk2.api.Factory is no longer present.

Add support for Cognito User Pool authorizer

Update internal methods to support the claims object in the request authorization context. This is relevant when an API is configured with a User Pool authorizer from Amazon Cognito.

CDI Support for the Jersey/JAX-RS container?

Ok guys, this is really awesome!
Thanks for doing this.

I've got the Spring integration up and running in minutes. It really works like a charme with all the Spring functionality included like autowiring etc.

The Jersey/JAX-RS integration also works quite good, but I would love to see some CDI support here as well. Is this somehow possible to provide a simple/small/lightweight CDI integration with Weld, Guice or something similar?

thx + regards,
Niko

Use Stage to activate a specific Spring profile

If the lambda is running under a specific 'stage', the component should use this to activate a Spring profile that may be packaged with the function. This will allow the user to control different configurations (data source, output queue, etc) based on the stage it's running as (test, prod, etc)

AwsProxyServletContext Does Not Support Servlet Filter Registration

Hello,

I am trying to use this library along with Spring Boot to create a REST application that uses javax.servlet.Filter implementations to transform responses. I see that all of the filter-related methods in AwsProxyServletContext are overridden to simply return null or to do nothing (source). This would seem to indicate that Filters are not supported with this container. Is that correct?

I have attempted several methods of registering Filters, which work properly with my local tests, but do not seem to have any effect when running in a live Lambda.

If I cannot use Filter, I will try to use Spring's HandlerInterceptor mechanism instead.

URLs in html getting encoded

I built a Spring MVC application and deployed on Lambda. I have a spring controller on Lamda which returns a HTML page. This page contains links as part of th:href attribute. But when rendered the link is not working as expected as URLs are getting encoded.

Looks some encoding filter getting applied on the content and encrypting all the URLs. This is happening even with the URL passed as "redirect:"

Is there any configuration that i can go to avoid this issue.

For instance URL "maps.google.com?ll=40.447786,-80.001202&q=Alcoa+Corp" comng up as
%2F%2Fmaps.google.com%3Fll%3D40.447786%2C-80.001202%26q%3DAlcoa%2520Corp

Accept-Encoding header causes Spring to throw 500 errors

If Content-Type request header is application/json instead of application/json;charset=UTF, then providing Accept-Encoding values other than UTF-8 (e.g. gzip, deflate, sdch) will result in 500 errors when running on AWS Lambda. Have not been able to reproduce this locally, but it happens without fail when run on AWS Lambda.

Full stack trace:

java.nio.charset.IllegalCharsetNameException: gzip, deflate, sdch
java.nio.charset.Charset.checkName(Charset.java:315) java.nio.charset.Charset.lookup2(Charset.java:484)
java.nio.charset.Charset.lookup(Charset.java:464)
java.nio.charset.Charset.forName(Charset.java:528) ~[na:1.8.0_101]
	at org.springframework.http.server.ServletServerHttpRequest.getHeaders(ServletServerHttpRequest.java:131) ~[task/:na]
	at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:167) ~[task/:na]
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:150) ~[task/:na]
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:128) ~[task/:na]
	at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[task/:na]
	at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:160) ~[task/:na]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129) ~[task/:na]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) ~[task/:na]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[task/:na]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[task/:na]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[task/:na]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) ~[task/:na]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[task/:na]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [task/:na]
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) [task/:na]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) [task/:na]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [task/:na]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:770) [task/:na]
	at com.amazonaws.serverless.proxy.spring.LambdaSpringApplicationInitializer.dispatch(LambdaSpringApplicationInitializer.java:82) [task/:na]
	at com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler.handleRequest(SpringLambdaContainerHandler.java:136) [task/:na]
	at com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler.handleRequest(SpringLambdaContainerHandler.java:37) [task/:na]
	at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:88) [task/:na]
	at com.joeyvmason.serverless.spring.application.LambdaHandler.handleRequest(LambdaHandler.java:33) [task/:na]
	at com.joeyvmason.serverless.spring.application.LambdaHandler.handleRequest(LambdaHandler.java:14) [task/:na]
	at lambdainternal.EventHandlerLoader$PojoHandlerAsStreamHandler.handleRequest(EventHandlerLoader.java:375) [LambdaSandboxJava-1.0.jar:na]
	at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:1139) [LambdaSandboxJava-1.0.jar:na]
	at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:285) [LambdaSandboxJava-1.0.jar:na]
	at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:57) [LambdaSandboxJava-1.0.jar:na]
	at java.lang.Class.forName0(Native Method) [na:1.8.0_101]
	at java.lang.Class.forName(Class.java:348) [na:1.8.0_101]
	at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:94) [LambdaJavaRTEntry-1.0.jar:na]
INFO; Jan 18, 2017 01:49:51 AM; tid:[main]; LoggingInterceptor afterCompletion; Request completed with Status(500)

Spring Boot is not handling the request

Hi,

I followed the documentation about Spring Boot, I have:

LambdaHandler:

public class LambdaHandler implements RequestHandler<AwsProxyRequest, AwsProxyResponse> {
    SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler

    private static final Logger LOG = Logger.getLogger(LambdaHandler.class);

    public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
        LOG.info("received: " + awsProxyRequest.dump());
        return handler.proxy(awsProxyRequest, context);
    }

    public LambdaHandler(){
        long milis = System.currentTimeMillis()
        SpringApplication springBootApplication = new SpringApplication(AppsApplication.class);
        springBootApplication.setWebEnvironment(false);
        springBootApplication.setBannerMode(Banner.Mode.OFF);

        // create a new empty context and set the spring boot application as a parent of it
        ConfigurableWebApplicationContext wrappingContext = new AnnotationConfigWebApplicationContext();
        wrappingContext.setParent(springBootApplication.run());

        // now we can initialize the framework with the wrapping context
        handler = SpringLambdaContainerHandler.getAwsProxyHandler(wrappingContext);
        LOG.info("Loading time: " + (System.currentTimeMillis()-milis) )
    }
}

My controller code:

@RequestMapping("/apps/{id}")
public App getApp(@PathVariable String id) {
        appService.get(id)
        return appService.get(id)
}

I get on logs:
2017-10-25 18:23:29.361 WARN 20596 --- [ main] o.s.web.servlet.PageNotFound : No mapping found for HTTP request with URI [/apps/1] in DispatcherServlet with name 'aws-servless-java-container'

But removing: springBootApplication.setWebEnvironment(false);

I have on logs:
2017-10-25 18:23:28.644 INFO 20596 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/apps/{id}]}" onto public AppController.getApp(java.lang.String)

And it's working, any help?

Thank you!

Spark: Cold start occassionally throws NullPointer exception

Following spark sample, occasionally getting:

START RequestId: 1a7fc844-9fdd-11e7-bdf6-7b809f4c7a77 Version: $LATEST
22 Sep 2017 21:29:26 INFO LambdaContainerHandler - Starting Lambda Container Handler
22 Sep 2017 21:29:26 INFO LambdaHandler - Registering path: /sea/v1
22 Sep 2017 21:29:26 INFO LambdaEmbeddedServer - Spark called configureWebSockets. However, web sockets are not supported
22 Sep 2017 21:29:26 INFO LambdaEmbeddedServer - Starting Spark server, ignoring port and host
22 Sep 2017 21:29:26 ERROR LambdaContainerHandler - Error while handling request
java.lang.NullPointerException
at com.amazonaws.serverless.proxy.spark.SparkLambdaContainerHandler.handleRequest(SparkLambdaContainerHandler.java:169)
at com.amazonaws.serverless.proxy.spark.SparkLambdaContainerHandler.handleRequest(SparkLambdaContainerHandler.java:61)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:126)
at com.logindex.lambda.LambdaHandler.handleRequest(LambdaHandler.kt:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at lambdainternal.EventHandlerLoader$PojoMethodRequestHandler.handleRequest(EventHandlerLoader.java:259)
at lambdainternal.EventHandlerLoader$PojoHandlerAsStreamHandler.handleRequest(EventHandlerLoader.java:178)
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888)
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:281)
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:94)
22 Sep 2017 21:29:27 ERROR AwsProxyExceptionHandler - Called exception handler for:
java.lang.NullPointerException
at com.amazonaws.serverless.proxy.spark.SparkLambdaContainerHandler.handleRequest(SparkLambdaContainerHandler.java:169)
at com.amazonaws.serverless.proxy.spark.SparkLambdaContainerHandler.handleRequest(SparkLambdaContainerHandler.java:61)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:126)
at com.logindex.lambda.LambdaHandler.handleRequest(LambdaHandler.kt:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at lambdainternal.EventHandlerLoader$PojoMethodRequestHandler.handleRequest(EventHandlerLoader.java:259)
at lambdainternal.EventHandlerLoader$PojoHandlerAsStreamHandler.handleRequest(EventHandlerLoader.java:178)
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:888)
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:281)
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:64)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:94)
22 Sep 2017 21:29:27 INFO LambdaEmbeddedServer - Called join method, nothing to do here since Lambda only runs a single event per container
END RequestId: 1a7fc844-9fdd-11e7-bdf6-7b809f4c7a77
REPORT RequestId: 1a7fc844-9fdd-11e7-bdf6-7b809f4c7a77	Duration: 1834.28 ms	Billed Duration: 1900 ms Memory Size: 256 MB	Max Memory Used: 56 MB	

Feature Request - Allow to run locally

I managed to make it run on Tomcat as a WAR file with some playing with maven profiles, but it's not exactly the same as the ApiGatewayRequestContext is not available in an offline / local war deployment. It will be nice if there was a built in way to run the app locally as a Spring application with similar RequestContext behavior as in a lambda deployment.

Bug - Filter chain not working properly

Summary
Filter chain is not working as expected. In some case I want to set the response directly, for example for authorization (i.e return http code 401), in doFilter method and interrupt the process. But even if the http code of the reponse is correctly set (401), the process is not interrupted. The controller with the URL requested is then called (but should not be). Then you received http 401 with a response as if the request was successful.

Steps to reproduce
From aws-serverless-java-container-master\samples\spring\pet-store, modify LambdaHandler.java to add a filter, named TestFilter which will only set response to http 401 when the doFilter method is called (see in attachments). Call url /pets. You will receive a http response code 401 with a list of pets.

Add the TestFilter class (see in attachments):

public class TestFilter implements Filter {
@OverRide
public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException {
if(true) {
((HttpServletResponse) res).setStatus(401);
return;
}
chain.doFilter(req, res);
}

Expected Result
I expected the TestFilter doFilter() to interrupt the process if I return before calling chain.doFilter method and then just receive a http reponse code 401 (without the list of pets)

Actual Result
TestFilter doFilter() is executed, the response is set (http code 401) but the controller is actually called and the list of pets returned.

aws-serverless-spring-bug.zip

Enable to Add Spring DelegatingFilterProxy Filter to Handler

Hi,

I am trying to Run a Spring Code on Lambda. Everything works except Spring's URL Based Security. I Tried adding the springSecurityFilterChain filter my self but it gives the following exception.

	 java.lang.IllegalArgumentException: FilterConfig must not be null
		at org.springframework.util.Assert.notNull(Assert.java:134)
		at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:175)
		at com.amazonaws.serverless.proxy.internal.servlet.FilterHolder.init(FilterHolder.java:84)
		at com.amazonaws.serverless.proxy.internal.servlet.FilterChainHolder.doFilter(FilterChainHolder.java:83)
		at com.amazonaws.serverless.proxy.internal.servlet.AwsLambdaServletContainerHandler.doFilter(AwsLambdaServletContainerHandler.java:184)
		at com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler.handleRequest(SpringLambdaContainerHandler.java:139)
		at com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler.handleRequest(SpringLambdaContainerHandler.java:35)
		at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:126)

Below is my Code

App Config

	 @Configuration
	 @EnableWebMvc
	 @EnableAspectJAutoProxy
	 @ComponentScan(basePackages = "com.sample")
	 @PropertySource(value = { "classpath:config.properties" })
	 public class AppConfiguration {

	 }

WebSecurity Config

	 @Configuration
	 @EnableWebSecurity
	 @EnableGlobalMethodSecurity(prePostEnabled = true)
	 public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
	 
	 @Override
		 protected void configure(HttpSecurity http) throws Exception {
			 
			 http.csrf().disable();
			 http.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint);
			 http.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll();
			 http.formLogin().loginPage("/login").permitAll();
			 http.logout().logoutUrl("/logout").logoutSuccessHandler(restLogoutSuccessHandler);
			 http.authorizeRequests().antMatchers("/**").authenticated();
			 http.addFilterBefore(authenticationFilter(),UsernamePasswordAuthenticationFilter.class);
		 }
	 
	 }

Request Handler Method

	 @Override
	 public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
	 
	 if(handler == null)
	 {
		 try {
			 handler = SpringLambdaContainerHandler.getAwsProxyHandler(AppConfiguration.class);
			 
			 handler.onStartup(servletContext -> {
				 
				 Dynamic securityFilter = servletContext.addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, DelegatingFilterProxy.class);
				 securityFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
				 
			 });
			 
		 } catch (ContainerInitializationException e) {
			 e.printStackTrace();
		 }
	 }
	 
	 return handler.proxy(awsProxyRequest, context);
	 } 

I am not able to find any way to initialize the filterConfig variable of FilterHolder class.

Please a look into the issue.

custom domain name with base path

When I specified /ping1 as basePath for my custom domain. when I am trying to invoke them (api.mydomain.com/ping1/ping) I got 404. after dump the input stream, i found the base path was passed into API request path like below.
{"resource":"/{proxy+}","path":"/ping1/ping","httpMethod":"GET","headers":

Do we have a good solution to solve the problem?

Thanks in advance

Spring MVC - requestDispatcher null

I tried Spring MVC application with Spring boot. I have a Controller method which will forward to success /failure html page. This works fine with Spring Boot and Lambda. But I am facing Load time and Jar file size issues wirh Spring Boot.

So decided to try without Spring boot, with plain Spring using aws-serverless framework. I started getting error like "javax.servlet.ServletException: Could not get RequestDispatcher for ... ". When I looked at code, in AwsProxyServletContext the getRequestDispatcher() method is returning null. Then I realized there is no application / web server (container) is available in the package. Tried with Jetty. But couldn't get it to working (html page getting generated). Sample code is at : https://github.com/gmaruti/mvc-sample-spring.git

Please let me know whether there any better approach!

  • Thanks,

ApiGatewayAuthorizerContext not serializing contextProperties

We are adding some context in a custom authorizer and it seems like the ApiGatewayAuthorizerContext is not serializing it properly. The principalId is available but we can't get anything else through getContextValue(String key).

Everything also works fine when using the following interface:

public AwsProxyResponse handleRequest(Map<String, Object> input, Context context) {}

@PathVariables not URL encoded

In a classic Spring deployment (e.g. on a standalone / built in Spring Boot embedded Tomcat), when you get a @PathVariable, usually it's already URL decoded, e.g. if I send a request to

/foo/bar/Some%20Thing

to a

@GetMapping("/foo/bar/{baz}")
public void handle(@PathVariable("baz") String baz) …

then baz should be "Some Thing"

This can be fixed in the Lambda handler easily, but I think it will be nice the container will take care of it (can be a configuration param as it's a breaking change)

Right now the workaround I used is simply:

request.setPath(java.net.URLDecoder.decode(request.getPath(), "UTF-8"));

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.