Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Serverless-java-container to aws-lambda-java-events #584

Closed
wants to merge 15 commits into from

Conversation

mbfreder
Copy link
Contributor

Issue #, if available:

Description of changes:

  • Migrated request and response classes for APIGateway Rest Api, Http Api and ALB to their equivalents in aws-lambda-java-events library
  • Update tests to be compatible with aws-lambda-java-events classes.

By submitting this pull request

  • I confirm that my contribution is made under the terms of the Apache 2.0 license.
  • I confirm that I've made a best effort attempt to update all relevant documentation.

@sapessi
Copy link
Collaborator

sapessi commented Jun 11, 2023

We identified new issues on unchanged lines of code. Navigate to the Amazon CodeGuru Reviewer console to view the recommendations to fix them.

import java.util.stream.Collectors;
import java.util.stream.Stream;

public class AwsAlbHttpServletRequest extends AwsHttpServletRequest{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommendation generated by Amazon CodeGuru Reviewer. Leave feedback on this recommendation by replying to the comment or by reacting to the comment using emoji.

This class references 46 other classes. By comparison, 98% of the classes in the CodeGuru reference dataset reference fewer. This indicates that this class is highly coupled with other classes. A class that is highly coupled with other classes is difficult to understand and its behavior might change unexpectedly when one of its referenced classes is updated. High coupling could also increase the integration test complexity, maintenance cost and technical debt. We recommend that you simplify this class or break it into multiple classes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think breaking this class into multiple classes will add more confusion and make it difficult to understand. This implementation is quite similar to already existing classes like AwsHttpApiV2ProxyHttpServletRequest and AwsProxyHttpServletRequest.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reduce duplicate code? There is a lot copy/paste from AwsProxyHttpServletRequest. We can run mvn pmd:cpd for a report.

@mbfreder mbfreder force-pushed the java-events branch 2 times, most recently from 8430ff4 to a71db17 Compare June 11, 2023 22:41
@@ -94,7 +94,7 @@ public String getAuthenticationScheme() {
if (event.getRequestContext().getAuthorizer() == null) {
return null;
}
if (event.getRequestContext().getAuthorizer().isJwt()) {
if (event.getRequestContext().getAuthorizer().getJwt() != null) { //TODO: Confirm
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check out the TODO here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. Thanks Roger.

case ALB:
return event.getMultiValueHeaders().getFirst(ALB_IDENTITY_HEADER);
}
return event.getRequestContext().getAuthorizer().get("principalId").toString(); // TODO: Check later
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

}

request.setPath(stripBasePath(request.getPath(), config));
if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE) != null && request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0) != null) { //TODO: check
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

@@ -195,7 +194,7 @@ public String getQueryString() {
return this.generateQueryString(
request.getMultiValueQueryStringParameters(),
// ALB does not automatically decode parameters, so we don't want to re-encode them
request.getRequestSource() != RequestSource.ALB,
true, //request.getRequestSource() != RequestSource.ALB, TODO: check
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

@@ -49,17 +52,17 @@ public HttpServletRequest readRequest(AwsProxyRequest request, SecurityContext s
}

request.setPath(stripBasePath(request.getPath(), config));
if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE) != null) {
String contentType = request.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
if (request.getMultiValueHeaders() != null && request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE) != null && request.getMultiValueHeaders().get(HttpHeaders.CONTENT_TYPE).get(0) != null) { //TODO: check
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

}
AwsProxyHttpServletRequest servletRequest = new AwsProxyHttpServletRequest(request, lambdaContext, securityContext, config);
servletRequest.setServletContext(servletContext);
servletRequest.setAttribute(API_GATEWAY_CONTEXT_PROPERTY, request.getRequestContext());
servletRequest.setAttribute(API_GATEWAY_STAGE_VARS_PROPERTY, request.getStageVariables());
servletRequest.setAttribute(API_GATEWAY_EVENT_PROPERTY, request);
servletRequest.setAttribute(ALB_CONTEXT_PROPERTY, request.getRequestContext().getElb());
//servletRequest.setAttribute(ALB_CONTEXT_PROPERTY, request.getRequestContext().getElb()); TODO: elb
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO


assertThat(req.getHeaders().get("accept"), is("*"));
assertThat(req.getHeaders().get("accept"), is("*")); //TODO: Move this to alb specific test file, if any.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I left many of these TODOs after my initial changes. Some were around ALB references that wasn't clear what was the best option at the time

import java.util.stream.Collectors;
import java.util.stream.Stream;

public class AwsAlbHttpServletRequest extends AwsHttpServletRequest{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reduce duplicate code? There is a lot copy/paste from AwsProxyHttpServletRequest. We can run mvn pmd:cpd for a report.

case ALB:
return event.getMultiValueHeaders().getFirst(ALB_IDENTITY_HEADER);
}
return event.getRequestContext().getAuthorizer().get("principalId").toString();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please define a constant for principalId (ideally it should be provided by aws-lambda-events lib).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

return null;
};
}

if (getAuthenticationScheme().equals(AUTH_SCHEME_COGNITO_POOL)) {
return new CognitoUserPoolPrincipal(event.getRequestContext().getAuthorizer().getClaims());
return new CognitoUserPoolPrincipal((Map<String, String>) event.getRequestContext().getAuthorizer().get("claims"));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please define a constant (ideally it should be provided by aws-lambda-events lib).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

if (event.getMultiValueHeaders().containsKey(ALB_ACESS_TOKEN_HEADER)) {
return AUTH_SCHEME_CUSTOM;
}
if (event.getRequestContext().getAuthorizer() != null && ((Map<String, String>) event.getRequestContext().getAuthorizer().get("claims")).get("sub") != null) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use constants

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

claims = c;
}

@Override
public String getName() {
return claims.getSubject();
return claims.get("sub");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use constant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

}

return new StringBuilder().append("null")
.append(".execute-api.")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is for API-Gateway but not for ALB

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the same logic and tweaked it to make this test pass, since ALB's request context doesn't have an API ID. Is there a better way to do it?

@@ -16,6 +16,7 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AwsProxyResponse should be moved to src/test/java

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -17,7 +17,7 @@
<properties>
<spring.version>6.0.9</spring.version>
<springboot.version>3.1.0</springboot.version>
<springsecurity.version>6.1.0</springsecurity.version>
<springsecurity.version>6.0.3</springsecurity.version>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this downgrade seems to be a merge error

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Thanks for pointing that out.

* @param valueSeparator The separator to be used for parsing header values
* @return A list of SimpleMapEntry objects with all of the possible values for the header.
*/
protected static List<AwsHttpServletRequest.HeaderValue> parseHeaderValue(String headerValue, String valueSeparator, String qualifierSeparator) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommendation generated by Amazon CodeGuru Reviewer. Leave feedback on this recommendation by replying to the comment or by reacting to the comment using emoji.

The cyclomatic complexity of this method is 13. By comparison, 98% of the methods in the CodeGuru reference dataset have a lower cyclomatic complexity. This indicates the method has a high number of decisions and it can make the logic difficult to understand and test.

We recommend that you simplify this method or break it into multiple methods. For example, consider extracting the code block on lines 439-447 into a separate method.

import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.cleanUri;
import static com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletRequest.decodeRequestPath;

public class AwsHttpServletRequestHelper {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommendation generated by Amazon CodeGuru Reviewer. Leave feedback on this recommendation by replying to the comment or by reacting to the comment using emoji.

This class references 45 other classes. By comparison, 98% of the classes in the CodeGuru reference dataset reference fewer. This indicates that this class is highly coupled with other classes. A class that is highly coupled with other classes is difficult to understand and its behavior might change unexpectedly when one of its referenced classes is updated. High coupling could also increase the integration test complexity, maintenance cost and technical debt. We recommend that you simplify this class or break it into multiple classes.

Copy link
Collaborator

@deki deki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please rebase on main?

We could use the opportunity and move some of the helping methods to https://github.com/aws/aws-lambda-java-libs/tree/events-v4-serialization-v2 so that other users of that library benefit from it as well. In addition this would reduce the amount of code here.

@@ -169,7 +176,7 @@
<version>${dependencyCheck.version}</version>
<configuration>
<skipProvidedScope>true</skipProvidedScope>
<failBuildOnCVSS>7</failBuildOnCVSS>
<failBuildOnCVSS>8</failBuildOnCVSS>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue was related to a false positive. The CVE has been updated so it's no longer required.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm just noticed https://nvd.nist.gov/vuln/detail/CVE-2023-35116 came back today. FasterXML/jackson-databind#3972 is closed.
Let me add a suppression for it...


@Override
public Enumeration<String> getHeaders(String s) {
return AwsHttpServletRequestHelper.getHeaders(request.getMultiValueHeaders(), s);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both AwsAlbHttpServletRequest and AwsProxyHttpServletRequest extend AwsHttpServletRequest. Instead of overriding all methods twice in subclasses and delegating to the helper, this should be done in AwsHttpServletRequest directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AwsHttpServletRequest doesn't have access to the underlying request objects. I can't think of a way to move the methods there if I can't access the request objects (APIGatewayProxyRequestEvent and ApplicationLoadBalancerRequestEvent).

@@ -22,11 +22,11 @@ Resources:
Type: HttpApi
Properties:
TimeoutInMillis: 20000
PayloadFormatVersion: '1.0'
# PayloadFormatVersion: '1.0'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is that intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, updated.

@@ -265,7 +265,7 @@
<version>${dependencyCheck.version}</version>
<configuration>
<skipProvidedScope>true</skipProvidedScope>
<failBuildOnCVSS>7</failBuildOnCVSS>
<failBuildOnCVSS>8</failBuildOnCVSS>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

@mbfreder
Copy link
Contributor Author

Could you please rebase on main?

We could use the opportunity and move some of the helping methods to https://github.com/aws/aws-lambda-java-libs/tree/events-v4-serialization-v2 so that other users of that library benefit from it as well. In addition this would reduce the amount of code here.

Rebased on main.
Question: Which helping methods are you referring to exactly? I think we could benefit more by having a parent classes for the request and response classes in the java-events library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants