[Twisted-web] secure access to xmlrpc, soap (access from ip-ranges, login, ssl) - a feasible approach?

Marco Aschwanden PPNTWIMBXFFC at spammotel.com
Thu Mar 9 12:20:04 CST 2006


Hi

I would like to write a server, that delivers the same services over  
xmlrpc or soap. It is no problem to design this. The problem arises when  
it comes to authentification.

What I want:
- Deliver services in xmlrpc or soap
- Deliver services only to people in well defined ip-ranges  
(192.168.1.*,...)
- Deliver services only to logged in users (except for login requests  
which should always pass!)
- User don't have to log in each time they do a request! (overhead would  
be deadly)
- Deliver services encrypted (ssl) if desired

What I have:
- I have a server that delivers services over xmlrpc or soap
- I have a class that keeps track for users that have logged  
in/expired/available.
- I have a class that can test, whether the request comes from a valid ip.


The problem(s):
- I know that twisted has "cred" library to authentificate people. I don't  
see how this is usable with a stateless protocol like xmlrpc or soap. As  
far as I understood the "cred"-library does not apply to xmlrpc or soap.  
If it does, than a simple exmaple would be very nice.


To me it seems, that the best point to enforce "authentification" and  
"logged sessions" is to override render-method of
--> twisted.web.xmlrpc.XMLRPC
--> twisted.soap.SOAPPublisher


 from twisted.web.xmlrpc import XMLRPC
import xmlrpclib
import bsw_config


class XMLRPC_WITH_AUTH(XMLRPC):
      def __init__(self):
           XMLRPC.__init__(self)


      def render(self, request):
           """Overriding this let me introduce authentification."""

           # <Modification>
           # --> verify whether the ip is in the allowed range -->
           # I do it here, before any further handling is done!
           # verify --> request.client.host is allowed
           # </Modification>

           request.content.seek(0, 0)
           args, functionPath = xmlrpclib.loads(request.content.read())

           # <Modification>
           # Always let login request pass! (xxx Multicall?)
           if not functionPath == u"do_login":
                # verify user logged in already based on IP (port always  
changes -
                # because xmlrpc is stateless)
                # what other possibilty do I have for a unique id?
                if not verify_user_is_logged_in(request.client.host):
                     self._cbRender(Fault(xxx, xxx) , request)
                     return server.NOT_DONE_YET
           # </Modification>

           try:
                function = self._getFunction(functionPath)
           except Fault, f:
                self._cbRender(f, request)
           else:
                request.setHeader("content-type", "text/xml")
                defer.maybeDeferred(function, *args).addErrback(
                self._ebRender
              ).addCallback(
                self._cbRender, request
              )
           return server.NOT_DONE_YET


The two <modification></modification> show my intended interventions.

Is this a feasible approach?

The only unique id I have from the client is his IP - the socket/port, as  
I said, changes with each request (stateless nature of xmlrpc/soap). This  
poses a security risk, because clients served from the same  
proxy/router/firewall have the same IP... which forces me to add a unique  
token to each request (please not).

Do you know another unique item of each request, that identifies the  
client further?

To further secure the transport, I would like to be able to transport the  
data over ssl. Is this as easy as:

reactor.listenSSL(XMLRPC_PORT, server.Site(XmlrpcPublisher()), some_cert)
reactor.listenSSL(SOAP_PORT, server.Site(SoapPublisher()), some_cert)


Thanks for all your answers in advance,
Greetins,
Marco





More information about the Twisted-web mailing list