PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/mig/grsfs-fuse/fs/core/network/rpc/securepyro.py

http://migrid.googlecode.com/
Python | 239 lines | 141 code | 23 blank | 75 comment | 9 complexity | 0a3a9658617c512a505901c43bb872be MD5 | raw file
Possible License(s): IPL-1.0, GPL-2.0, GPL-3.0, MPL-2.0-no-copyleft-exception, JSON
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # --- BEGIN_HEADER ---
  5. #
  6. # securepyro - a secure version of the external pyro server and proxy
  7. # Copyright (C) 2003-2011 The MiG Project lead by Brian Vinter
  8. #
  9. # This file is part of MiG.
  10. #
  11. # MiG is free software: you can redistribute it and/or modify
  12. # it under the terms of the GNU General Public License as published by
  13. # the Free Software Foundation; either version 2 of the License, or
  14. # (at your option) any later version.
  15. #
  16. # MiG is distributed in the hope that it will be useful,
  17. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. # GNU General Public License for more details.
  20. #
  21. # You should have received a copy of the GNU General Public License
  22. # along with this program; if not, write to the Free Software
  23. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  24. #
  25. # -- END_HEADER ---
  26. #
  27. """A SSL/TLS secured version of the external Pyro server and proxy. Requires
  28. Pyro and m2crypto to provide the SSL functionality.
  29. """
  30. import os
  31. import sys
  32. import Pyro.core
  33. import Pyro.protocol
  34. default_name = 'all'
  35. # Binary wrapping (for symmetry with xmlrpc implementation)
  36. def wrapbinary(data):
  37. """Pack binary data - no action required"""
  38. return data
  39. def unwrapbinary(binary):
  40. """Unpack binary data - no action required"""
  41. return binary
  42. class InsecurePyroServerProxy(Pyro.core.DynamicProxyWithAttrs):
  43. """Insecure XMLRPC server proxy suitable for our use cases"""
  44. def __init__(self, address_tuple, **kwargs):
  45. """Translate address_tuple to suitable uri"""
  46. kwargs['uri'] = 'PYROLOC://%s:%d/%s' % (address_tuple[0],
  47. address_tuple[1],
  48. default_name)
  49. Pyro.core.DynamicProxyWithAttrs.__init__(self, '%(uri)s' % kwargs)
  50. class SecurePyroServerProxy(Pyro.core.DynamicProxyWithAttrs):
  51. """Secure XMLRPC server proxy suitable for our use cases"""
  52. def __init__(self, address_tuple, **kwargs):
  53. """Prepare secure socket and translate address_tuple to suitable uri"""
  54. kwargs['uri'] = 'PYROLOCSSL://%s:%d/%s' % (address_tuple[0],
  55. address_tuple[1],
  56. default_name)
  57. # requires m2crypto module and concatenated ssl key/cert
  58. Pyro.config.PYROSSL_CERTDIR = '.'
  59. Pyro.config.PYROSSL_SERVER_CERT = 'combined.pem'
  60. Pyro.config.PYROSSL_CA_CERT = 'cacert.pem'
  61. Pyro.config.PYROSSL_CLIENT_CERT = 'combined.pem'
  62. Pyro.config.PYRO_DNS_URI = True
  63. Pyro.core.DynamicProxyWithAttrs.__init__(self, '%(uri)s' % kwargs)
  64. class DummyHelper:
  65. """Wrapper object"""
  66. def echo_test(self, text):
  67. """For testing only"""
  68. return text
  69. class IntrospectionHelper:
  70. """For introspection functions"""
  71. introspect = {'system.listMethods': ('None', 'list of method names'),
  72. 'system.listSignatures': ('None', 'list of signatures'),
  73. 'system.methodHelp': ('method name', 'method help string')}
  74. def __init__(self):
  75. """Prepare public introspection functions"""
  76. pass
  77. def listMethods(self):
  78. """List available methods"""
  79. methods = self.introspect.keys()
  80. # TODO: should look up methods from parent, too
  81. return methods
  82. def listSignatures(self):
  83. """List available signatures"""
  84. methods = self.introspect.keys()
  85. signatures = []
  86. # TODO: should look up methods from parent, too
  87. for name in methods:
  88. signatures.append((name, 'unknown', 'unknown'))
  89. return signatures
  90. def methodHelp(self, method):
  91. """Show method docs"""
  92. methods = self.introspect.keys()
  93. # TODO: should look up methods from parent
  94. if method in methods:
  95. return 'doc for %s: none' % method
  96. return 'no help available for %s' % method
  97. class SecurePyroServer(Pyro.core.Daemon):
  98. """Secure Pyro server with automatic keep-alive support.
  99. Optional SSL key and certificate paths are exposed as key_path and
  100. cert_path arguments that may be overriden in instantiation if they are not
  101. the default combined.pem and combined.pem in the current directory.
  102. You can create suitable key and cert files with:
  103. openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout key.pem
  104. The optional ssl_version, ca_certs and cert_reqs arguments can be used to
  105. control additional low level settings during instantiation.
  106. They map directly to the corresponding ssl.wrap_socket arguments, so
  107. please refer to the ssl module documentation for details.
  108. The server uses a ssl_version default of None which allows the
  109. client to select whatever SSL or TLS protocol that it implements.
  110. """
  111. def __init__(self, addr, allow_none=True, key_path='combined.pem',
  112. cert_path='combined.pem', ca_certs=None, cert_reqs=None,
  113. ssl_version=None):
  114. """Overriding __init__ method of the Pyro server Daemon to add SSL in
  115. between basic init and network activation.
  116. """
  117. # Validate arguments possibly supplied by user
  118. if not os.path.isfile(key_path):
  119. raise ValueError("No such server key: %s" % key_path)
  120. if not os.path.isfile(cert_path):
  121. raise ValueError("No such server certificate: %s" % cert_path)
  122. # requires m2crypto module, concatenated ssl key/cert and cacert
  123. proto = 'PYROSSL'
  124. Pyro.config.PYROSSL_CERTDIR = os.path.join(os.getcwd(),
  125. os.path.dirname(key_path))
  126. if ca_certs:
  127. Pyro.config.PYROSSL_CA_CERT = ca_certs[0]
  128. else:
  129. Pyro.config.PYROSSL_CA_CERT = 'cacert.pem'
  130. Pyro.config.PYROSSL_SERVER_CERT = cert_path
  131. Pyro.config.PYROSSL_CLIENT_CERT = cert_path
  132. Pyro.config.PYRO_DNS_URI = True
  133. Pyro.core.initServer(banner=0)
  134. Pyro.core.Daemon.__init__(self, prtcol=proto, host=addr[0],
  135. port=addr[1])
  136. # Expose internal Pyro socket like xmlrpc socket
  137. self.socket = self.sock
  138. def register_instance(self, obj, name=default_name):
  139. """Fake object registration interface like xmlrpc"""
  140. # Skip name server and bind wrap object with method x() to name.
  141. # client must open proxy to URI/name to enable use of proxy.x()
  142. if self.__introspection:
  143. obj.system = IntrospectionHelper()
  144. pyro_obj = Pyro.core.ObjBase()
  145. pyro_obj.delegateTo(obj)
  146. self.connectPersistent(pyro_obj, name)
  147. def register_introspection_functions(self):
  148. """Fake introspection registration interface like xmlrpc"""
  149. self.__introspection = True
  150. self.register_instance(DummyHelper())
  151. def serve_forever(self):
  152. """Fake xmlrpc server request loop interface"""
  153. self.requestLoop()
  154. class InsecurePyroServer(Pyro.core.Daemon):
  155. """Insecure Pyro server"""
  156. def __init__(self, addr, allow_none=True):
  157. """Overriding __init__ method of the Pyro server Daemon.
  158. Exposes all functionality through the 'base' object.
  159. """
  160. Pyro.core.initServer(banner=0)
  161. Pyro.core.Daemon.__init__(self, host=addr[0], port=addr[1])
  162. # Expose internal Pyro socket like xmlrpc socket
  163. self.socket = self.sock
  164. def register_instance(self, obj, name=default_name):
  165. """Fake object registration interface like xmlrpc"""
  166. # Skip name server and bind wrap object with method x to name.
  167. # client must open proxy to URI/name to enable use of proxy.x()
  168. if self.__introspection:
  169. obj.system = IntrospectionHelper()
  170. pyro_obj = Pyro.core.ObjBase()
  171. pyro_obj.delegateTo(obj)
  172. self.connectPersistent(pyro_obj, name)
  173. def register_introspection_functions(self):
  174. """Fake introspection registration interface like xmlrpc"""
  175. self.__introspection = True
  176. self.register_instance(DummyHelper())
  177. def serve_forever(self):
  178. """Fake xmlrpc server request loop interface"""
  179. self.requestLoop()
  180. if __name__ == '__main__':
  181. address_tuple = ("localhost", 8000)
  182. if sys.argv[1:]:
  183. address_tuple = (sys.argv[1], address_tuple[1])
  184. if sys.argv[2:]:
  185. address_tuple = (address_tuple[0], int(sys.argv[2]))
  186. if 'client' in sys.argv[3:]:
  187. if 'insecure' in sys.argv[3:]:
  188. print "Open InsecurePyroServerProxy for %s:%s" % address_tuple
  189. proxy = InsecurePyroServerProxy(address_tuple)
  190. else:
  191. print "Open SecurePyroServerProxy for %s:%s" % address_tuple
  192. proxy = SecurePyroServerProxy(address_tuple)
  193. print "requesting list of methods from server on %s:%d" % address_tuple
  194. reply = proxy.system.listMethods()
  195. print "server replied: %s" % reply
  196. reply = proxy.echo_test("hello world!")
  197. print "server replied: %s" % reply
  198. else:
  199. if 'insecure' in sys.argv[3:]:
  200. print "Starting InsecurePyroServer on %s:%s" % address_tuple
  201. server = InsecurePyroServer(address_tuple)
  202. else:
  203. print "Starting SecurePyroServer on %s:%s" % address_tuple
  204. server = SecurePyroServer(address_tuple)
  205. server.register_introspection_functions()
  206. server.register_instance(DummyHelper())
  207. server.serve_forever()