Ignore:
Timestamp:
07/06/10 11:09:11 (10 years ago)
Author:
pjkersha
Message:

Incomplete - task 5: MyProxy? Logon HTTPS Interface

  • Added middleware for get trust roots interface
File:
1 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/MyProxyLogonWebService/myproxy/server/wsgi/middleware.py

    r6937 r6938  
    3232 
    3333 
    34 class MyProxyClientMiddleware(object): 
     34class MyProxyClientMiddlewareBase(object): 
     35    """Base class for common functionality""" 
     36    __slots__ = ('__app', '__clientEnvironKeyName',) 
     37     
     38    CLIENT_ENV_KEYNAME_OPTNAME = 'clientEnvKeyName' 
     39    DEFAULT_CLIENT_ENV_KEYNAME = ('myproxy.server.wsgi.middleware.' 
     40                                  'MyProxyClientMiddleware.myProxyClient') 
     41         
     42    def __init__(self, app): 
     43        self.__app = app 
     44        self.__clientEnvironKeyName = None 
     45     
     46    def _getClientEnvironKeyName(self): 
     47        """Get MyProxyClient environ key name 
     48         
     49        @rtype: basestring 
     50        @return: MyProxyClient environ key name 
     51        """ 
     52        return self.__clientEnvironKeyName 
     53 
     54    def _setClientEnvironKeyName(self, value): 
     55        """Set MyProxyClient environ key name 
     56         
     57        @type value: basestring 
     58        @param value: MyProxyClient environ key name 
     59        """ 
     60        if not isinstance(value, basestring): 
     61            raise TypeError('Expecting string type for "clientEnvironKeyName"; ' 
     62                            'got %r type' % type(value)) 
     63        self.__clientEnvironKeyName = value 
     64 
     65    clientEnvironKeyName = property(fget=_getClientEnvironKeyName,  
     66                                    fset=_setClientEnvironKeyName,  
     67                                    doc="key name in environ for the " 
     68                                        "MyProxyClient instance")   
     69     
     70    @property 
     71    def app(self): 
     72        """Get Property method for reference to next WSGI application in call 
     73        stack 
     74        @rtype: function 
     75        @return: WSGI application 
     76        """ 
     77        return self.__app 
     78     
     79    @staticmethod 
     80    def getStatusMessage(statusCode): 
     81        '''Make a standard status message for use with start_response 
     82        @type statusCode: int 
     83        @param statusCode: HTTP status code 
     84        @rtype: str 
     85        @return: status code with standard message 
     86        @raise KeyError: for invalid status code 
     87        ''' 
     88        return '%d %s' % (statusCode, httplib.responses[statusCode]) 
     89         
     90     
     91class MyProxyClientMiddleware(MyProxyClientMiddlewareBase): 
    3592    ''' 
    3693    Create a MyProxy client and make it available to other middleware in the  
     
    3895    ''' 
    3996    # Options for ini file 
    40     CLIENT_ENV_KEYNAME_OPTNAME = 'clientEnvKeyName' 
    4197    LOGON_FUNC_ENV_KEYNAME_OPTNAME = 'logonFuncEnvKeyName'      
    4298     
    4399    # Default environ key names 
    44     CLIENT_ENV_KEYNAME = ('myproxy.server.wsgi.middleware.' 
    45                           'MyProxyClientMiddleware.myProxyClient') 
    46100    LOGON_FUNC_ENV_KEYNAME = ('myproxy.server.wsgi.middleware.' 
    47101                              'MyProxyClientMiddleware.logon') 
    48102     
    49     CERTIFICATE_REQUST_POST_PARAM_KEYNAME = 'certificate_request' 
    50     GET_TRUSTROOTS_PARAM_KEYNAME = 'get_trustroots' 
    51     GET_TRUSTROOTS_TRUE_STR = '1' 
     103    CERT_REQ_POST_PARAM_KEYNAME = 'certificate_request' 
    52104     
    53105    # Option prefixes 
     
    59111        '__myProxyClient',  
    60112        '__logonFuncEnvironKeyName', 
    61         '__clientEnvironKeyName' 
    62113    ) 
    63114     
    64115    def __init__(self, app): 
    65         '''''' 
    66         self.__app = app 
     116        '''Create attributes 
     117         
     118        @type app: function 
     119        @param app: WSGI callable for next application in stack 
     120        ''' 
     121        super(MyProxyClientMiddleware, self).__init__(app) 
    67122        self.__myProxyClient = None 
    68123        self.__logonFuncEnvironKeyName = None 
    69         self.__clientEnvironKeyName = None 
    70124 
    71125    @classmethod 
     
    118172                     
    119173        self.clientEnvironKeyName = app_conf.get(clientEnvKeyOptName, 
    120                                 MyProxyClientMiddleware.CLIENT_ENV_KEYNAME) 
     174                            MyProxyClientMiddleware.DEFAULT_CLIENT_ENV_KEYNAME) 
    121175                     
    122176        logonFuncEnvKeyOptName = prefix + \ 
     
    124178 
    125179        self.logonFuncEnvironKeyName = app_conf.get(logonFuncEnvKeyOptName, 
    126                                 MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME)  
    127                 
    128     def _getClientEnvironKeyName(self): 
    129         return self.__clientEnvironKeyName 
    130  
    131     def _setClientEnvironKeyName(self, value): 
    132         if not isinstance(value, basestring): 
    133             raise TypeError('Expecting string type for "clientEnvironKeyName"; ' 
    134                             'got %r type' % type(value)) 
    135         self.__clientEnvironKeyName = value 
    136  
    137     clientEnvironKeyName = property(fget=_getClientEnvironKeyName,  
    138                                     fset=_setClientEnvironKeyName,  
    139                                     doc="key name in environ for the " 
    140                                         "MyProxyClient instance")     
     180                                MyProxyClientMiddleware.LOGON_FUNC_ENV_KEYNAME) 
    141181 
    142182    def _getLogonFuncEnvironKeyName(self): 
     183        """Get MyProxyClient logon function environ key name 
     184         
     185        @rtype: basestring 
     186        @return: MyProxyClient logon function environ key name 
     187        """ 
    143188        return self.__logonFuncEnvironKeyName 
    144189 
    145190    def _setLogonFuncEnvironKeyName(self, value): 
     191        """Set MyProxyClient environ key name 
     192         
     193        @type value: basestring 
     194        @param value: MyProxyClient logon function environ key name 
     195        """ 
    146196        if not isinstance(value, basestring): 
    147197            raise TypeError('Expecting string type for ' 
     
    156206     
    157207    def _getMyProxyClient(self): 
     208        """Get MyProxyClient instance 
     209         
     210        @rtype: myproxy.client.MyProxyClient 
     211        @return: MyProxyClient instance 
     212        """ 
    158213        return self.__myProxyClient 
    159214 
    160215    def _setMyProxyClient(self, value): 
     216        """Set MyProxyClient instance 
     217         
     218        @type value: myproxy.client.MyProxyClient 
     219        @param value: MyProxyClient instance 
     220        """ 
    161221        if not isinstance(value, MyProxyClient): 
    162222            raise TypeError('Expecting %r type for "myProxyClient" attribute ' 
     
    181241        environ[self.logonFuncEnvironKeyName] = self.myProxyLogon 
    182242         
    183         return self.__app(environ, start_response) 
     243        return self.app(environ, start_response) 
    184244     
    185245    @property 
     
    200260             
    201261            request = Request(environ) 
    202             certReqKey = self.__class__.CERTIFICATE_REQUST_POST_PARAM_KEYNAME 
     262            certReqKey = self.__class__.CERT_REQ_POST_PARAM_KEYNAME 
    203263            pemCertReq = request.POST.get(certReqKey) 
    204264            if pemCertReq is None: 
     
    208268                                                     httplib.BAD_REQUEST) 
    209269            log.debug("cert req = %r", pemCertReq) 
    210             getTrustRootsKey = self.__class__.GET_TRUSTROOTS_PARAM_KEYNAME 
    211             getTrustRoots = (request.postvars.get(getTrustRootsKey) ==  
    212                              self.__class__.GET_TRUSTROOTS_TRUE_STR) 
    213270             
    214271            # Expecting PEM encoded request 
     
    228285             
    229286            try: 
    230                 if getTrustRoots: 
    231                     trustRootsDict = self.myProxyClient.getTrustRoots() 
    232                      
    233                     trustRoots = '\n'.join([ 
    234                         "FILEDATA_%s=%s" % (fileName, fileContents)  
    235                         for fileName, fileContents in trustRootsDict.items() 
    236                     ]) 
    237                 else: 
    238                     trustRoots = '' 
    239                  
    240287                credentials = self.myProxyClient.logon(username,  
    241288                                                       password, 
     
    243290                status = self.getStatusMessage(httplib.OK) 
    244291                response = '\n'.join(credentials) 
    245                 response += '\n'+trustRoots 
    246292                 
    247293                start_response(status, 
     
    264310                raise # Trigger 500 Internal Server Error 
    265311             
    266  
    267          
    268312        return _myProxylogon 
    269  
    270     @staticmethod 
    271     def getStatusMessage(statusCode): 
    272         '''Make a standard status message for use with start_response 
    273         @type statusCode: int 
    274         @param statusCode: HTTP status code 
    275         @rtype: str 
    276         @return: status code with standard message 
    277         @raise KeyError: for invalid status code 
     313     
     314     
     315class MyProxyGetTrustRootsMiddlewareError(Exception): 
     316    """MyProxyGetTrustRootsMiddleware exception class""" 
     317     
     318     
     319class MyProxyGetTrustRootsMiddleware(MyProxyClientMiddlewareBase): 
     320    """HTTP client interface for MyProxy server Get Trust Roots method 
     321     
     322    It relies on a myproxy.server.wsgi.MyProxyClientMiddleware instance called  
     323    upstream in the WSGI stack to set up a MyProxyClient instance and make it  
     324    available in the environ to call its getTrustRoots method. 
     325    """ 
     326     
     327    # Options for ini file 
     328    CLIENT_ENV_KEYNAME_OPTNAME = \ 
     329        MyProxyClientMiddleware.CLIENT_ENV_KEYNAME_OPTNAME 
     330         
     331    PATH_OPTNAME = 'path'      
     332     
     333    DEFAULT_CLIENT_ENV_KEYNAME = \ 
     334        MyProxyClientMiddleware.DEFAULT_CLIENT_ENV_KEYNAME 
     335     
     336    DEFAULT_PATH = '/myproxy/get-trustroots' 
     337     
     338    # Option prefixes 
     339    PARAM_PREFIX = 'myproxy.getTrustRoots.' 
     340     
     341    __slots__ = ( 
     342        '__path', 
     343    ) 
     344     
     345    def __init__(self, app): 
     346        '''Create attributes 
     347         
     348        @type app: function 
     349        @param app: WSGI callable for next application in stack 
    278350        ''' 
    279         return '%d %s' % (statusCode, httplib.responses[statusCode]) 
    280      
     351        super(MyProxyGetTrustRootsMiddleware, self).__init__(app) 
     352        self.__path = None 
     353         
     354    @classmethod 
     355    def filter_app_factory(cls, app, global_conf, prefix=PARAM_PREFIX,  
     356                           **app_conf): 
     357        """Function following Paste filter app factory signature 
     358         
     359        @type app: callable following WSGI interface 
     360        @param app: next middleware/application in the chain       
     361        @type global_conf: dict         
     362        @param global_conf: PasteDeploy global configuration dictionary 
     363        @type prefix: basestring 
     364        @param prefix: prefix for configuration items 
     365        @type app_conf: dict         
     366        @param app_conf: PasteDeploy application specific configuration  
     367        dictionary 
     368        """ 
     369        app = cls(app) 
     370        app.parseConfig(prefix=prefix, **app_conf) 
     371        return app 
     372     
     373    def parseConfig(self, prefix=PARAM_PREFIX, **app_conf): 
     374        """Parse dictionary of configuration items updating the relevant  
     375        attributes of this instance 
     376         
     377        @type prefix: basestring 
     378        @param prefix: prefix for configuration items 
     379        @type app_conf: dict         
     380        @param app_conf: PasteDeploy application specific configuration  
     381        dictionary 
     382        """ 
     383        clientEnvKeyOptName = prefix + self.__class__.CLIENT_ENV_KEYNAME_OPTNAME 
     384                     
     385        self.clientEnvironKeyName = app_conf.get(clientEnvKeyOptName, 
     386                                    self.__class__.DEFAULT_CLIENT_ENV_KEYNAME) 
     387         
     388        pathOptName = prefix + self.__class__.PATH_OPTNAME 
     389        self.path = app_conf.get(pathOptName, self.__class__.DEFAULT_PATH) 
     390 
     391    def _getPath(self): 
     392        """Get URI path for get trust roots method 
     393        @rtype: basestring 
     394        @return: path for get trust roots method 
     395        """ 
     396        return self.__path 
     397 
     398    def _setPath(self, value): 
     399        """Set URI path for get trust roots method 
     400        @type value: basestring 
     401        @param value: path for get trust roots method 
     402        """ 
     403        if not isinstance(value, basestring): 
     404            raise TypeError('Expecting string type for "path"; got %r' %  
     405                            type(value)) 
     406         
     407        self.__path = value 
     408 
     409    path = property(fget=_getPath, fset=_setPath,  
     410                    doc="environ SCRIPT_NAME path which invokes the " 
     411                        "getTrustRoots method on this middleware") 
     412     
     413    def __call__(self, environ, start_response): 
     414        '''Get MyProxyClient instance from environ and call MyProxy  
     415        getTrustRoots method returning the response. 
     416         
     417        MyProxyClientMiddleware must be in place upstream in the WSGI stack 
     418         
     419        @type environ: dict 
     420        @param environ: WSGI environment variables dictionary 
     421        @type start_response: function 
     422        @param start_response: standard WSGI start response function 
     423        ''' 
     424        # Skip if path doesn't match 
     425        if environ['PATH_INFO'] != self.path: 
     426            return self.app(environ, start_response) 
     427         
     428        log.debug("MyProxyGetTrustRootsMiddleware.__call__ ...") 
     429         
     430        # Check method 
     431        requestMethod = environ.get('REQUEST_METHOD')              
     432        if requestMethod != 'GET': 
     433            response = "HTTP Request method not recognised" 
     434            log.error("HTTP Request method %r not recognised", requestMethod) 
     435            status = self.__class__.getStatusMessage(httplib.BAD_REQUEST) 
     436            start_response(status, 
     437                           [('Content-type', 'text/plain'), 
     438                            ('Content-length', str(len(response)))]) 
     439            return [response] 
     440         
     441        myProxyClient = environ[self.clientEnvironKeyName] 
     442        if not isinstance(myProxyClient, MyProxyClient): 
     443            raise TypeError('Expecting %r type for "myProxyClient" environ[%r] ' 
     444                            'attribute got %r' % (MyProxyClient,  
     445                                                  self.clientEnvironKeyName, 
     446                                                  type(myProxyClient))) 
     447         
     448        response = self._getTrustRoots(myProxyClient) 
     449        start_response(self.getStatusMessage(httplib.OK), 
     450                       [('Content-length', str(len(response))), 
     451                        ('Content-type', 'text/plain')]) 
     452 
     453        return [response] 
     454     
     455    @classmethod 
     456    def _getTrustRoots(cls, myProxyClient): 
     457        """Call getTrustRoots method on MyProxyClient instance retrieved from 
     458        environ and format and return a HTTP response 
     459         
     460        @type myProxyClient: myproxy.client.MyProxyClient 
     461        @param myProxyClient: MyProxyClient instance on which to call  
     462        getTrustRoots method 
     463         
     464        @rtype: basestring 
     465        @return: trust roots formatted as a HTTP response 
     466        """ 
     467        try: 
     468            trustRoots = myProxyClient.getTrustRoots() 
     469             
     470            # Serialise dict response 
     471            response = "\n".join(["%s=%s" % i for i in trustRoots.items()]) 
     472             
     473            return response 
     474                    
     475        except MyProxyClientError, e: 
     476            log.error("MyProxyClient.getTrustRoots raised an " 
     477                      "MyProxyClientError exception calling %r: %s",  
     478                      myProxyClient.hostname, 
     479                      traceback.format_exc()) 
     480             
     481        except socket.error, e: 
     482            raise MyProxyGetTrustRootsMiddlewareError("Socket error with " 
     483                                                      "MyProxy server %r: %s" %  
     484                                                      (myProxyClient.hostname,  
     485                                                       e)) 
     486        except Exception, e: 
     487            log.error("MyProxyClient.getTrustRoots raised an unknown exception " 
     488                      "calling %r: %s",  
     489                      myProxyClient.hostname, 
     490                      traceback.format_exc()) 
     491            raise # Trigger 500 Internal Server Error 
     492        
Note: See TracChangeset for help on using the changeset viewer.