[Zope-dev] XMLRPC and Basic Auth problems

Casey Duncan casey@zope.com
Thu, 15 Aug 2002 00:36:15 -0400


This tcp dump from an xml-rpc request to the root manage method shows tha=
t you=20
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=3D'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.1=
b1
    Date: Thu, 15 Aug 2002 04:19:25 GMT
    WWW-Authenticate: basic realm=3D"Zope"
    Content-Type: text/xml
    Etag:=20
    Connection: close
    Content-Length: 731

    <?xml version=3D'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:=20
&lt;html&gt;&lt;head&gt;&lt;title&gt;Zope&lt;/title&gt;&lt;/head&gt;&lt;b=
ody=20
bgcolor=3D"#FFFFFF"&gt;

     &lt;strong&gt;You are not authorized to access this=20
resource.&lt;/strong&gt;&lt;p&gt;
    No Authorization header found.

    &lt;p&gt;&lt;a href=3D"http://www.zope.org/Credits" target=3D"_top"&g=
t;&lt;img=20
src=3D"http://localhost:9080/p_/ZopeButton" width=3D"115" height=3D"50" b=
order=3D"0"=20
alt=3D"Powered by Zope" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&g=
t;
    </string></value>
    </member>
    </struct></value>
    </fault>
    </methodResponse>
    [00:00.220 - server closed]

The server returns a 200 response status. Strangly, the response headers =
do=20
include WWW-Authenticate. So, the xml-rpc code must be changing the respo=
nse=20
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.1=
b1
    Date: Thu, 15 Aug 2002 04:24:48 GMT
    WWW-Authenticate: basic realm=3D"Zope"
    Bobo-Exception-File:=20
/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:=20
    Content-Length: 350
    Bobo-Exception-Line: 647

    <html><head><title>Zope</title></head><body bgcolor=3D"#FFFFFF">

     <strong>You are not authorized to access this resource.</strong><p>
    No Authorization header found.

    <p><a href=3D"http://www.zope.org/Credits" target=3D"_top"><img=20
src=3D"http://localhost:9080/p_/ZopeButton" width=3D"115" height=3D"50" b=
order=3D"0"=20
alt=3D"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 err=
or=20
over xml-rpc is correct. Whether this behavior is wrong, I am not sure. I=
=20
would think that if the xml-rpc spec says nothing specific about this, th=
en=20
we should defer to the general http spec, in which case Zope would not be=
=20
compliant.

-Casey

On Wednesday 14 August 2002 11:59 pm, Tim Hoffman wrote:
> Hi Casey
>=20
> I am using Basic Auth with xmlrpc lib now, and yes it does work with
> Python2.1 but that's not my point.
>=20
> The XML-RPC spec doesn't talk about authentication,  and so yes what yo=
u
> 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=20
> 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-RP=
C
> is used on top of it.=20
>=20
> And I am inclined to agree.
>=20
> Regards
>=20
> Tim
>=20
> On Thu, 2002-08-15 at 11:47, Casey Duncan wrote:
> > Python's xmlrpclib doesn't support any authentication. It is easily=20
subclassed=20
> > to include it. I have successfully used it to connect with Zope and I=
 do=20
not=20
> > have any reason to believe that Zope is broken with regard to=20
authentication.=20
> >=20
> > However I do think that Python's xmlrpclib should include basic auth.=
=20
Perhaps=20
> > I will make an effort to put this in, since it is so easy.
> >=20
> > This how-to provides the code for extending xmlrpclib:
> >=20
> > http://www.zope.org/Members/Amos/XML-RPC
> >=20
> > It doesn't quite work for Python 2.1+, but I have attached a working=20
version I=20
> > use.
> >=20
> > hth,
> >=20
> > Casey=20
> >=20
> > 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.
> > >=20
> > > I believe I should raise a collector issue on this, however do=20
> > > people believe this is a correct assessment of the situation.
> > >=20
> > >=20
> > > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> > > 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.
> > >=20
> > > Actually, it references the HTTP spec, which is quite clear about
> > > requiring a 401.
> > >=20
> > >   http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2
> > >=20
> > > Without the 401, you don't know the authentication realm,
> > > authentication type, or digest nonce -- three things you need to kn=
ow
> > > in order to authenticate (although the last one is only needed for
> > > Digest auth, not Basic Auth).
> > >=20
> > > 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?
> > >=20
> > > 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 underscore=
s
> > > the importance of the 401 response.
> > >=20
> > >     http://www.xwt.org/xmc/draft-megacz-xmc-05.txt
> > >=20
> > >   - a
> > >=20
> > > --=20
> > > Sick of HTML user interfaces?
> > > www.xwt.org
> > >=20
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> > >=20
> > >=20
> > >=20
> > > On Thu, 2002-08-15 at 10:47, Tim Hoffman wrote:
> > > > Hi
> > > >=20
> > > > I am working on a project that uses XWT (xwt.org) as a frontend t=
o=20
Zope.
> > > >=20
> > > > XWT uses XMLRPC to communicate with a backend (in this case Zope)=
=2E
> > > >=20
> > > > XWT expects an Error 401 is authentication is required on an XMLR=
PC
> > > > call, so that it can negotiate the correct auth method=20
> > > >=20
> > > > The author of XWT sent the following email to me
> > > >=20
> > > > >Tim, I've got a piece of the answer -- your server needs to retu=
rn an
> > > > >HTTP 401 (Unauthorized) if no username/password is provided. Thi=
s
> > > > >response includes the challenge that XWT needs in order to build=
 an
> > > > >authentication request (realm, digest nonce challenge, etc).
> > > >=20
> > > > However what Zope is doing is sending back a <fault> in the=20
> > > > XMLRPC <methodResponse> packet.=20
> > > >=20
> > > > So it appears to me that Zope doesn't send a http response 401 fo=
r=20
> > > > XMLRPC (over http), but will send a 401 back to the browser.
> > > >=20
> > > > XMLRPC doesn't say anything about authentication, so I suppose ei=
ther
> > > > method is acceptable. However because XMLRPC is implemented=20
> > > > on top of http, I would have thought a http approach (ie error 40=
1)
> > > > would be used.
> > > >=20
> > > > It appears that this behaviour is fundamental to Zope and is not =
an
> > > > artifact of cookie auth in CMF etc..
> > > >=20
> > > > Is this really correct behaviour ?
> > > >=20
> > > > Regards
> > > >=20
> > > > Tim Hoffman
> > > >=20
> > > >=20
> > > > =20
> > > >=20
> > > >=20
> > > > _______________________________________________
> > > > Zope-Dev maillist  -  Zope-Dev@zope.org
> > > > http://lists.zope.org/mailman/listinfo/zope-dev
> > > > **  No cross posts or HTML encoding!  **
> > > > (Related lists -=20
> > > >  http://lists.zope.org/mailman/listinfo/zope-announce
> > > >  http://lists.zope.org/mailman/listinfo/zope )
> > >=20
> > >=20
> > >=20
> > > _______________________________________________
> > > Zope-Dev maillist  -  Zope-Dev@zope.org
> > > http://lists.zope.org/mailman/listinfo/zope-dev
> > > **  No cross posts or HTML encoding!  **
> > > (Related lists -=20
> > >  http://lists.zope.org/mailman/listinfo/zope-announce
> > >  http://lists.zope.org/mailman/listinfo/zope )
> > >=20
> >=20
> > ----
> >=20
>=20
> > import string, xmlrpclib, httplib
> > from base64 import encodestring
> >=20
> > class BasicAuthTransport(xmlrpclib.Transport):
> >     verbose =3D 0
> >    =20
> >     def __init__(self, username=3DNone, password=3DNone):
> >         self.username=3Dusername
> >         self.password=3Dpassword
> >=20
> >     def request(self, host, handler, request_body, verbose=3D0):
> >         # issue XML-RPC request
> >=20
> >         h =3D httplib.HTTP(host)
> >         h.putrequest("POST", handler)
> >=20
> >         # required by HTTP/1.1
> >         h.putheader("Host", host)
> >=20
> >         # 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)))
> >=20
> >         # 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,=20
self.password)),
> >                     "\012", ""))
> >         h.endheaders()
> >=20
> >         if request_body:
> >             h.send(request_body)
> >=20
> >         errcode, errmsg, headers =3D h.getreply()
> >=20
> >         if errcode !=3D 200:
> >             raise xmlrpclib.ProtocolError(
> >                 host + handler,
> >                 errcode, errmsg,
> >                 headers
> >                 )
> >=20
> >         return self.parse_response(h.getfile())=20
> >=20
> >=20
>=20
>=20
>=20