Skip to content
Browse files

first commit

  • Loading branch information...
0 parents commit 70db5ff86274008f4cf942b1e54e357576383d0d @lionelyoung committed
Showing with 245 additions and 0 deletions.
  1. +5 −0 .gitignore
  2. +57 −0 README
  3. +15 −0 cacert.pem
  4. +17 −0 client.py
  5. +1 −0 httpspass.conf
  6. +7 −0 make_password.py
  7. +15 −0 privkey.pem
  8. +30 −0 protocol.py
  9. +12 −0 xmlrpc.conf
  10. +10 −0 xmlrpc_app.py
  11. +76 −0 xmlrpcserver.py
5 .gitignore
@@ -0,0 +1,5 @@
+*~
+*.swp
+*.pyc
+*.log
+*.pid
57 README
@@ -0,0 +1,57 @@
+Modular, SSL, XMLRPC Server with Authentication for Python using Twistd
+Sami Khan
+Etopian Inc. (http://www.etopian.com)
+
+In order to run: twistd -y xmlrpc_app.py
+
+You may need to edit xmlrpc_app.py in order to point it to the directory in which
+the server files reside.
+
+See protocol.py for an example of how to write your own class to extend the server.
+
+See xmlrpc.conf for configuring the server with our own class, port, etc.
+
+See httpspass.conf to define the username password of your server. The password is a hash.
+
+Also you should generate your own certificates andd not use mine, they are for testing only.
+
+If you need any development done, be sure to hire me (http://www.etopian.com/quote)!
+
+Cheer,
+Sami Khan
+
+==========================================================================
+What I needed to do to get this to work:
+
+* Install Twisted
+* Install pyOpenSSL
+* Install web2 from Twisted:
+ svn co svn://svn.twistedmatrix.com/svn/Twisted/trunk Twisted
+* Move web2 into twisted
+* Make salted hash password (salt is the last 2 characters of the password)
+ from crypt import crypt
+ password = 'mypass'
+ crypt(password, password[-2:]) #(use the last two characters as the salt)
+* Add username/password to httpspass.conf
+* Create a Twisted Client
+ from twisted.web.xmlrpc import Proxy
+ from twisted.internet import reactor
+
+ def printValue(value):
+ print repr(value)
+ reactor.stop()
+
+ def printError(error):
+ print 'error', error
+ reactor.stop()
+
+ proxy = Proxy('https://%s:%s@localhost:9870' % ('myfancyusername', 'ohmygod'))
+ proxy.callRemote('echo', 'hello, im echoing this').addCallbacks(printValue, printError)
+ reactor.run()
+* Start the server:
+ twistd -y xmlrpc_app.py
+* Test the client:
+ python client.py
+
+Best wishes,
+Lionel Young
15 cacert.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICZTCCAc4CCQCu+pJt7jSMFzANBgkqhkiG9w0BAQUFADB3MQswCQYDVQQGEwJD
+QTEQMA4GA1UECBMHQWxiZXJ0YTEQMA4GA1UEBxMHQ2FsZ2FyeTEQMA4GA1UEChMH
+RXRvcGlhbjEQMA4GA1UEAxMHRXRvcGlhbjEgMB4GCSqGSIb3DQEJARYRYWRtaW5A
+ZXRvcGlhbi5jb20wHhcNMDgxMDA0MjMzNzAzWhcNMDgxMTAzMjMzNzAzWjB3MQsw
+CQYDVQQGEwJDQTEQMA4GA1UECBMHQWxiZXJ0YTEQMA4GA1UEBxMHQ2FsZ2FyeTEQ
+MA4GA1UEChMHRXRvcGlhbjEQMA4GA1UEAxMHRXRvcGlhbjEgMB4GCSqGSIb3DQEJ
+ARYRYWRtaW5AZXRvcGlhbi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB
+AMivGSMVD3UbqKNhtyp+AIE+NFLqKPrVyRKAZercc+dxFRV/b8ghM9zA1xrvMynB
+wHr8BzaIJ1ubEri6sIpZs2T3YhKWa2jANuRt9XMSH9/W3alaAnL55Dk4O6JIxrcn
+MW5cxMW770gHXCbtisfscFpdiMvVpj212PSv+gbv/ej5AgMBAAEwDQYJKoZIhvcN
+AQEFBQADgYEAjZJMBmsyPotIoSfS0BbjNUuymtoeK4tES2PJvZlmrIbmmjtlREVQ
+XW0G5mxgcmQtMw1hTY6xuycpSjFUBdYQGJapZ928rf+QZeUDxl4ADqc1rN1nECcN
+RV+I9BdnTOzhS7D8qST+GL1uhVyi/58eRCII+vULEyL2cMagHWeURN8=
+-----END CERTIFICATE-----
17 client.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+if __name__ == '__main__':
+ from twisted.web.xmlrpc import Proxy
+ from twisted.internet import reactor
+
+ def printValue(value):
+ print repr(value)
+ reactor.stop()
+
+ def printError(error):
+ print 'error', error
+ reactor.stop()
+
+ proxy = Proxy('https://%s:%s@localhost:9870' % ('myfancyusername', 'ohmygod'))
+ proxy.callRemote('mult', 2, 3).addCallbacks(printValue, printError)
+ reactor.run()
1 httpspass.conf
@@ -0,0 +1 @@
+myfancyusername:odMiBrkbgKTLA
7 make_password.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+if __name__ == '__main__':
+ from crypt import crypt
+ password = 'ohmygod'
+ salt = password[-2:]
+ print crypt(password, salt)
15 privkey.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDIrxkjFQ91G6ijYbcqfgCBPjRS6ij61ckSgGXq3HPncRUVf2/I
+ITPcwNca7zMpwcB6/Ac2iCdbmxK4urCKWbNk92ISlmtowDbkbfVzEh/f1t2pWgJy
++eQ5ODuiSMa3JzFuXMTFu+9IB1wm7YrH7HBaXYjL1aY9tdj0r/oG7/3o+QIDAQAB
+AoGBALtLD366bQ6ynZS94aB6sCXu1A5+E3jmhR4LTxL+Y/2ggDjsEnsI4coo/5hX
+nbxe4zDkfibas0C/XZ2iPpkgVlc+vYAP9/aZ8EoS8nB5xKloQo2Az3jQPuthrwS+
+er/NfPS+RFr2ldYcbQqB9uhDClgDSapUU1ZhL8AkhWP90U3BAkEA/tTzas8riUC+
+F8wqXKS0IFOOvrXUAs4VICiJiHmQugJNeJLsFob+3HC1NloGGGAXbjSqG+RNTt2O
+YOkmG3ZpHQJBAMmamp5ow4sk8XgLb4hOilWSGWMcB3xi67i8f19igNCcZLMApAJ0
+kklkug+3L2EJM0qIBlglPZSC0bCqJeCC1I0CQFulF/l0kfKlbve9/AofTYxGoJJj
+b+CmXqCXE4caOPs8MsJHDFK5r9R1UCZAz+paPHLsy7SGMWtIcJjXoFXGCt0CQFik
+sfeU+OXliIbQAGpenlShuKfrWx9GH39K4nZ+SUVwfpZ2Yabyup+qumTOlvaDpRnQ
+VXnMZhc2rhyPs7fTzsECQExvcjhfFXhNLFQgq2i3DcjD/NnJShWxF2LolP+vNesw
+/bzJtygh1mmCYtb2uD8j8ng8kxAkhuperP/ZUhci37I=
+-----END RSA PRIVATE KEY-----
30 protocol.py
@@ -0,0 +1,30 @@
+from twisted.web2 import xmlrpc
+
+
+# this is the main class which contains the xmlrpc_ functions we need
+class XMLRPCProtocol(xmlrpc.XMLRPC):
+
+ addSlash = True
+
+ def xmlrpc_bind(self, request):
+ return parse("test.conf")
+
+ def xmlrpc_echo(self, request, x):
+ """Return all passed args."""
+ return x
+
+ def xmlrpc_mult(self, request, x, y):
+ """Return all passed args."""
+ return x*y
+
+ #add a new zone, reload the configuration
+ def addZone(self, request, name):
+ print 'adding new zone'
+
+ def updateZone(self, request, name):
+ print 'updating existing zone'
+
+
+ def setTTL(self, request, name):
+ print 'test'
+
12 xmlrpc.conf
@@ -0,0 +1,12 @@
+[XMLRPCServer]
+service=protocol
+
+transport=https
+transport_port=9870
+httpauthrealm=Etopian
+
+sslprivateKey=privkey.pem
+sslcertKey=cacert.pem
+
+unixuser=
+unixgroup=
10 xmlrpc_app.py
@@ -0,0 +1,10 @@
+import sys
+sys.path.append("/path/to/app")
+
+import xmlrpcserver
+from twisted.application import service, strports
+
+application = service.Application("XMLRPCServer")
+x = xmlrpcserver.XMLRPCService( )
+XMLRPCService = x.start( )
+XMLRPCService.setServiceParent(application)
76 xmlrpcserver.py
@@ -0,0 +1,76 @@
+# Modular XMLRPC Server with SSL, Authentication using Twistd
+# Etopian Inc.
+# (c) Sami Khan 2009
+# Licensed under GPL v 3
+
+
+from zope.interface import Interface, implements
+
+from twisted.application import service, internet, strports
+from twisted.cred import portal as portal1
+from twisted.cred import checkers
+from twisted.internet import protocol, reactor, ssl
+from twisted.protocols import basic
+from twisted.web2 import channel, resource, http, responsecode, xmlrpc, server
+from twisted.web2.auth.interfaces import IAuthenticatedRequest, IHTTPUser
+from twisted.web2.auth import basic, digest, wrapper
+
+#dynamically load the protocol
+from ConfigParser import *
+config = ConfigParser()
+config.read('xmlrpc.conf')
+
+try:
+
+ service = config.get('XMLRPCServer', 'service')
+ print service
+ exec "import " + service + " as xmlrpcprotocol"
+except ImportError:
+ print 'Protocol file was not found. Check to see if it compiles.'
+
+
+class IHTTPUser(Interface):
+ pass
+
+class HTTPUser(object):
+ implements(IHTTPUser)
+
+class HTTPAuthRealm(object):
+ implements(portal1.IRealm)
+
+ def requestAvatar(self, avatarId, mind, *interfaces):
+ if IHTTPUser in interfaces:
+ return IHTTPUser, HTTPUser()
+
+ raise NotImplementedError("Only IHTTPUser interface is supported")
+
+
+class XMLRPCService(internet.SSLServer):
+ #check a password generated by htpasswd, keeps you from storing plaintext on server
+ def checkHashedPassword(self, username, password, hashedpassword):
+ """For files created with htpasswd"""
+ from crypt import crypt
+ return crypt(password, hashedpassword[:2])
+
+ def start(self):
+ #rsrc = NameServerProtocol( )
+ rsrc = apply(xmlrpcprotocol.XMLRPCProtocol)
+
+ #handle auth stuff
+ portal = portal1.Portal(HTTPAuthRealm())
+
+ checker = checkers.FilePasswordDB('httpspass.conf', ':', 0, 1, True, hash=self.checkHashedPassword)
+ portal.registerChecker(checker)
+ httpauthrealm = port = config.get('XMLRPCServer', 'httpauthrealm')
+ credFactories = (basic.BasicCredentialFactory(httpauthrealm), digest.DigestCredentialFactory('md5', httpauthrealm))
+ ifaces = (IHTTPUser,)
+ root = wrapper.HTTPAuthResource(rsrc, credFactories, portal, ifaces)
+ site = server.Site(root)
+ # Comment out the HTTPAuth wrapper
+ #site = server.Site(rsrc)
+
+ port = config.get('XMLRPCServer', 'transport_port')
+ privateKey = config.get('XMLRPCServer', 'sslprivateKey')
+ certKey = config.get('XMLRPCServer', 'sslcertKey')
+ s = strports.service('ssl:'+port+':privateKey='+privateKey+':certKey='+certKey, channel.HTTPFactory(site))
+ return s

0 comments on commit 70db5ff

Please sign in to comment.
Something went wrong with that request. Please try again.