Author: markt
Date: Wed Jan 23 13:57:50 2019
New Revision: 1851916

URL: http://svn.apache.org/viewvc?rev=1851916&view=rev
Log:
Make the removal of leading and trailing whitespace from credentials passed to 
BASIC authentication configurable via a new attribute, trimCredentials on the 
BasicAuthenticator.

Modified:
    tomcat/trunk/java/org/apache/catalina/authenticator/BasicAuthenticator.java
    tomcat/trunk/java/org/apache/catalina/authenticator/mbeans-descriptors.xml
    tomcat/trunk/test/org/apache/catalina/authenticator/TestBasicAuthParser.java
    tomcat/trunk/webapps/docs/changelog.xml
    tomcat/trunk/webapps/docs/config/valve.xml

Modified: 
tomcat/trunk/java/org/apache/catalina/authenticator/BasicAuthenticator.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/BasicAuthenticator.java?rev=1851916&r1=1851915&r2=1851916&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/authenticator/BasicAuthenticator.java 
(original)
+++ tomcat/trunk/java/org/apache/catalina/authenticator/BasicAuthenticator.java 
Wed Jan 23 13:57:50 2019
@@ -49,6 +49,7 @@ public class BasicAuthenticator extends
 
     private Charset charset = StandardCharsets.ISO_8859_1;
     private String charsetString = null;
+    private boolean trimCredentials = true;
 
 
     public String getCharset() {
@@ -69,6 +70,17 @@ public class BasicAuthenticator extends
     }
 
 
+
+    public boolean getTrimCredentials() {
+        return trimCredentials;
+    }
+
+
+    public void setTrimCredentials(boolean trimCredentials) {
+        this.trimCredentials = trimCredentials;
+    }
+
+
     @Override
     protected boolean doAuthenticate(Request request, HttpServletResponse 
response)
             throws IOException {
@@ -87,7 +99,7 @@ public class BasicAuthenticator extends
             ByteChunk authorizationBC = authorization.getByteChunk();
             BasicCredentials credentials = null;
             try {
-                credentials = new BasicCredentials(authorizationBC, charset);
+                credentials = new BasicCredentials(authorizationBC, charset, 
trimCredentials);
                 String username = credentials.getUsername();
                 String password = credentials.getPassword();
 
@@ -138,6 +150,7 @@ public class BasicAuthenticator extends
         private static final String METHOD = "basic ";
 
         private final Charset charset;
+        private final boolean trimCredentials;
         private final ByteChunk authorization;
         private final int initialOffset;
         private int base64blobOffset;
@@ -145,6 +158,7 @@ public class BasicAuthenticator extends
 
         private String username = null;
         private String password = null;
+
         /**
          * Parse the HTTP Authorization header for BASIC authentication
          * as per RFC 2617 section 2, and the Base64 encoded credentials
@@ -156,11 +170,35 @@ public class BasicAuthenticator extends
          *
          * @throws IllegalArgumentException If the header does not conform
          *                                  to RFC 2617
+         * @deprecated Unused. Will be removed in Tomcat 10. Use {@link
+         *             BasicCredentials#BasicCredentials(ByteChunk, Charset,
+         *             boolean)}
          */
+        @Deprecated
         public BasicCredentials(ByteChunk input, Charset charset) throws 
IllegalArgumentException {
+            this(input, charset, true);
+        }
+
+        /**
+         * Parse the HTTP Authorization header for BASIC authentication
+         * as per RFC 2617 section 2, and the Base64 encoded credentials
+         * as per RFC 2045 section 6.8.
+         *
+         * @param input           The header value to parse in-place
+         * @param charset         The character set to use to convert the bytes
+         *                        to a string
+         * @param trimCredentials Should leading and trailing whitespace be
+         *                        removed from the parsed credentials
+         *
+         * @throws IllegalArgumentException If the header does not conform
+         *                                  to RFC 2617
+         */
+        public BasicCredentials(ByteChunk input, Charset charset, boolean 
trimCredentials)
+                throws IllegalArgumentException {
             authorization = input;
             initialOffset = input.getOffset();
             this.charset = charset;
+            this.trimCredentials = trimCredentials;
 
             parseMethod();
             byte[] decoded = parseBase64();
@@ -245,12 +283,12 @@ public class BasicAuthenticator extends
                 username = new String(decoded, 0, colon, charset);
                 password = new String(decoded, colon + 1, decoded.length - 
colon - 1, charset);
                 // tolerate surplus white space around credentials
-                if (password.length() > 1) {
+                if (password.length() > 1 && trimCredentials) {
                     password = password.trim();
                 }
             }
             // tolerate surplus white space around credentials
-            if (username.length() > 1) {
+            if (username.length() > 1 && trimCredentials) {
                 username = username.trim();
             }
         }

Modified: 
tomcat/trunk/java/org/apache/catalina/authenticator/mbeans-descriptors.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/mbeans-descriptors.xml?rev=1851916&r1=1851915&r2=1851916&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/authenticator/mbeans-descriptors.xml 
(original)
+++ tomcat/trunk/java/org/apache/catalina/authenticator/mbeans-descriptors.xml 
Wed Jan 23 13:57:50 2019
@@ -64,6 +64,10 @@
                description="The name of the LifecycleState that this component 
is currently in"
                type="java.lang.String"
                writeable="false"/>
+
+    <attribute name="trimCredentials"
+               description="Controls whether leading and/or trailing 
whitespace is removed from the parsed credentials"
+               type="boolean"/>
   </mbean>
 
 

Modified: 
tomcat/trunk/test/org/apache/catalina/authenticator/TestBasicAuthParser.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/authenticator/TestBasicAuthParser.java?rev=1851916&r1=1851915&r2=1851916&view=diff
==============================================================================
--- 
tomcat/trunk/test/org/apache/catalina/authenticator/TestBasicAuthParser.java 
(original)
+++ 
tomcat/trunk/test/org/apache/catalina/authenticator/TestBasicAuthParser.java 
Wed Jan 23 13:57:50 2019
@@ -45,7 +45,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, USER_NAME, PASSWORD);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }
@@ -56,7 +56,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, USER_NAME, null);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertNull(credentials.getPassword());
     }
@@ -68,7 +68,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }
@@ -80,7 +80,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertNull(credentials.getPassword());
     }
@@ -93,7 +93,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD1, credentials.getPassword());
     }
@@ -119,7 +119,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_LONG, credentials.getUsername());
     }
 
@@ -141,7 +141,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_LONG, credentials.getUsername());
     }
 
@@ -157,7 +157,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(METHOD, USER_NAME, PASSWORD);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }
@@ -174,7 +174,7 @@ public class TestBasicAuthParser {
         BasicAuthenticator.BasicCredentials credentials = null;
         try {
             credentials = new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
             Assert.fail("IllegalArgumentException expected");
         }
         catch (Exception e) {
@@ -197,7 +197,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD + " ", USER_NAME, PASSWORD);
         final BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }
@@ -213,7 +213,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, USER_NAME, PWD_WRONG);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertNotSame(PASSWORD, credentials.getPassword());
     }
@@ -225,7 +225,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, EMPTY_USER_NAME, PASSWORD);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(EMPTY_USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }
@@ -237,7 +237,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, SHORT_USER_NAME, PASSWORD);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(SHORT_USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }
@@ -249,7 +249,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, USER_NAME, SHORT_PASSWORD);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(SHORT_PASSWORD, credentials.getPassword());
     }
@@ -261,7 +261,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, USER_NAME, PASSWORD_SPACE);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD_SPACE, credentials.getPassword());
     }
@@ -273,7 +273,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, USER_NAME, PASSWORD_COLON);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD_COLON, credentials.getPassword());
     }
@@ -285,7 +285,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, USER_NAME, PASSWORD_COLON);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD_COLON, credentials.getPassword());
     }
@@ -297,7 +297,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, USER_NAME, PASSWORD_COLON);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD_COLON, credentials.getPassword());
     }
@@ -315,7 +315,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, USER_NAME, PASSWORD, "    ");
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }
@@ -334,7 +334,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, " " + USER_NAME + " ", 
PASSWORD);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }
@@ -353,7 +353,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, USER_NAME, " " + PASSWORD + " 
");
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }
@@ -378,7 +378,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertNotSame(PASSWORD, credentials.getPassword());
         Assert.assertEquals(TRUNCATED_PWD, credentials.getPassword());
@@ -396,7 +396,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertNotSame(PASSWORD, credentials.getPassword());
     }
@@ -416,7 +416,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(POSSIBLY_DAMAGED_PWD, credentials.getPassword());
     }
@@ -433,7 +433,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }
@@ -452,7 +452,7 @@ public class TestBasicAuthParser {
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
-                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8);
+                    AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
         Assert.assertEquals(USER_NAME, credentials.getUsername());
         Assert.assertEquals(PASSWORD, credentials.getPassword());
     }

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1851916&r1=1851915&r2=1851916&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Wed Jan 23 13:57:50 2019
@@ -107,6 +107,12 @@
         <bug>63078</bug>: Ensure the utility thread pool is at least two, as 
the
         deployer uses a blocking pattern. (remm, markt)
       </fix>
+      <add>
+        Make the removal of leading and trailing whitespace from credentials
+        passed to BASIC authentication configurable via a new attribute,
+        <code>trimCredentials</code> on the <code>BasicAuthenticator</code>.
+        (markt)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Coyote">

Modified: tomcat/trunk/webapps/docs/config/valve.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/valve.xml?rev=1851916&r1=1851915&r2=1851916&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/valve.xml (original)
+++ tomcat/trunk/webapps/docs/config/valve.xml Wed Jan 23 13:57:50 2019
@@ -1271,6 +1271,12 @@
         specified, the platform default provider will be used.</p>
       </attribute>
 
+      <attribute name="trimCredentials" required="false">
+        <p>Controls whether leading and/or trailing whitespace is removed from
+        the parsed credentials. If not specified, the default value is
+        <code>true</code>.</p>
+      </attribute>
+
       <attribute name="jaspicCallbackHandlerClass" required="false">
         <p>Name of the Java class of the
         <code>javax.security.auth.callback.CallbackHandler</code> 
implementation



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

Reply via email to