Author: markt
Date: Sat Mar 16 20:25:35 2013
New Revision: 1457303
URL: http://svn.apache.org/r1457303
Log: (empty)
Modified:
tomcat/tc7.0.x/trunk/ (props changed)
tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java
tomcat/tc7.0.x/trunk/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java
tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
Merged /tomcat/trunk:r1457299,1457301
Modified:
tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java?rev=1457303&r1=1457302&r2=1457303&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java
Sat Mar 16 20:25:35 2013
@@ -48,8 +48,7 @@ public class HttpParser {
private static final Integer FIELD_TYPE_QUOTED_STRING = Integer.valueOf(1);
private static final Integer FIELD_TYPE_TOKEN_OR_QUOTED_STRING =
Integer.valueOf(2);
private static final Integer FIELD_TYPE_LHEX = Integer.valueOf(3);
- private static final Integer FIELD_TYPE_QUOTED_LHEX = Integer.valueOf(4);
- private static final Integer FIELD_TYPE_QUOTED_TOKEN = Integer.valueOf(5);
+ private static final Integer FIELD_TYPE_QUOTED_TOKEN = Integer.valueOf(4);
private static final Map<String,Integer> fieldTypes =
new HashMap<String,Integer>();
@@ -59,16 +58,23 @@ public class HttpParser {
private static final boolean isHex[] = new boolean[128];
static {
- // Digest field types
+ // Digest field types.
+ // Note: These are more relaxed than RFC2617. This adheres to the
+ // recommendation of RFC2616 that servers are tolerant of buggy
+ // clients when they can be so without ambiguity.
fieldTypes.put("username", FIELD_TYPE_QUOTED_STRING);
fieldTypes.put("realm", FIELD_TYPE_QUOTED_STRING);
fieldTypes.put("nonce", FIELD_TYPE_QUOTED_STRING);
fieldTypes.put("digest-uri", FIELD_TYPE_QUOTED_STRING);
- fieldTypes.put("response", FIELD_TYPE_QUOTED_LHEX);
+ // RFC2617 says response is <">32LHEX<">. 32LHEX will also be accepted
+ fieldTypes.put("response", FIELD_TYPE_LHEX);
+ // RFC2617 says algorithm is token. <">token<"> will also be accepted
fieldTypes.put("algorithm", FIELD_TYPE_QUOTED_TOKEN);
fieldTypes.put("cnonce", FIELD_TYPE_QUOTED_STRING);
fieldTypes.put("opaque", FIELD_TYPE_QUOTED_STRING);
+ // RFC2617 says qop is token. <">token<"> will also be accepted
fieldTypes.put("qop", FIELD_TYPE_QUOTED_TOKEN);
+ // RFC2617 says nc is 8LHEX. <">8LHEX<"> will also be accepted
fieldTypes.put("nc", FIELD_TYPE_LHEX);
// Setup the flag arrays
@@ -145,14 +151,10 @@ public class HttpParser {
value = readTokenOrQuotedString(input, false);
break;
case 3:
- // FIELD_TYPE_LHEX
+ // FIELD_TYPE_QUOTED_LHEX
value = readLhex(input);
break;
case 4:
- // FIELD_TYPE_QUOTED_LHEX
- value = readQuotedLhex(input);
- break;
- case 5:
// FIELD_TYPE_QUOTED_TOKEN
value = readQuotedToken(input);
break;
@@ -265,6 +267,8 @@ public class HttpParser {
int len = constant.length();
int c = input.read();
+
+ // Skip lws
while (c == 32 || c == 9) {
c = input.read();
}
@@ -361,9 +365,10 @@ public class HttpParser {
private static String readTokenOrQuotedString(StringReader input,
boolean returnQuoted) throws IOException {
- input.mark(1);
+
int c = input.read();
- input.reset();
+ // Skip back so first character is available to be read again
+ input.skip(-1);
if (c == '"') {
return readQuotedString(input, returnQuoted);
@@ -373,9 +378,12 @@ public class HttpParser {
}
/**
+ * Token can be read unambiguously with or without surrounding quotes so
+ * this parsing method for token permits optional surrounding double
quotes.
* This is not defined in any RFC. It is a special case to handle data from
- * buggy clients (known buggy clients include Microsoft IE 8 & 9, Apple
- * Safari for OSX and iOS) that add quotes to values that should be tokens.
+ * buggy clients (known buggy clients for DIGEST auth include Microsoft IE
8
+ * & 9, Apple Safari for OSX and iOS) that add quotes to values that should
+ * be tokens.
*
* @return the token if one was found, null if data other than a token or
* quoted token was found or null if the end of data was reached
@@ -396,7 +404,7 @@ public class HttpParser {
if (c == '"') {
quoted = true;
- } else if (c == -1) {
+ } else if (c == -1 || !isToken(c)) {
return null;
} else {
result.append((char) c);
@@ -425,14 +433,19 @@ public class HttpParser {
}
/**
- * Parses lower case hex but permits upper case hex to be used (converting
- * it to lower case before returning).
+ * LHEX can be read unambiguously with or without surrounding quotes so
this
+ * parsing method for LHEX permits optional surrounding double quotes. Some
+ * buggy clients (libwww-perl for DIGEST auth) are known to send quoted
LHEX
+ * when the specification requires just LHEX.
*
- * @return the lower case hex if present or <code>null</code> if data other
- * than lower case hex was found
+ * @return the sequence of LHEX (minus any surrounding quotes) if any was
+ * found, or <code>null</code> if data other LHEX was found
*/
- private static String readLhex(StringReader input) throws IOException {
+ private static String readLhex(StringReader input)
+ throws IOException {
+
StringBuilder result = new StringBuilder();
+ boolean quoted = false;
int c = input.read();
@@ -441,32 +454,34 @@ public class HttpParser {
c = input.read();
}
+ if (c == '"') {
+ quoted = true;
+ } else if (c == -1 || !isHex(c)) {
+ return null;
+ } else {
+ result.append((char) c);
+ }
+ c = input.read();
+
while (c != -1 && isHex(c)) {
result.append((char) c);
c = input.read();
}
- // Skip back so non-hex character is available for next read
- input.skip(-1);
- if (result.length() == 0) {
- return null;
+ if (quoted) {
+ if (c != '"') {
+ return null;
+ }
} else {
- return result.toString().toLowerCase(Locale.US);
+ // Skip back so non-token character is available for next read
+ input.skip(-1);
}
- }
- private static String readQuotedLhex(StringReader input)
- throws IOException {
-
- if (skipConstant(input, "\"") != SkipConstantResult.FOUND) {
- return null;
- }
- String result = readLhex(input);
- if (skipConstant(input, "\"") == SkipConstantResult.NOT_FOUND) {
+ if (c != -1 && result.length() == 0) {
return null;
+ } else {
+ return result.toString().toLowerCase(Locale.US);
}
-
- return result;
}
private static enum SkipConstantResult {
Modified:
tomcat/tc7.0.x/trunk/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java?rev=1457303&r1=1457302&r2=1457303&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java
(original)
+++
tomcat/tc7.0.x/trunk/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java
Sat Mar 16 20:25:35 2013
@@ -126,6 +126,28 @@ public class TestAuthorizationDigest {
}
@Test
+ public void testQuotedLhex() throws Exception {
+ String header = "Digest nc=\"00000001\"";
+
+ StringReader input = new StringReader(header);
+
+ Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+
+ Assert.assertEquals("00000001", result.get("nc"));
+ }
+
+ @Test
+ public void testUnclosedQuotedLhex() throws Exception {
+ String header = "Digest nc=\"00000001";
+
+ StringReader input = new StringReader(header);
+
+ Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+
+ Assert.assertNull(result);
+ }
+
+ @Test
public void testUnclosedQuotedString1() throws Exception {
String header = "Digest username=\"test";
@@ -226,6 +248,16 @@ public class TestAuthorizationDigest {
}
@Test
+ public void testWrongCharacterInToken2() throws Exception {
+ String header = "Digest qop=\u044f";
+
+ StringReader input = new StringReader(header);
+
+ Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+ Assert.assertNull(result);
+ }
+
+ @Test
public void testWrongCharacterInQuotedToken() throws Exception {
String header = "Digest qop=\"\u044f\"";
@@ -244,4 +276,14 @@ public class TestAuthorizationDigest {
Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
Assert.assertNull(result);
}
+
+ @Test
+ public void testWrongCharacterInQuotedHex() throws Exception {
+ String header = "Digest nc=\"\u044f\"";
+
+ StringReader input = new StringReader(header);
+
+ Map<String,String> result = HttpParser.parseAuthorizationDigest(input);
+ Assert.assertNull(result);
+ }
}
Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1457303&r1=1457302&r2=1457303&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Sat Mar 16 20:25:35 2013
@@ -87,6 +87,11 @@
are closed when parsing web application deployment descriptors.
(violetagg)
</fix>
+ <fix>
+ <bug>54707</bug>: Further relax the parsing of DIGEST authentication
+ headers to allow for buggy clients that quote values that RFC2617
states
+ should not be quoted. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Coyote">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]