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

Support VPC Lattice as an event source #845

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
30b161f
Added VPCLattice event
mbfreder Mar 7, 2024
38946e4
Added Servlet request and Security Context classes
mbfreder Mar 14, 2024
b9d9ad4
Added Springboot tests
mbfreder Apr 9, 2024
229ddbc
fix nullPointerException on request.getIsBase64Encoded()
mbfreder Apr 11, 2024
0679c1d
Added Jersey tests
mbfreder Apr 16, 2024
2de6093
Added Spring tests
mbfreder Apr 17, 2024
5117dfb
Added Sample app
mbfreder Apr 17, 2024
a71535b
Upgrade to Spring 6.1.6 to fix CVE-2024-22262
mbfreder Apr 17, 2024
7a645ec
remove duplicate lombok dep
mbfreder Apr 17, 2024
679016f
Fix java21 error
mbfreder Apr 17, 2024
2f3fad3
Remove lombok dependency
mbfreder Apr 29, 2024
66a0fc8
return HTTP/1.1 as default protocol
mbfreder Apr 29, 2024
6c57dde
Update SpringBoot version on sample
mbfreder Apr 29, 2024
0108f30
enabled auth to test sample app with awscurl
mbfreder Apr 29, 2024
07a5aba
Merge branch 'main' into vpclattice-integ
mbfreder Apr 29, 2024
4ce1ae6
reduce duplicated code for getServletConnection()
deki May 10, 2024
b587da7
reduce duplicated code for authenticate
deki May 22, 2024
6ca3d07
reduce duplicated code for login/ logout
deki May 22, 2024
6f2b629
reduce duplicated code for upgrade
deki May 22, 2024
5bc26a3
pull up SecurityContext and reduce duplicated code
deki May 22, 2024
389f834
Merge branch 'refs/heads/main' into vpclattice-integ
deki May 22, 2024
eb1b7a4
reduce duplicated code for getRequestDispatcher
deki May 22, 2024
47e8fc9
Merge remote-tracking branch 'origin/main' into vpclattice-integ
deki Aug 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions aws-serverless-java-container-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@
<version>1.2.3</version>
</dependency>

<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>24.0.1</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
Expand Down Expand Up @@ -63,6 +70,12 @@
<version>6.2.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
Copy link
Collaborator

Choose a reason for hiding this comment

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

I know where it's coming from, but can we please not introduce Lombok to this project?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. Thanks

<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.amazonaws.serverless.proxy;

import com.amazonaws.serverless.proxy.internal.jaxrs.AwsVpcLatticeV2SecurityContext;
import com.amazonaws.serverless.proxy.model.VPCLatticeV2RequestEvent;
import com.amazonaws.services.lambda.runtime.Context;
import jakarta.ws.rs.core.SecurityContext;

public class AwsVPCLatticeV2SecurityContextWriter implements SecurityContextWriter<VPCLatticeV2RequestEvent>{
@Override
public SecurityContext writeSecurityContext(VPCLatticeV2RequestEvent event, Context lambdaContext) {
return new AwsVpcLatticeV2SecurityContext(lambdaContext, event);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public abstract class RequestReader<RequestType, ContainerRequestType> {
*/
public static final String API_GATEWAY_CONTEXT_PROPERTY = "com.amazonaws.apigateway.request.context";

/**
* The key for the <strong>VPC Lattice V2 context</strong> property in the PropertiesDelegate object
*/
public static final String VPC_LATTICE_V2_CONTEXT_PROPERTY = "com.amazonaws.vpclattice.request.context";

/**
* The key for the <strong>API Gateway stage variables</strong> property in the PropertiesDelegate object
*/
Expand All @@ -55,6 +60,11 @@ public abstract class RequestReader<RequestType, ContainerRequestType> {
*/
public static final String API_GATEWAY_EVENT_PROPERTY = "com.amazonaws.apigateway.request";

/**
* The key to store the entire VPC Lattice V2 event
*/
public static final String VPC_LATTICE_V2_EVENT_PROPERTY = "com.amazonaws.vpclattice.request";

/**
* The key for the <strong>AWS Lambda context</strong> property in the PropertiesDelegate object
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.amazonaws.serverless.proxy.internal.jaxrs;

import com.amazonaws.serverless.proxy.model.VPCLatticeV2RequestEvent;
import com.amazonaws.services.lambda.runtime.Context;
import jakarta.ws.rs.core.SecurityContext;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.security.Principal;
import java.util.Objects;

/**
* default implementation of the <code>SecurityContext</code> object. This class supports 1 VPC Lattice authentication type:
* AWS_IAM.
*/
@Getter
@AllArgsConstructor
public class AwsVpcLatticeV2SecurityContext implements SecurityContext {

static final String AUTH_SCHEME_AWS_IAM = "AWS_IAM";


private final Context lambdaContext;
private final VPCLatticeV2RequestEvent event;

//-------------------------------------------------------------
// Implementation - SecurityContext
//-------------------------------------------------------------
@Override
public Principal getUserPrincipal() {
if (Objects.equals(getAuthenticationScheme(), AUTH_SCHEME_AWS_IAM)) {
return () -> getEvent().getRequestContext().getIdentity().getPrincipal();
}
return null;
}

@Override
public boolean isUserInRole(String role) {
return role.equals(event.getRequestContext().getIdentity().getPrincipal());
}

@Override
public boolean isSecure() {
return getAuthenticationScheme() != null;
}

@Override
public String getAuthenticationScheme() {
if (Objects.equals(getEvent().getRequestContext().getIdentity().getType(), AUTH_SCHEME_AWS_IAM)) {
return AUTH_SCHEME_AWS_IAM;
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public String format(ContainerRequestType servletRequest, ContainerResponseType
logLineBuilder.append(" ");
logLineBuilder.append(servletRequest.getRequestURI());
logLineBuilder.append(" ");
logLineBuilder.append(servletRequest.getProtocol());
//logLineBuilder.append(servletRequest.getProtocol());
Copy link
Collaborator

Choose a reason for hiding this comment

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

what is the reason for this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's no way to get the protocol from the lattice payload (confirmed with the VPC Lattice team), so I returned an UnsupportedOperationException which throws a nullpointerException on that line. Is it the right thing to return? or should we default to "HTTP/1.1" ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd default to HTTP as this is the only protocol supported anyway.

logLineBuilder.append("\" ");

// %>s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,56 +108,27 @@ public Cookie[] getCookies() {

@Override
public long getDateHeader(String s) {
if (headers == null) {
return -1L;
}
String dateString = headers.getFirst(s);
if (dateString == null) {
return -1L;
}
try {
return Instant.from(ZonedDateTime.parse(dateString, dateFormatter)).toEpochMilli();
} catch (DateTimeParseException e) {
log.warn("Invalid date header in request: " + SecurityUtils.crlf(dateString));
return -1L;
}
return getDateHeader(s, headers);
}

@Override
public String getHeader(String s) {
if (headers == null) {
return null;
}
return headers.getFirst(s);
return getHeader(s, headers);
}

@Override
public Enumeration<String> getHeaders(String s) {
if (headers == null || !headers.containsKey(s)) {
return Collections.emptyEnumeration();
}
return Collections.enumeration(headers.get(s));
return getHeaders(s, headers);
}

@Override
public Enumeration<String> getHeaderNames() {
if (headers == null) {
return Collections.emptyEnumeration();
}
return Collections.enumeration(headers.keySet());
return getHeaderNames(headers);
}

@Override
public int getIntHeader(String s) {
if (headers == null) {
return -1;
}
String headerValue = headers.getFirst(s);
if (headerValue == null || "".equals(headerValue)) {
return -1;
}

return Integer.parseInt(headerValue);
return getIntHeader(s, headers);
}

@Override
Expand Down Expand Up @@ -250,30 +221,17 @@ public String getCharacterEncoding() {

@Override
public void setCharacterEncoding(String s) throws UnsupportedEncodingException {
if (headers == null || !headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
log.debug("Called set character encoding to " + SecurityUtils.crlf(s) + " on a request without a content type. Character encoding will not be set");
return;
}
String currentContentType = headers.getFirst(HttpHeaders.CONTENT_TYPE);
headers.putSingle(HttpHeaders.CONTENT_TYPE, appendCharacterEncoding(currentContentType, s));
setCharacterEncoding(s, headers);
}

@Override
public int getContentLength() {
String headerValue = headers.getFirst(HttpHeaders.CONTENT_LENGTH);
if (headerValue == null) {
return -1;
}
return Integer.parseInt(headerValue);
return getContentLength(headers);
}

@Override
public long getContentLengthLong() {
String headerValue = headers.getFirst(HttpHeaders.CONTENT_LENGTH);
if (headerValue == null) {
return -1;
}
return Long.parseLong(headerValue);
return getContentLengthLong(headers);
}

@Override
Expand All @@ -286,17 +244,7 @@ public String getContentType() {

@Override
public String getParameter(String s) {
String queryStringParameter = getFirstQueryParamValue(queryString, s, config.isQueryStringCaseSensitive());
if (queryStringParameter != null) {
return queryStringParameter;
}

String[] bodyParams = getFormBodyParameterCaseInsensitive(s);
if (bodyParams.length == 0) {
return null;
} else {
return bodyParams[0];
}
return getParameter(queryString, s, config.isQueryStringCaseSensitive());
}

@Override
Expand All @@ -315,7 +263,7 @@ public String[] getParameterValues(String s) {

values.addAll(Arrays.asList(getFormBodyParameterCaseInsensitive(s)));

if (values.size() == 0) {
if (values.isEmpty()) {
return null;
} else {
return values.toArray(new String[0]);
Expand Down Expand Up @@ -456,6 +404,8 @@ public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse se
return asyncContext;
}



@Override
public AsyncContext getAsyncContext() {
if (asyncContext == null) {
Expand Down Expand Up @@ -505,7 +455,7 @@ private MultiValuedTreeMap<String, String> parseRawQueryString(String qs) {
return qsMap;
}

private Headers headersMapToMultiValue(Map<String, String> headers) {
protected static Headers headersMapToMultiValue(Map<String, String> headers) {
if (headers == null || headers.size() == 0) {
return new Headers();
}
Expand Down
Loading
Loading