[Zope-dev] XMLRPC and Basic Auth problems
Tim Hoffman
timhoffman@cams.wa.gov.au
15 Aug 2002 13:35:01 +0800
Hi Casey
Thanks for the note. I had done the snoops myself yesterday and came to
the same conclusion. Do you want me to raise the collector issue ?
Rgds
Tim
On Thu, 2002-08-15 at 12:36, Casey Duncan wrote:
> This tcp dump from an xml-rpc request to the root manage method shows that you
> are correct:
>
> [00:00.000 - client 127.0.0.1:3130 forwarded to :8080]
> [00:00.002 - server connected]
> POST /RPC2 HTTP/1.0
> Host: localhost:9080
> User-Agent: xmlrpclib.py/1.0.0 (by www.pythonware.com)
> Content-Type: text/xml
> Content-Length: 100
>
> <?xml version='1.0'?>
> <methodCall>
> <methodName>manage</methodName>
> <params>
> </params>
> </methodCall>
> HTTP/1.0 200 OK
> Server: Zope/(unreleased version, python 2.1.3, freebsd4) ZServer/1.1b1
> Date: Thu, 15 Aug 2002 04:19:25 GMT
> WWW-Authenticate: basic realm="Zope"
> Content-Type: text/xml
> Etag:
> Connection: close
> Content-Length: 731
>
> <?xml version='1.0'?>
> <methodResponse>
> <fault>
> <value><struct>
> <member>
> <name>faultCode</name>
> <value><int>-2</int></value>
> </member>
> <member>
> <name>faultString</name>
> <value><string>Unexpected Zope error value:
> <html><head><title>Zope</title></head><body
> bgcolor="#FFFFFF">
>
> <strong>You are not authorized to access this
> resource.</strong><p>
> No Authorization header found.
>
> <p><a href="http://www.zope.org/Credits" target="_top"><img
> src="http://localhost:9080/p_/ZopeButton" width="115" height="50" border="0"
> alt="Powered by Zope" /></a></p></body></html>
> </string></value>
> </member>
> </struct></value>
> </fault>
> </methodResponse>
> [00:00.220 - server closed]
>
> The server returns a 200 response status. Strangly, the response headers do
> include WWW-Authenticate. So, the xml-rpc code must be changing the response
> status.
>
> Here is a transcript of a normal http request to the same method:
>
> [00:00.000 - client 127.0.0.1:3133 forwarded to :8080]
> [00:00.002 - server connected]
> GET /manage HTTP/1.0
> Host: localhost:9080
> User-agent: Python-urllib/1.15
>
> HTTP/1.0 401 Unauthorized
> Server: Zope/(unreleased version, python 2.1.3, freebsd4) ZServer/1.1b1
> Date: Thu, 15 Aug 2002 04:24:48 GMT
> WWW-Authenticate: basic realm="Zope"
> Bobo-Exception-File:
> /usr/home/casey/Sandbox/Zope/lib/python/ZPublisher/HTTPResponse.py
> Bobo-Exception-Type: Unauthorized
> Content-Type: text/html
> Connection: close
> Bobo-Exception-Value: bobo exception
> Etag:
> Content-Length: 350
> Bobo-Exception-Line: 647
>
> <html><head><title>Zope</title></head><body bgcolor="#FFFFFF">
>
> <strong>You are not authorized to access this resource.</strong><p>
> No Authorization header found.
>
> <p><a href="http://www.zope.org/Credits" target="_top"><img
> src="http://localhost:9080/p_/ZopeButton" width="115" height="50" border="0"
> alt="Powered by Zope" /></a></p></body></html>
> [00:00.124 - server closed]
>
> Now the 401 response status is returned.
>
> So, your assertion that Zope does not return a 401 on an unauthorized error
> over xml-rpc is correct. Whether this behavior is wrong, I am not sure. I
> would think that if the xml-rpc spec says nothing specific about this, then
> we should defer to the general http spec, in which case Zope would not be
> compliant.
>
> -Casey
>
> On Wednesday 14 August 2002 11:59 pm, Tim Hoffman wrote:
> > Hi Casey
> >
> > I am using Basic Auth with xmlrpc lib now, and yes it does work with
> > Python2.1 but that's not my point.
> >
> > The XML-RPC spec doesn't talk about authentication, and so yes what you
> > say is correct. However Adams position is that the spec says it is
> > implemented on top of http and the http spec says that an error
> > 401 needs to be sent if authentication is invalid etc.. So Adam makes
> > the claim that Zope is not compliant with the http protocol when XML-RPC
> > is used on top of it.
> >
> > And I am inclined to agree.
> >
> > Regards
> >
> > Tim
> >
> > On Thu, 2002-08-15 at 11:47, Casey Duncan wrote:
> > > Python's xmlrpclib doesn't support any authentication. It is easily
> subclassed
> > > to include it. I have successfully used it to connect with Zope and I do
> not
> > > have any reason to believe that Zope is broken with regard to
> authentication.
> > >
> > > However I do think that Python's xmlrpclib should include basic auth.
> Perhaps
> > > I will make an effort to put this in, since it is so easy.
> > >
> > > This how-to provides the code for extending xmlrpclib:
> > >
> > > http://www.zope.org/Members/Amos/XML-RPC
> > >
> > > It doesn't quite work for Python 2.1+, but I have attached a working
> version I
> > > use.
> > >
> > > hth,
> > >
> > > Casey
> > >
> > > On Wednesday 14 August 2002 10:51 pm, Tim Hoffman wrote:
> > > > I have had further from Adam Megacz <adam@megacz.com> the author of XWT
> > > > on this issue.
> > > >
> > > > I believe I should raise a collector issue on this, however do
> > > > people believe this is a correct assessment of the situation.
> > > >
> > > >
> > > > ======================================================================
> > > > Tim Hoffman <timhoffman@cams.wa.gov.au> writes:
> > > > > The xmlrpc spec doesn't say anything about authentication.
> > > > > ...
> > > > > I suppose this whole area is pretty vague.
> > > >
> > > > Actually, it references the HTTP spec, which is quite clear about
> > > > requiring a 401.
> > > >
> > > > http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2
> > > >
> > > > Without the 401, you don't know the authentication realm,
> > > > authentication type, or digest nonce -- three things you need to know
> > > > in order to authenticate (although the last one is only needed for
> > > > Digest auth, not Basic Auth).
> > > >
> > > > Unfortunately, it seems that a lot of XML-RPC libraries are broken in
> > > > this manner. I'm working with the Apache people right now on fixing
> > > > the Java libraries -- could you please work with the Python people to
> > > > get this fixed?
> > > >
> > > > I think this is a result of the fact that HTTP Auth isn't used very
> > > > often in XML-RPC, although it should be. I'm working on an RFC for
> > > > XML-RPC, and I will certainly include some wording which underscores
> > > > the importance of the 401 response.
> > > >
> > > > http://www.xwt.org/xmc/draft-megacz-xmc-05.txt
> > > >
> > > > - a
> > > >
> > > > --
> > > > Sick of HTML user interfaces?
> > > > www.xwt.org
> > > >
> =========================================================================
> > > >
> > > >
> > > >
> > > > On Thu, 2002-08-15 at 10:47, Tim Hoffman wrote:
> > > > > Hi
> > > > >
> > > > > I am working on a project that uses XWT (xwt.org) as a frontend to
> Zope.
> > > > >
> > > > > XWT uses XMLRPC to communicate with a backend (in this case Zope).
> > > > >
> > > > > XWT expects an Error 401 is authentication is required on an XMLRPC
> > > > > call, so that it can negotiate the correct auth method
> > > > >
> > > > > The author of XWT sent the following email to me
> > > > >
> > > > > >Tim, I've got a piece of the answer -- your server needs to return an
> > > > > >HTTP 401 (Unauthorized) if no username/password is provided. This
> > > > > >response includes the challenge that XWT needs in order to build an
> > > > > >authentication request (realm, digest nonce challenge, etc).
> > > > >
> > > > > However what Zope is doing is sending back a <fault> in the
> > > > > XMLRPC <methodResponse> packet.
> > > > >
> > > > > So it appears to me that Zope doesn't send a http response 401 for
> > > > > XMLRPC (over http), but will send a 401 back to the browser.
> > > > >
> > > > > XMLRPC doesn't say anything about authentication, so I suppose either
> > > > > method is acceptable. However because XMLRPC is implemented
> > > > > on top of http, I would have thought a http approach (ie error 401)
> > > > > would be used.
> > > > >
> > > > > It appears that this behaviour is fundamental to Zope and is not an
> > > > > artifact of cookie auth in CMF etc..
> > > > >
> > > > > Is this really correct behaviour ?
> > > > >
> > > > > Regards
> > > > >
> > > > > Tim Hoffman
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > > _______________________________________________
> > > > > Zope-Dev maillist - Zope-Dev@zope.org
> > > > > http://lists.zope.org/mailman/listinfo/zope-dev
> > > > > ** No cross posts or HTML encoding! **
> > > > > (Related lists -
> > > > > http://lists.zope.org/mailman/listinfo/zope-announce
> > > > > http://lists.zope.org/mailman/listinfo/zope )
> > > >
> > > >
> > > >
> > > > _______________________________________________
> > > > Zope-Dev maillist - Zope-Dev@zope.org
> > > > http://lists.zope.org/mailman/listinfo/zope-dev
> > > > ** No cross posts or HTML encoding! **
> > > > (Related lists -
> > > > http://lists.zope.org/mailman/listinfo/zope-announce
> > > > http://lists.zope.org/mailman/listinfo/zope )
> > > >
> > >
> > > ----
> > >
> >
> > > import string, xmlrpclib, httplib
> > > from base64 import encodestring
> > >
> > > class BasicAuthTransport(xmlrpclib.Transport):
> > > verbose = 0
> > >
> > > def __init__(self, username=None, password=None):
> > > self.username=username
> > > self.password=password
> > >
> > > def request(self, host, handler, request_body, verbose=0):
> > > # issue XML-RPC request
> > >
> > > h = httplib.HTTP(host)
> > > h.putrequest("POST", handler)
> > >
> > > # required by HTTP/1.1
> > > h.putheader("Host", host)
> > >
> > > # required by XML-RPC
> > > h.putheader("User-Agent", self.user_agent)
> > > h.putheader("Content-Type", "text/xml")
> > > h.putheader("Content-Length", str(len(request_body)))
> > >
> > > # basic auth
> > > if self.username is not None and self.password is not None:
> > > h.putheader("AUTHORIZATION", "Basic %s" % string.replace(
> > > encodestring("%s:%s" % (self.username,
> self.password)),
> > > "\012", ""))
> > > h.endheaders()
> > >
> > > if request_body:
> > > h.send(request_body)
> > >
> > > errcode, errmsg, headers = h.getreply()
> > >
> > > if errcode != 200:
> > > raise xmlrpclib.ProtocolError(
> > > host + handler,
> > > errcode, errmsg,
> > > headers
> > > )
> > >
> > > return self.parse_response(h.getfile())
> > >
> > >
> >
> >
> >