Skip to content

Commit c01c98f

Browse files
committed
Fixed a potential null pointer in security utils and simplified header processing to continue addressing the feedback in #263
1 parent 6cf2398 commit c01c98f

File tree

3 files changed

+76
-27
lines changed

3 files changed

+76
-27
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ public static boolean isValidHost(String host, String apiId, String region) {
7070
* @return A copy of the original string without CRLF characters
7171
*/
7272
public static String crlf(String s) {
73+
if (s == null) {
74+
return null;
75+
}
7376
return s.replaceAll("[\r\n]", "");
7477
}
7578

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

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

1515
import com.amazonaws.serverless.proxy.RequestReader;
16-
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
1716
import com.amazonaws.serverless.proxy.internal.SecurityUtils;
1817
import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
1918
import com.amazonaws.serverless.proxy.model.ContainerConfig;
2019
import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap;
2120
import com.amazonaws.services.lambda.runtime.Context;
2221

23-
import com.fasterxml.jackson.core.JsonProcessingException;
24-
import org.apache.http.HeaderElement;
2522
import org.apache.http.message.BasicHeaderValueParser;
26-
import org.apache.http.message.ParserCursor;
27-
import org.apache.http.util.CharArrayBuffer;
2823
import org.slf4j.Logger;
2924
import org.slf4j.LoggerFactory;
3025

@@ -376,31 +371,44 @@ protected List<HeaderValue> parseHeaderValue(String headerValue, String valueSep
376371
newValue.setRawValue(v);
377372

378373
for (String q : curValue.split(qualifierSeparator)) {
379-
// contains key/value pairs and it's not a base64-encoded value.
380-
if (q.contains(HEADER_KEY_VALUE_SEPARATOR) && !q.trim().endsWith("==")) {
381-
String[] kv = q.split(HEADER_KEY_VALUE_SEPARATOR);
382-
String key = kv[0].trim();
383-
String val = null;
384-
if (kv.length > 1) {
385-
val = kv[1].trim();
374+
375+
String[] kv = q.split(HEADER_KEY_VALUE_SEPARATOR, 2);
376+
String key = null;
377+
String val = null;
378+
// no separator, set the value only
379+
if (kv.length == 1) {
380+
val = q.trim();
381+
}
382+
// we have a separator
383+
if (kv.length == 2) {
384+
// if the length of the value is 0 we assume that we are looking at a
385+
// base64 encoded value with padding so we just set the value. This is because
386+
// we assume that empty values in a key/value pair will contain at least a white space
387+
if (kv[1].length() == 0) {
388+
val = q.trim();
386389
}
387-
// TODO: Should we concatenate the rest of the values?
388-
if (newValue.getValue() == null) {
389-
newValue.setKey(key);
390-
newValue.setValue(val);
391-
} else {
392-
// special case for quality q=
393-
if ("q".equals(key)) {
394-
curPreference = Float.parseFloat(val);
395-
} else {
396-
newValue.addAttribute(key, val);
397-
}
390+
// this was a base64 string with an additional = for padding, set the value only
391+
if ("=".equals(kv[1].trim())) {
392+
val = q.trim();
393+
} else { // it's a proper key/value set both
394+
key = kv[0].trim();
395+
val = ("".equals(kv[1].trim()) ? null : kv[1].trim());
398396
}
397+
}
398+
399+
if (newValue.getValue() == null) {
400+
newValue.setKey(key);
401+
newValue.setValue(val);
399402
} else {
400-
newValue.setValue(q.trim());
403+
// special case for quality q=
404+
if ("q".equals(key)) {
405+
curPreference = Float.parseFloat(val);
406+
} else {
407+
newValue.addAttribute(key, val);
408+
}
401409
}
402-
newValue.setPriority(curPreference);
403410
}
411+
newValue.setPriority(curPreference);
404412
values.add(newValue);
405413
}
406414

@@ -428,7 +436,6 @@ protected String decodeRequestPath(String requestPath, ContainerConfig config) {
428436

429437
}
430438

431-
432439
/**
433440
* Class that represents a header value.
434441
*/

aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletRequestTest.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.junit.Test;
1111

1212
import javax.servlet.ServletException;
13+
import javax.servlet.http.Cookie;
1314
import javax.ws.rs.core.HttpHeaders;
1415

1516
import static org.junit.Assert.*;
@@ -85,10 +86,48 @@ public void headers_parseHeaderValue_encodedContentWithEquals() {
8586
String value = Base64.getUrlEncoder().encodeToString("a".getBytes());
8687

8788
List<AwsHttpServletRequest.HeaderValue> result = context.parseHeaderValue(value);
88-
89+
assertTrue(result.size() > 0);
8990
assertEquals("YQ==", result.get(0).getValue());
9091
}
9192

93+
@Test
94+
public void headers_parseHeaderValue_base64EncodedCookieValue() {
95+
String value = Base64.getUrlEncoder().encodeToString("a".getBytes());
96+
String cookieValue = "jwt=" + value + "; secondValue=second";
97+
AwsProxyRequest req = new AwsProxyRequestBuilder("/test", "GET").header(HttpHeaders.COOKIE, cookieValue).build();
98+
AwsHttpServletRequest context = new AwsProxyHttpServletRequest(req,null,null);
99+
100+
Cookie[] cookies = context.getCookies();
101+
102+
assertEquals(2, cookies.length);
103+
assertEquals("jwt", cookies[0].getName());
104+
assertEquals(value, cookies[0].getValue());
105+
}
106+
107+
@Test
108+
public void headers_parseHeaderValue_cookieWithSeparatorInValue() {
109+
String cookieValue = "jwt==test; secondValue=second";
110+
AwsProxyRequest req = new AwsProxyRequestBuilder("/test", "GET").header(HttpHeaders.COOKIE, cookieValue).build();
111+
AwsHttpServletRequest context = new AwsProxyHttpServletRequest(req,null,null);
112+
113+
Cookie[] cookies = context.getCookies();
114+
115+
assertEquals(2, cookies.length);
116+
assertEquals("jwt", cookies[0].getName());
117+
assertEquals("=test", cookies[0].getValue());
118+
}
119+
120+
@Test
121+
public void headers_parseHeaderValue_headerWithPaddingButNotBase64Encoded() {
122+
AwsHttpServletRequest context = new AwsProxyHttpServletRequest(null,null,null);
123+
124+
List<AwsHttpServletRequest.HeaderValue> result = context.parseHeaderValue("hello=");
125+
assertTrue(result.size() > 0);
126+
assertEquals("hello", result.get(0).getKey());
127+
System.out.println("\"" + result.get(0).getValue() + "\"");
128+
assertNull(result.get(0).getValue());
129+
}
130+
92131
@Test
93132
public void queryString_generateQueryString_validQuery() {
94133
AwsProxyHttpServletRequest request = new AwsProxyHttpServletRequest(queryString, mockContext, null, config);

0 commit comments

Comments
 (0)