Changeset 6886


Ignore:
Timestamp:
24/05/10 11:49:58 (9 years ago)
Author:
pjkersha
Message:
  • working unit tests for HTTP Basic Auth middleware
  • refactoring MyProxyClient? middleware and MyProxy? logon app ready for testing.
Location:
TI12-security/trunk/MyProxyServerUtils
Files:
4 added
1 deleted
3 edited
1 moved

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/MyProxyServerUtils/myproxy/server/wsgi/__init__.py

    r6881 r6886  
    1 """HTTPS proxy to MyProxy server WSGI Application 
     1"""MyProxy server utilities WSGI package 
    22  
    33NERC DataGrid Project 
     
    99__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1010__revision__ = "$Id: $" 
    11 import logging 
    12 log = logging.getLogger(__name__) 
    13 import traceback 
    14 import re 
    15 import httplib 
    16 import socket 
    17  
    18 from M2Crypto import X509 
    19  
    20 #from myproxy.client import MyProxyClient, MyProxyClientError 
    21      
    22 from myproxy.server.wsgi.httpbasicauth import HttpBasicAuthMiddleware 
    23          
    24          
    25 class MyProxyClientMiddlewareConfigError(Exception): 
    26     """Configuration error with MyProxyClientMiddleware""" 
    27  
    28  
    29 class MyProxyClientMiddleware(object): 
    30     ''' 
    31     Create a MyProxy client and make it available to other middleware in the  
    32     WSGI stack 
    33     ''' 
    34     # Options for ini file 
    35     CLIENT_ENV_KEYNAME_OPTNAME = 'clientEnvKeyName' 
    36     LOGON_FUNC_ENV_KEYNAME_OPTNAME = 'logonFuncEnvKeyName'      
    37      
    38     # Default environ key names 
    39     CLIENT_ENV_KEYNAME = ('ndg.security.server.wsgi.authn.' 
    40                           'MyProxyClientMiddleware') 
    41     LOGON_FUNC_ENV_KEYNAME = ('ndg.security.server.wsgi.authn.' 
    42                               'MyProxyClientMiddleware.logon') 
    43      
    44     WSGI_INPUT_ENV_KEYNAME = 'wsgi.input' 
    45      
    46     # Option prefixes 
    47     PARAM_PREFIX = 'myproxy.' 
    48     MYPROXY_CLIENT_PARAM_PREFIX = 'client.' 
    49      
    50     def __init__(self, app, global_conf, prefix=PARAM_PREFIX,  
    51                  myProxyClientPrefix=MYPROXY_CLIENT_PARAM_PREFIX, **app_conf): 
    52         '''''' 
    53         super(MyProxyClientMiddleware, self).__init__(app, global_conf) 
    54         self.__myProxyClient = None 
    55  
    56         # Get MyProxyClient initialisation parameters 
    57         myProxyClientFullPrefix = prefix + myProxyClientPrefix 
    58                              
    59         myProxyClientKw = dict([(k.replace(myProxyClientFullPrefix, ''), v)  
    60                                  for k,v in app_conf.items()  
    61                                  if k.startswith(myProxyClientFullPrefix)]) 
    62          
    63         self.myProxyClient = MyProxyClient(**myProxyClientKw) 
    64         clientEnvKeyOptName = prefix + \ 
    65                             MyProxyClientMiddleware.CLIENT_ENV_KEYNAME_OPTNAME 
    66                      
    67         self.clientEnvironKeyName = app_conf.get(clientEnvKeyOptName, 
    68                                 MyProxyClientMiddleware.CLIENT_ENV_KEYNAME) 
    69                      
    70         logonFuncEnvKeyOptName = prefix + \ 
    71                     MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME_OPTNAME 
    72  
    73         self.logonFuncEnvironKeyName = app_conf.get(logonFuncEnvKeyOptName, 
    74                                 MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME) 
    75  
    76     def _getClientEnvironKeyName(self): 
    77         return self.__clientEnvironKeyName 
    78  
    79     def _setClientEnvironKeyName(self, value): 
    80         if not isinstance(value, basestring): 
    81             raise TypeError('Expecting string type for "clientEnvironKeyName"; ' 
    82                             'got %r type' % type(value)) 
    83         self.__clientEnvironKeyName = value 
    84  
    85     clientEnvironKeyName = property(fget=_getClientEnvironKeyName,  
    86                                     fset=_setClientEnvironKeyName,  
    87                                     doc="key name in environ for the " 
    88                                         "MyProxyClient instance")     
    89  
    90     def _getLogonFuncEnvironKeyName(self): 
    91         return self.__logonFuncEnvironKeyName 
    92  
    93     def _setLogonFuncEnvironKeyName(self, value): 
    94         if not isinstance(value, basestring): 
    95             raise TypeError('Expecting string type for ' 
    96                             '"logonFuncEnvironKeyName"; got %r type' %  
    97                             type(value)) 
    98         self.__logonFuncEnvironKeyName = value 
    99  
    100     logonFuncEnvironKeyName = property(fget=_getLogonFuncEnvironKeyName,  
    101                                        fset=_setLogonFuncEnvironKeyName,  
    102                                        doc="key name in environ for the " 
    103                                            "MyProxy logon function") 
    104      
    105     def _getMyProxyClient(self): 
    106         return self.__myProxyClient 
    107  
    108     def _setMyProxyClient(self, value): 
    109         if not isinstance(value, MyProxyClient): 
    110             raise TypeError('Expecting %r type for "myProxyClient" attribute ' 
    111                             'got %r' % (MyProxyClient, type(value))) 
    112         self.__myProxyClient = value 
    113          
    114     myProxyClient = property(fget=_getMyProxyClient, 
    115                              fset=_setMyProxyClient,  
    116                              doc="MyProxyClient instance used to convert HTTPS" 
    117                                  " call into a call to a MyProxy server") 
    118  
    119     def __call__(self, environ, start_response): 
    120         '''Set MyProxyClient instance and MyProxy logon method in environ 
    121          
    122         @type environ: dict 
    123         @param environ: WSGI environment variables dictionary 
    124         @type start_response: function 
    125         @param start_response: standard WSGI start response function 
    126         ''' 
    127         log.debug("MyProxyClientMiddleware.__call__ ...") 
    128         environ[self.clientEnvironKeyName] = self.myProxyClient 
    129         environ[self.logonFuncEnvironKeyName] = self.myProxyLogon 
    130          
    131         return self._app(environ, start_response) 
    132      
    133     @property 
    134     def myProxyLogon(self): 
    135         """Return the MyProxy logon method wrapped as a HTTP Basic Auth  
    136         authenticate interface function 
    137         """ 
    138         def _myProxylogon(environ, start_response, username, password): 
    139             """Wrap MyProxy logon method as a WSGI app 
    140             """ 
    141             if environ.get('REQUEST_METHOD') == 'GET': 
    142                 # No certificate request passed with GET call 
    143                 # TODO: retire this method? - keys are generated here instead of 
    144                 # the client 
    145                 certReq = None 
    146                      
    147             elif environ.get('REQUEST_METHOD') == 'POST': 
    148                  
    149                 pemCertReq = environ[ 
    150                         MyProxyClientMiddleware.WSGI_INPUT_ENV_KEYNAME].read() 
    151                  
    152                 # TODO: restore WSGI file object 
    153                  
    154                 # Expecting PEM encoded request 
    155                 certReq = X509.load_request_string(pemCertReq)   
    156             else: 
    157                 status = self.getStatusMessage(httplib.UNAUTHORIZED) 
    158                 response = ("HTTP request method %r not recognised for this " 
    159                             "request " % environ.get('REQUEST_METHOD',  
    160                                                      '<Not set>')) 
    161                  
    162             try: 
    163                 credentials = self.myProxyClient.logon(username,  
    164                                                        password, 
    165                                                        certReq=certReq) 
    166                 status = self.getStatusMessage(httplib.OK) 
    167                 response = '\n'.join(credentials) 
    168                  
    169             except MyProxyClientError, e: 
    170                 status = self.getStatusMessage(httplib.UNAUTHORIZED) 
    171                 response = str(e) 
    172              
    173             except socket.error, e: 
    174                 raise MyProxyClientMiddlewareConfigError("Socket error " 
    175                                         "with MyProxy server %r: %s" %  
    176                                         (self.myProxyClient.hostname, e)) 
    177             except Exception, e: 
    178                 log.error("MyProxyClient.logon raised an unknown exception " 
    179                           "calling %r: %s",  
    180                           self.myProxyClient.hostname, 
    181                           traceback.format_exc()) 
    182                 raise 
    183              
    184             start_response(status, 
    185                            [('Content-length', str(len(response))), 
    186                             ('Content-type', 'text/plain')]) 
    187             return [response] 
    188          
    189         return _myProxylogon 
    190          
    191          
    192 class MyProxyLogonMiddlewareConfigError(Exception): 
    193     """Configuration error with MyProxyLogonMiddleware""" 
    194      
    195      
    196 class MyProxyLogonMiddleware(object): 
    197     """HTTP Basic Auth interface to MyProxy logon.  This interfaces creates a 
    198     MyProxy client instance and HTTP Basic Auth based web service interface 
    199     for MyProxy logon calls.  This WSGI must be run over HTTPS to ensure 
    200     confidentiality of username/passphrase credentials 
    201     """ 
    202     PARAM_PREFIX = 'myproxy.logon.' 
    203      
    204     def __init__(self, app, global_conf, prefix=PARAM_PREFIX, **app_conf):         
    205          
    206         authnFuncEnvKeyNameOptName = HTTPBasicAuthMiddleware.PARAM_PREFIX + \ 
    207                         HTTPBasicAuthMiddleware.AUTHN_FUNC_ENV_KEYNAME_OPTNAME 
    208                          
    209         if authnFuncEnvKeyNameOptName in app_conf: 
    210             raise MyProxyLogonMiddlewareConfigError("Found %r option name in " 
    211                 "application configuration settings.  Use %r instead" % 
    212                 (authnFuncEnvKeyNameOptName,  
    213                  MyProxyClientMiddleware.PARAM_PREFIX + \ 
    214                  MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME_OPTNAME)) 
    215          
    216         httpBasicAuthApp = HTTPBasicAuthMiddleware(app, app_conf, **app_conf) 
    217         app = MyProxyClientMiddleware(httpBasicAuthApp, app_conf, **app_conf) 
    218          
    219         # Set HTTP Basic Auth to use the MyProxy client logon for its 
    220         # authentication method 
    221         httpBasicAuthApp.authnFuncEnvironKeyName = app.logonFuncEnvironKeyName 
    222          
    223         super(MyProxyLogonMiddleware, self).__init__(app, global_conf,  
    224                                                      prefix=prefix, **app_conf) 
  • TI12-security/trunk/MyProxyServerUtils/myproxy/server/wsgi/httpbasicauth.py

    r6881 r6886  
    5252                           **local_conf): 
    5353        """Function following Paste filter app factory signature 
     54         
     55        @type app: callable following WSGI interface 
     56        @param app: next middleware/application in the chain       
     57        @type global_conf: dict         
     58        @param global_conf: PasteDeploy global configuration dictionary 
     59        @type prefix: basestring 
     60        @param prefix: prefix for configuration items 
     61        @type app_conf: dict         
     62        @param app_conf: PasteDeploy application specific configuration  
     63        dictionary 
    5464        """ 
    5565        httpBasicAuthFilter = cls(app) 
     
    5868        return httpBasicAuthFilter 
    5969         
    60     def parseConfig(self, prefix='', **local_conf): 
     70    def parseConfig(self, prefix='', **app_conf): 
     71        """Parse dictionary of configuration items updating the relevant  
     72        attributes of this instance 
     73         
     74        @type prefix: basestring 
     75        @param prefix: prefix for configuration items 
     76        @type app_conf: dict         
     77        @param app_conf: PasteDeploy application specific configuration  
     78        dictionary 
     79        """ 
    6180        rePathMatchListOptName = prefix + \ 
    6281                            HttpBasicAuthMiddleware.RE_PATH_MATCH_LIST_OPTNAME 
    63         rePathMatchListVal = local_conf.pop(rePathMatchListOptName, '') 
     82        rePathMatchListVal = app_conf.pop(rePathMatchListOptName, '') 
    6483         
    6584        self.rePathMatchList = [re.compile(i)  
     
    6988                    HttpBasicAuthMiddleware.AUTHN_FUNC_ENV_KEYNAME_OPTNAME 
    7089                     
    71         self.authnFuncEnvironKeyName = local_conf.get(paramName, 
     90        self.authnFuncEnvironKeyName = app_conf.get(paramName, 
    7291                                HttpBasicAuthMiddleware.AUTHN_FUNC_ENV_KEYNAME) 
    7392 
  • TI12-security/trunk/MyProxyServerUtils/setup.py

    r6881 r6886  
    3535    url =               'http://proj.badc.rl.ac.uk/ndg/wiki/Security/MyProxyClient', 
    3636    platforms =         ['POSIX', 'Linux', 'Windows'], 
    37     install_requires =  ['PyOpenSSL'], 
     37    install_requires =  ['MyProxyClient'], 
    3838    license =           __license__, 
    3939    test_suite =        'myproxy.server.test', 
Note: See TracChangeset for help on using the changeset viewer.