Author: markt
Date: Fri Jan  4 21:01:00 2013
New Revision: 1429124

URL: http://svn.apache.org/viewvc?rev=1429124&view=rev
Log:
Make HTTP DIGEST authentication header parsing tolerant of known buggy clients.

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:r1429123

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=1429124&r1=1429123&r2=1429124&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 
Fri Jan  4 21:01:00 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<String,Integer>();
@@ -65,7 +66,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
@@ -149,6 +150,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(
@@ -348,6 +353,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/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=1429124&r1=1429123&r2=1429124&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
 Fri Jan  4 21:01:00 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);
+    }
 }

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=1429124&r1=1429123&r2=1429124&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Fri Jan  4 21:01:00 2013
@@ -74,6 +74,10 @@
         Allow web applications to be stopped cleanly even if filters shown
         exceptions when their destroy() method is called. (markt)
       </fix>
+      <add>
+        Make HTTP Digest authentication header parsing tolerant of invalid
+        headers sent by known buggy clients. (markt)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Jasper">



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to