Author: markt Date: Fri Jan 4 20:55:34 2013 New Revision: 1429123 URL: http://svn.apache.org/viewvc?rev=1429123&view=rev Log: Make HTTP DIGEST authentication header parsing tolerant of known buggy clients.
Modified: tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java Modified: tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java?rev=1429123&r1=1429122&r2=1429123&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java Fri Jan 4 20:55:34 2013 @@ -48,6 +48,7 @@ public class HttpParser { 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 Map<String,Integer> fieldTypes = new HashMap<>(); @@ -64,7 +65,7 @@ public class HttpParser { fieldTypes.put("algorithm", FIELD_TYPE_TOKEN); fieldTypes.put("cnonce", FIELD_TYPE_QUOTED_STRING); fieldTypes.put("opaque", FIELD_TYPE_QUOTED_STRING); - fieldTypes.put("qop", FIELD_TYPE_TOKEN); + fieldTypes.put("qop", FIELD_TYPE_QUOTED_TOKEN); fieldTypes.put("nc", FIELD_TYPE_LHEX); // Setup the flag arrays @@ -148,6 +149,10 @@ public class HttpParser { // FIELD_TYPE_QUOTED_LHEX value = readQuotedLhex(input); break; + case 5: + // FIELD_TYPE_QUOTED_TOKEN + value = readQuotedToken(input); + break; default: // Error throw new IllegalArgumentException( @@ -346,6 +351,58 @@ public class HttpParser { } /** + * 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. + * + * @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 + * before a quoted token was terminated + */ + private static String readQuotedToken(StringReader input) + throws IOException { + + StringBuilder result = new StringBuilder(); + boolean quoted = false; + + int c = input.read(); + + // Skip lws + while (c == 32 || c == 9) { + c = input.read(); + } + + if (c == '"') { + quoted = true; + } else if (c == -1) { + return null; + } else { + result.append((char) c); + } + c = input.read(); + + while (c != -1 && isToken[c]) { + result.append((char) c); + c = input.read(); + } + + if (quoted) { + if (c != '"') { + return null; + } + } else { + // Skip back so non-token character is available for next read + input.skip(-1); + } + + if (c != -1 && result.length() == 0) { + return null; + } else { + return result.toString(); + } + } + + /** * Parses lower case hex but permits upper case hex to be used (converting * it to lower case before returning). * Modified: tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java?rev=1429123&r1=1429122&r2=1429123&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java (original) +++ tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestAuthorizationDigest.java Fri Jan 4 20:55:34 2013 @@ -155,4 +155,53 @@ public class TestAuthorizationDigest { Assert.assertNull(result); } + @Test + public void testTokenQop() throws Exception { + String header = "Digest qop=auth"; + + StringReader input = new StringReader(header); + + Map<String,String> result = HttpParser.parseAuthorizationDigest(input); + Assert.assertEquals("auth", result.get("qop")); + } + + @Test + public void testQuotedTokenQop() throws Exception { + String header = "Digest qop=\"auth\""; + + StringReader input = new StringReader(header); + + Map<String,String> result = HttpParser.parseAuthorizationDigest(input); + Assert.assertEquals("auth", result.get("qop")); + } + + @Test + public void testNonTokenQop() throws Exception { + String header = "Digest qop=au{th"; + + StringReader input = new StringReader(header); + + Map<String,String> result = HttpParser.parseAuthorizationDigest(input); + Assert.assertNull(result); + } + + @Test + public void testQuotedNonTokenQop() throws Exception { + String header = "Digest qop=\"au{th\""; + + StringReader input = new StringReader(header); + + Map<String,String> result = HttpParser.parseAuthorizationDigest(input); + Assert.assertNull(result); + } + + @Test + public void testUnclosedQuotedTokenQop() throws Exception { + String header = "Digest qop=\"auth"; + + StringReader input = new StringReader(header); + + Map<String,String> result = HttpParser.parseAuthorizationDigest(input); + Assert.assertNull(result); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org