xml-rpc-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Adam Megacz <a...@xwt.org>
Subject patch to correct improper handling of HTTP Basic authentication
Date Tue, 13 Aug 2002 23:56:47 GMT

XmlRpc.java does not provide adequate support to implement HTTP Basic
Authentication. WebServer.java implements it incorrectly. This patch
fixes both problems.

If an HTTP request requires authentication, the server MUST return a
401 Unauthorized:

  http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2

Without the 401, the client doesn't know which type of authentication
to use. It can't assume Basic, because that would mean sending
passwords in the clear even to Digest-capable servers (thereby
rendering digest auth useless). It can't assume Digest, because the
401 contains the nonce (which is required to perform digest
authentication).

Patch appended. This also fixes a bug whereby WebServer would return
an HTTP/1.1 response without a Content-Length or chunked encoding,
which is not allowed.

  - a

------------------------------------------------------------------------------

Index: src/java/org/apache/xmlrpc/WebServer.java
===================================================================
RCS file: /home/cvspublic/xml-rpc/src/java/org/apache/xmlrpc/WebServer.java,v
retrieving revision 1.13
diff -u -r1.13 WebServer.java
--- src/java/org/apache/xmlrpc/WebServer.java	13 Aug 2002 22:27:16 -0000	1.13
+++ src/java/org/apache/xmlrpc/WebServer.java	13 Aug 2002 23:53:40 -0000
@@ -94,6 +94,7 @@
     protected static final byte[] conclose = "Connection: close\r\n".getBytes();
     protected static final byte[] ok = " 200 OK\r\n".getBytes();
     protected static final byte[] server = "Server: Apache XML-RPC 1.0\r\n".getBytes();
+    protected static final byte[] www_authenticate = "WWW-Authenticate: Basic realm=XMLRPC\r\n".getBytes();
 
     private static final String HTTP_11 = "HTTP/1.1";
     private static final String STAR = "*";
@@ -584,29 +585,40 @@
                     {
                         ServerInputStream sin = new ServerInputStream(input,
                                 contentLength);
-                        byte result[] = xmlrpc.execute(sin, user, password);
-                        output.write(httpversion.getBytes());
-                        output.write(ok);
-                        output.write(server);
-                        if (keepalive)
-                        {
-                            output.write(conkeep);
-                        }
-                        else
-                        {
-                            output.write (conclose);
+                        try {
+                            byte result[] = xmlrpc.execute(sin, user, password);
+                            output.write(httpversion.getBytes());
+                            output.write(ok);
+                            output.write(server);
+                            if (keepalive)
+                                {
+                                    output.write(conkeep);
+                                }
+                            else
+                                {
+                                    output.write (conclose);
+                                }
+                            output.write(ctype);
+                            output.write(clength);
+                            output.write(Integer.toString(result.length)
+                                         .getBytes());
+                            output.write(doubleNewline);
+                            output.write(result);
+                        } catch (XmlRpcServer.AuthenticationRequiredException are) {
+                            output.write("HTTP/1.0".getBytes());
+                            output.write(" 401 Unauthorized\r\n".getBytes());
+                            output.write(server);
+                            output.write(www_authenticate);
+                            output.write("\r\n".getBytes());
+                            output.write(("Method " + method
+                                          + " requires a username and password").getBytes());
+                            keepalive = false;
                         }
-                        output.write(ctype);
-                        output.write(clength);
-                        output.write(Integer.toString(result.length)
-                                .getBytes());
-                        output.write(doubleNewline);
-                        output.write(result);
                         output.flush();
                     }
                     else
                     {
-                        output.write(httpversion.getBytes());
+                        output.write("HTTP/1.0".getBytes());
                         output.write(" 400 Bad Request\r\n".getBytes());
                         output.write(server);
                         output.write("\r\n".getBytes());
Index: src/java/org/apache/xmlrpc/XmlRpcServer.java
===================================================================
RCS file: /home/cvspublic/xml-rpc/src/java/org/apache/xmlrpc/XmlRpcServer.java,v
retrieving revision 1.28
diff -u -r1.28 XmlRpcServer.java
--- src/java/org/apache/xmlrpc/XmlRpcServer.java	9 Aug 2002 09:14:24 -0000	1.28
+++ src/java/org/apache/xmlrpc/XmlRpcServer.java	13 Aug 2002 23:53:40 -0000
@@ -136,6 +136,7 @@
      * since this is all packed into the response.
      */
     public byte[] execute(InputStream is)
+        throws AuthenticationRequiredException
     {
         return execute(is, null, null);
     }
@@ -146,6 +147,7 @@
      * use the credentials to authenticate the user.
      */
     public byte[] execute(InputStream is, String user, String password)
+        throws AuthenticationRequiredException
     {
         Worker worker = getWorker();
         byte[] retval = worker.execute(is, user, password);
@@ -202,6 +204,7 @@
          * Given a request for the server, generates a response.
          */
         public byte[] execute(InputStream is, String user, String password)
+            throws AuthenticationRequiredException
         {
             try
             {
@@ -224,7 +227,7 @@
          * @return
          */
         private byte[] executeInternal(InputStream is, String user,
-                String password)
+                String password) throws AuthenticationRequiredException
         {
             byte[] result;
             long now = 0;
@@ -284,6 +287,7 @@
                 Object outParam;
                 if (handler instanceof AuthenticatedXmlRpcHandler)
                 {
+                    if (user == null) throw new XmlRpcServer.AuthenticationRequiredException();
                     outParam =((AuthenticatedXmlRpcHandler) handler)
                             .execute(methodName, inParams, user, password);
                 }
@@ -303,6 +307,9 @@
             }
             catch(Exception x)
             {
+                if (x instanceof XmlRpcServer.AuthenticationRequiredException)
+                    throw (XmlRpcServer.AuthenticationRequiredException)x;
+
                 if (XmlRpc.debug)
                 {
                     x.printStackTrace();
@@ -427,6 +434,11 @@
             writer.endElement("methodResponse");
         }
     } // end of inner class Worker
+
+    public static class AuthenticationRequiredException extends IOException {
+        AuthenticationRequiredException() { }
+    }
+
 } // XmlRpcServer
 
 /**
@@ -555,4 +567,6 @@
         }
         return returnValue;
     }
+
 }
+

Mime
View raw message