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
Fix/jetty 9.4.x cookie cutter legacy #9352
Changes from 5 commits
6d331bf
06ba736
93f6586
4dd5d66
21bce64
13ba312
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,5 +24,6 @@ | |
public enum CookieCompliance | ||
{ | ||
RFC6265, | ||
RFC6265_LEGACY, // Forgiving of bad quotes. | ||
RFC2965 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,10 +19,13 @@ | |
package org.eclipse.jetty.server; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
import javax.servlet.http.Cookie; | ||
|
||
import org.eclipse.jetty.http.CookieCompliance; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
|
||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.hamcrest.Matchers.is; | ||
|
@@ -162,15 +165,13 @@ public void testRFC2965CookieSpoofingExample() | |
"$Version=\"1\"; session_id=\"1111\"; $Domain=\".cracker.edu\""; | ||
|
||
Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC2965, rawCookie); | ||
|
||
assertThat("Cookies.length", cookies.length, is(2)); | ||
assertCookie("Cookies[0]", cookies[0], "session_id", "1234", 1, null); | ||
assertCookie("Cookies[1]", cookies[1], "session_id", "1111", 1, null); | ||
|
||
cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie); | ||
assertThat("Cookies.length", cookies.length, is(2)); | ||
assertCookie("Cookies[0]", cookies[0], "session_id", "1234\", $Version=\"1", 0, null); | ||
assertCookie("Cookies[1]", cookies[1], "session_id", "1111", 0, null); | ||
assertThat("Cookies.length", cookies.length, is(1)); | ||
assertCookie("Cookies[0]", cookies[0], "session_id", "1111", 0, null); | ||
} | ||
|
||
/** | ||
|
@@ -266,12 +267,93 @@ public void testExcessiveSemicolons() | |
{ | ||
char[] excessive = new char[65535]; | ||
Arrays.fill(excessive, ';'); | ||
String rawCookie = "foo=bar; " + excessive + "; xyz=pdq"; | ||
String rawCookie = "foo=bar; " + new String(excessive) + "; xyz=pdq"; | ||
|
||
Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie); | ||
|
||
assertThat("Cookies.length", cookies.length, is(2)); | ||
assertCookie("Cookies[0]", cookies[0], "foo", "bar", 0, null); | ||
assertCookie("Cookies[1]", cookies[1], "xyz", "pdq", 0, null); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("rfc6265Cookies") | ||
public void testRFC6265CookieParsing(Param param) | ||
{ | ||
Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, param.input); | ||
|
||
assertThat("Cookies.length (" + dump(cookies) + ")", cookies.length, is(param.expected.size())); | ||
for (int i = 0; i < cookies.length; i++) | ||
{ | ||
Cookie cookie = cookies[i]; | ||
assertThat("Cookies[" + i + "] (" + dump(cookies) + ")", cookie.getName() + "=" + cookie.getValue(), is(param.expected.get(i))); | ||
} | ||
} | ||
|
||
public static List<Param> rfc6265Cookies() | ||
{ | ||
return Arrays.asList( | ||
new Param("A=1; B=2; C=3", "A=1", "B=2", "C=3"), | ||
new Param("A=\"1\"; B=2; C=3", "A=1", "B=2", "C=3"), | ||
new Param("A=\"1\"; B=\"2\"; C=\"3\"", "A=1", "B=2", "C=3"), | ||
new Param("A=1; B=2; C=\"3", "A=1", "B=2"), | ||
new Param("A=1 ; B=2; C=3", "A=1", "B=2", "C=3"), | ||
new Param("A= 1; B=2; C=3", "A=1", "B=2", "C=3"), | ||
new Param("A=\"1; B=2\"; C=3", "C=3"), | ||
new Param("A=\"1; B=2; C=3"), | ||
new Param("A=\"1 B=2\"; C=3", "A=1 B=2", "C=3"), // Why should A be rejected? Shouldn't it be A=<1 B=2>? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment either is outdated and should go away, or space characters should be rejected and there's a bug left. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We want to keep us much legacy behaviour as possible for these lenient cases, so I don't want to change the code. I'll remove the comment. |
||
new Param("A=\"\"1; B=2; C=3", "B=2", "C=3"), | ||
new Param("A=\"\" ; B=2; C=3", "A=", "B=2", "C=3"), | ||
new Param("A=\"\"; B=2; C=3", "A=", "B=2", "C=3"), | ||
new Param("A=1\"\"; B=2; C=3", "B=2", "C=3"), | ||
new Param("A=1\"; B=2; C=3", "B=2", "C=3"), | ||
new Param("A=1\"1; B=2; C=3", "B=2", "C=3"), | ||
/* TODO Use Legacy mode for these | ||
new Param("A=\" 1\"; B=2; C=3", "A=1", "B=2", "C=3"), // Why should the whitespaces be trimmed? They were not in the prev impl. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These assertions should be adapted. In these four cases, |
||
new Param("A=\"1 \"; B=2; C=3", "A=1", "B=2", "C=3"), // ditto | ||
new Param("A=\" 1 \"; B=2; C=3", "A=1", "B=2", "C=3"), // ditto | ||
new Param("A=\" 1 1 \"; B=2; C=3", "A=1 1", "B=2", "C=3"), // ditto | ||
*/ | ||
new Param("A=1,; B=2; C=3", "B=2", "C=3"), | ||
new Param("A=\"1,\"; B=2; C=3", "B=2", "C=3"), | ||
new Param("A=\\1; B=2; C=3", "B=2", "C=3"), | ||
new Param("A=\"\\1\"; B=2; C=3", "B=2", "C=3"), | ||
new Param("A=1\u0007; B=2; C=3", "B=2", "C=3"), | ||
new Param("A=\"1\u0007\"; B=2; C=3", "B=2", "C=3"), | ||
new Param("€"), | ||
new Param("@={}"), | ||
new Param("$X=Y; N=V", "N=V"), | ||
new Param("N=V; $X=Y", "N=V") | ||
); | ||
} | ||
|
||
private static String dump(Cookie[] cookies) | ||
{ | ||
StringBuilder sb = new StringBuilder(); | ||
for (Cookie cookie : cookies) | ||
{ | ||
sb.append("<").append(cookie.getName()).append(">=<").append(cookie.getValue()).append("> | "); | ||
} | ||
if (sb.length() > 0) | ||
sb.delete(sb.length() - 2, sb.length() - 1); | ||
return sb.toString(); | ||
} | ||
|
||
private static class Param | ||
{ | ||
private final String input; | ||
private final List<String> expected; | ||
|
||
public Param(String input, String... expected) | ||
{ | ||
this.input = input; | ||
this.expected = Arrays.asList(expected); | ||
} | ||
|
||
@Override | ||
public String toString() | ||
{ | ||
return input + " -> " + expected.toString(); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd remove the comment because it's not what the code does (the code does not check for
,
"
and\
.Alternatively, can this block be merged with the block below which is identical and has a clarifying comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove the comment.
It is not identical to the code below. This is the original code and the code below is updated by @lorban.