Ignore:
Timestamp:
22/09/12 22:22:51 (8 years ago)
Author:
pjkersha
Message:

Patches from Willem to support Google and Github OAuth 2.0 profiles.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ndg_oauth/ndg_oauth_server/ndg/oauth/server/examples/bearer_tok/bearer_tok_server_app_serve.py

    r8117 r8153  
    1 from paste.script.serve import ServeCommand 
    2  
    3 ServeCommand("serve").run(["bearer_tok_server_app.ini"]) 
     1#from paste.script.serve import ServeCommand 
     2# 
     3#ServeCommand("serve").run(["bearer_tok_server_app.ini"]) 
     4#!/usr/bin/env python 
     5"""NDG Security test harness for security web services middleware stack 
     6 
     7""" 
     8__author__ = "P J Kershaw" 
     9__date__ = "20/11/08" 
     10__copyright__ = "(C) 2009 Science and Technology Facilities Council" 
     11__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     12__revision__ = "$Id:$" 
     13from os import path 
     14import optparse  
     15      
     16from OpenSSL import SSL 
     17from OpenSSL import crypto  
     18from paste.deploy import loadapp 
     19from paste.script.util.logging_config import fileConfig 
     20 
     21THIS_DIR = path.dirname(__file__) 
     22SHARED_CONFIG_DIR  = path.join(THIS_DIR, '..', 'shared_config') 
     23PKI_DIR = path.join(SHARED_CONFIG_DIR, 'pki')  
     24CACERT_DIR = path.join(PKI_DIR, 'ca') 
     25 
     26import paste.httpserver 
     27from threading import Thread 
     28 
     29 
     30class PasteDeployAppServer(object): 
     31    """Wrapper to paste.httpserver to enable background threading""" 
     32     
     33    def __init__(self, app=None, cfgFilePath=None, port=7443, host='0.0.0.0', 
     34                 ssl_context=None): 
     35        """Load an application configuration from cfgFilePath ini file and  
     36        instantiate Paste server object 
     37        """        
     38        self.__thread = None 
     39         
     40        if cfgFilePath: 
     41            if app: 
     42                raise KeyError('Set either the "cfgFilePath" or "app" keyword ' 
     43                               'but not both') 
     44             
     45            fileConfig(cfgFilePath, defaults={'here':path.dirname(cfgFilePath)}) 
     46            app = loadapp('config:%s' % cfgFilePath) 
     47             
     48        elif app is None: 
     49            raise KeyError('Either the "cfgFilePath" or "app" keyword must be ' 
     50                           'set') 
     51                        
     52        self.__pasteServer = paste.httpserver.serve(app, host=host, port=port,  
     53                                                    start_loop=False,  
     54                                                    ssl_context=ssl_context) 
     55     
     56    @property 
     57    def pasteServer(self): 
     58        return self.__pasteServer 
     59     
     60    @property 
     61    def thread(self): 
     62        return self.__thread 
     63     
     64    def start(self): 
     65        """Start server""" 
     66        self.pasteServer.serve_forever() 
     67         
     68    def startThread(self): 
     69        """Start server in a separate thread""" 
     70        self.__thread = Thread(target=PasteDeployAppServer.start, args=(self,)) 
     71        self.thread.start() 
     72         
     73    def terminateThread(self): 
     74        self.pasteServer.server_close() 
     75 
     76  
     77class OpenSSLVerifyCallbackMiddleware(object): 
     78    """Set peer certificate retrieved from PyOpenSSL SSL context callback in 
     79    environ dict SSL_CLIENT_CERT item 
     80     
     81    FOR TESTING PURPOSES ONLY - IT IS NOT THREAD SAFE 
     82    """ 
     83    def __init__(self, app): 
     84        self._app = app 
     85        self.ssl_client_cert = None 
     86        self.ssl_client_cert_dn = None 
     87#        self.ignore_pat = 'localhost' 
     88        self.ignore_pat = None 
     89         
     90    def createSSLCallback(self): 
     91        """Make a SSL Context callback function and return it to the caller""" 
     92        def _callback(conn, x509, errnum, errdepth, ok): 
     93            if errdepth == 0: 
     94                subject = x509.get_subject() 
     95                components = subject.get_components() 
     96                if self.ignore_pat not in [i[-1] for i in components]: 
     97                    self.ssl_client_cert = crypto.dump_certificate( 
     98                                                    crypto.FILETYPE_PEM, x509) 
     99                    self.ssl_client_cert_dn = '/'+ '/'.join( 
     100                                        ['%s=%s' % i for i in components]) 
     101            return ok 
     102         
     103        return _callback 
     104         
     105    def __call__(self, environ, start_response): 
     106        """Set the latest peer SSL client certificate from the SSL callback 
     107        into environ SSL_CLIENT_CERT key""" 
     108        if self.ssl_client_cert: 
     109            environ['SSL_CLIENT_CERT'] = self.ssl_client_cert 
     110            environ['SSL_CLIENT_S_DN'] = self.ssl_client_cert_dn 
     111            self.ssl_client_cert = None 
     112 
     113        return self._app(environ, start_response) 
     114     
     115 
     116class ApacheSSLVariablesMiddleware(object): 
     117    """Simulate Apache SSL environment setting relevant environ variables""" 
     118    def __init__(self, app): 
     119        self._app = app 
     120                                  
     121    def __call__(self, environ, start_response): 
     122        environ['HTTPS'] = '1' 
     123        return self._app(environ, start_response) 
     124 
     125        
     126INI_FILENAME = 'bearer_tok_server_app.ini' 
     127 
     128# To start run  
     129# $ paster serve services.ini or run this file as a script, see 
     130# $ ./securityservicesapp.py -h 
     131if __name__ == '__main__':     
     132    cfgFilePath = path.join(path.dirname(path.abspath(__file__)), INI_FILENAME)  
     133      
     134    defCertFilePath = path.join(PKI_DIR, 'host.pem') 
     135    defPriKeyFilePath = path.join(PKI_DIR, 'host.pem') 
     136         
     137    parser = optparse.OptionParser() 
     138    parser.add_option("-p", 
     139                      "--port", 
     140                      dest="port", 
     141                      default=5000, 
     142                      type='int', 
     143                      help="port number to run under") 
     144 
     145    parser.add_option("-s", 
     146                      "--with-ssl", 
     147                      dest="withSSL", 
     148                      default='True', 
     149                      help="Run with SSL") 
     150 
     151    parser.add_option("-c", 
     152                      "--cert-file", 
     153                      dest='certFilePath', 
     154                      default=defCertFilePath, 
     155                      help="SSL Certificate file") 
     156 
     157    parser.add_option("-k", 
     158                      "--private-key-file", 
     159                      default=defPriKeyFilePath, 
     160                      dest='priKeyFilePath', 
     161                      help="SSL private key file") 
     162 
     163    parser.add_option("-f", 
     164                      "--conf", 
     165                      dest="configFilePath", 
     166                      default=cfgFilePath, 
     167                      help="Configuration file path") 
     168     
     169    parser.add_option("-a", 
     170                      "--with-ssl-client-auth", 
     171                      dest="ssl_client_authn", 
     172                      action='store_true', 
     173                      default=True, 
     174                      help="Set client authentication with SSL (requires -s " 
     175                           "option") 
     176     
     177    opt = parser.parse_args()[0] 
     178    cfgFilePath = path.abspath(opt.configFilePath) 
     179     
     180    if opt.withSSL.lower() == 'true': 
     181        ssl_context = SSL.Context(SSL.SSLv23_METHOD) 
     182#        ssl_context.set_options(SSL.OP_NO_SSLv2) 
     183     
     184        ssl_context.use_privatekey_file(opt.priKeyFilePath) 
     185        ssl_context.use_certificate_file(opt.certFilePath) 
     186         
     187        ssl_context.load_verify_locations(None, CACERT_DIR) 
     188        ssl_context.set_verify_depth(9) 
     189         
     190        # Load the application from the Paste ini file configuration         
     191        fileConfig(cfgFilePath, defaults={'here': path.dirname(cfgFilePath)}) 
     192        app = loadapp('config:%s' % cfgFilePath) 
     193         
     194        if opt.ssl_client_authn: 
     195            # Wrap the application in middleware to set the SSL client certificate  
     196            # obtained from the SSL handshake in environ                 
     197            app = OpenSSLVerifyCallbackMiddleware(app) 
     198            _callback = app.createSSLCallback() 
     199             
     200            # Wrap in middleware to simulate Apache environment 
     201            app = ApacheSSLVariablesMiddleware(app) 
     202         
     203            ssl_context.set_verify(SSL.VERIFY_PEER, _callback) 
     204             
     205        server = PasteDeployAppServer(app=app,  
     206                                      port=opt.port, 
     207                                      ssl_context=ssl_context)  
     208    else: 
     209        ssl_context = None 
     210 
     211        server = PasteDeployAppServer(cfgFilePath=cfgFilePath,  
     212                                      port=opt.port, 
     213                                      ssl_context=ssl_context)  
     214    server.start() 
Note: See TracChangeset for help on using the changeset viewer.