Return-Path: Delivered-To: apmail-xml-rpc-dev-archive@xml.apache.org Received: (qmail 26968 invoked by uid 500); 15 Aug 2002 23:35:50 -0000 Mailing-List: contact rpc-dev-help@xml.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: list-post: Reply-To: rpc-dev@xml.apache.org Delivered-To: mailing list rpc-dev@xml.apache.org Received: (qmail 26959 invoked from network); 15 Aug 2002 23:35:49 -0000 Received: from customer80.globaltap.com (HELO alonzo.megacz.com) (206.104.238.80) by daedalus.apache.org with SMTP; 15 Aug 2002 23:35:49 -0000 Received: from megacz by alonzo.megacz.com with local (Exim 3.12 #1 (Debian)) id 17fUA8-00073O-00 for ; Thu, 15 Aug 2002 16:36:20 -0700 To: rpc-dev@xml.apache.org Subject: Re: patch to correct improper handling of HTTP Basic authentication References: <86bs86gvnk.fsf@megacz.com> From: Adam Megacz X-Home-Page: http://www.megacz.com/adam Organization: Myself Date: 15 Aug 2002 16:36:20 -0700 In-Reply-To: Adam Megacz's message of "13 Aug 2002 16:56:47 -0700" Message-ID: <8665yb4ruz.fsf@megacz.com> Lines: 193 User-Agent: Gnus/5.0803 (Gnus v5.8.3) Emacs/20.7 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N Status: O X-Status: X-Keywords: Uh, is this going to get committed? The Zope/Python XML-RPC people are fixing a similar defect in their XML-RPC implementation; it would be good if Apache followed suit. http://lists.zope.org/pipermail/zope-dev/2002-August/017126.html http://lists.zope.org/pipermail/zope-dev/2002-August/017143.html - a Adam Megacz writes: > 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; > } > + > } > + > -- Sick of HTML user interfaces? www.xwt.org