Changeset 4841 for TI12-security


Ignore:
Timestamp:
19/01/09 16:42:25 (11 years ago)
Author:
pjkersha
Message:

More work on security filter pipeline.

Location:
TI12-security/trunk/python
Files:
3 added
6 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/X509.py

    r4838 r4841  
    5252        if filePath is not None: 
    5353            if not isinstance(filePath, basestring): 
    54                 raise X509CertError( 
    55                         "Certificate File Path input must be a valid string") 
     54                raise X509CertError("Certificate File Path input must be a " 
     55                                    "valid string") 
    5656             
    5757        self.__filePath = filePath             
     
    6262        if m2CryptoX509: 
    6363            self.__setM2CryptoX509(m2CryptoX509) 
    64          
     64        else: 
     65            self.__m2CryptoX509 = None 
    6566 
    6667    def read(self,  
  • TI12-security/trunk/python/ndg.security.common/ndg/security/common/utils/classfactory.py

    r4840 r4841  
    6868            # Import module name specified in properties file 
    6969            importModule=__import__(moduleName,globals(),locals(),[className]) 
     70            components = moduleName.split('.') 
     71            for components in components[1:]: 
     72                module = getattr(module, part) 
    7073 
    71             #importClass = getattr(importModule, className) 
    72             importClass = eval('importModule.'+className) 
     74            importClass = getattr(module, className) 
     75            #importClass = eval('importModule.'+className) 
    7376        finally: 
    7477            # revert back to original sys path, if necessary 
  • TI12-security/trunk/python/ndg.security.server/ndg/__init__.py

    r4839 r4841  
    1313__author__ = "P J Kershaw" 
    1414__date__ = "27/10/06" 
    15 __copyright__ = """(C) 2009 Science and Technology Facilities Council" 
     15__copyright__ = "(C) 2009 Science and Technology Facilities Council" 
    1616__license__ = "BSD - see LICENSE file in top-level directory" 
    1717__contact__ = "Philip.Kershaw@stfc.ac.uk" 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/__init__.py

    r4840 r4841  
    1212import httplib 
    1313 
     14 
    1415class NDGSecurityMiddlewareBase(object): 
    1516    """Base class for NDG Security Middleware classes""" 
    16     propertyDefaults = {} 
     17    propertyDefaults = { 
     18        'mountPath': '/', 
     19    } 
    1720     
    1821    def __init__(self, app, app_conf, prefix='', **local_conf): 
     
    2326        ''' 
    2427        self._app = app 
     28        self._environ = None 
     29        self._pathInfo = None 
     30        self._path = None 
     31         
    2532        opt = self.__class__.propertyDefaults.copy() 
    2633         
     
    4249            if not name.startswith('_'): 
    4350                setattr(self, name, val) 
    44                          
     51 
     52    def _initCall(self, environ): 
     53        """Call from derived class' __call__() to set environ and path 
     54        attributes""" 
     55        self.environ = environ 
     56        self.setPathInfo() 
     57        self.setPath() 
     58          
    4559    def _setResponse(self,  
    4660                     environ,  
     
    139153             
    140154            self._pathInfo = environ['PATH_INFO'] 
     155            if self._pathInfo != '/': 
     156                self._pathInfo.rstrip('/') 
    141157         
    142158    def _getPathInfo(self): 
     
    147163                        doc="URL path as assigned to PATH_INFO environ key") 
    148164 
     165 
     166    def setPath(self, path=None): 
     167        if path: 
     168            self._path = path 
     169        else: 
     170            self._path = self.mountPath.rstrip() + self._pathInfo 
     171            if self._path != '/': 
     172                self._path.rstrip('/') 
     173         
     174    def _getPath(self): 
     175        return self._path 
     176     
     177    path = property(fget=_getPath, 
     178                        fset=setPath, 
     179                        doc="Full URL path minus domain name - equivalent to " 
     180                            "self.mountPath PATH_INFO environ setting") 
     181 
    149182    def _setEnviron(self, environ): 
    150183        self._environ = environ 
     
    160193class NDGSecurityPathFilter(NDGSecurityMiddlewareBase): 
    161194    """Specialization of NDG Security Middleware to enable filtering based on 
    162     PATH_INFO""" 
     195    PATH_INFO 
     196     
     197    B{This class must be run under Apache mod_wsgi} 
     198 
     199    - Apache SSLOptions directive StdEnvVars option must be set 
     200    """ 
    163201    propertyDefaults = { 
    164202        'errorResponseCode': 401, 
    165203        'serverName': None, 
    166         'mountPath': '', 
    167         'pathMatchList': '/' 
     204        'pathMatchList': ['/'] 
    168205    } 
    169206    propertyDefaults.update(NDGSecurityMiddlewareBase.propertyDefaults) 
     
    173210                         doc="Check for input path match to list of paths" 
    174211                             "to which this middleware is to be applied") 
     212     
     213    sslServerDNKeyName = 'SSL_SERVER_S_DN' 
     214 
     215    _isSSLRequest = lambda self: bool(self.environ.get( 
     216                                NDGSecurityPathFilter.sslServerDNKeyName)) 
     217    isSSLRequest = property(fget=_isSSLRequest, 
     218                            doc="Approximation for is an SSL request boolean " 
     219                                "- depends on Apache config SSLOptions " 
     220                                "StdEnvVars option being set") 
    175221     
    176222    def __init__(self, *arg, **kw): 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/pep/__init__.py

    r4838 r4841  
    1818 
    1919class PEPMiddleware(NDGSecurityPathFilter): 
    20     
     20    """WSGI Middleware to enforce a security policy for a given request URL 
     21    """    
    2122    def __init__(self, *arg, **kw): 
    2223        log.debug("Initialising PEPMiddleware ...") 
    2324        super(PEPMiddleware, self).__init__(*arg, **kw) 
    2425        self.charset = '; charset=utf-8' 
    25      
     26 
    2627    def __call__(self, environ, start_response): 
    27         log.info("Calling PEP middleware ...") 
    28         self.environ = environ 
    29         self.setPathInfo() 
    30         log.error("environ=%s" % environ) 
    31         print >> environ['wsgi.errors'], "environ=%s" % environ 
     28        log.debug("Calling PEPMiddleware.__call__ ...") 
     29        self._initCall(environ) 
    3230         
    3331        # TODO: Is a security session set? 
    34          
     32        if True: 
     33            if self.isSSLRequest: 
     34                response = self._redirectFromHTTPS2HTTP(start_response) 
     35                if response is not None: 
     36                    return response 
     37                 
    3538        # Is this requested URL secured? 
    3639        if self.pathMatch: 
     
    4144            # User is logged in - Redirect to HTTP based URL and complete 
    4245            # Policy enforcement 
    43             response = self._redirectFromHTTPS2HTTP(start_response) 
    44             if response is not None: 
    45                 return response 
     46            if self.isSSLRequest: 
     47                response = self._redirectFromHTTPS2HTTP(start_response) 
     48                if response is not None: 
     49                    return response 
    4650             
    4751        return self._setResponse(environ, start_response) 
    4852 
    4953    def _redirectFromHTTPS2HTTP(self, start_response): 
    50         sslServerDN = self.environ.get('SSL_SERVER_S_DN') 
     54        sslServerDN = self.environ.get(PEPMiddleware.sslServerDNKeyName) 
     55 
    5156        if sslServerDN is not None: 
    5257            if self.serverName: 
     
    5560                dn = X500DN.Parse(sslServerDN) 
    5661                serverName = dn['CN'] 
    57              
    5862            url = 'http://' + serverName + self.mountPath + self.pathInfo 
    5963            print >> self.environ['wsgi.errors'], "redirecting to [%s]" % url 
     
    7579                        ('Location', url)]) 
    7680        return [] 
     81 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/ssl.py

    r4838 r4841  
    1616__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1717__revision__ = "$Id$" 
    18 __license__ = "BSD" 
     18__license__ = "BSD - see top-level directory for LICENSE file" 
    1919import logging 
    2020log = logging.getLogger(__name__) 
     
    2727class SSLClientAuthNMiddleware(NDGSecurityPathFilter): 
    2828    '''Apply to SSL client authentication to configured URL paths. 
     29     
     30    B{This class must be run under Apache mod_wsgi} 
    2931 
    30     SSL Client certificate is expected to be present in environ as  
    31     SSL_CLIENT_CERT key as set by standard Apache SSL.''' 
     32    - SSL Client certificate is expected to be present in environ as  
     33    SSL_CLIENT_CERT key as set by Apache SSL with ExportCertData option to 
     34    SSLOptions directive enabled.''' 
    3235 
    3336    sslClientCertKeyName = 'SSL_CLIENT_CERT' 
     
    3740    } 
    3841    propertyDefaults.update(NDGSecurityPathFilter.propertyDefaults) 
    39      
    40     _isSSLClientCertSet = lambda self: bool(self._environ.get( 
     42         
     43    _isSSLClientCertSet = lambda self: bool(self.environ.get( 
    4144                                SSLClientAuthNMiddleware.sslClientCertKeyName))  
    4245    isSSLClientCertSet = property(fget=_isSSLClientCertSet, 
     
    6972                                      "peer certificate must validate against " 
    7073                                      "one") 
    71     def _getPathMatchList(self): 
    72         return self._pathMatchList 
    73      
    74     def _setPathMatchList(self, pathList): 
    75         ''' 
    76         @type pathList: list or tuple 
    77         @param pathList: list of URL paths to apply SSL client authentication  
    78         to. Paths are relative to the point at which this middleware is mounted 
    79         as set in environ['PATH_INFO'] 
    80         ''' 
    81         # TODO: refactor to: 
    82         # * enable reading of path list from a database or some other  
    83         # configuration source. 
    84         # * enable some kind of pattern matching for paths 
    85          
    86         if isinstance(pathList, basestring): 
    87             # Try parsing a space separated list of file paths 
    88              self._pathMatchList = pathList.split() 
    89              
    90         elif not isinstance(pathList, (list, tuple)): 
    91             raise TypeError('Expecting a list or tuple for "pathMatchList"') 
    92         else: 
    93             self._pathMatchList = pathList 
    94              
    95     pathMatchList = property(fget=_getPathMatchList, 
    96                              fset=_setPathMatchList, 
    97                              doc='List of URL paths to which to apply SSL ' 
    98                                  'client authentication') 
    9974                
    10075    def __call__(self, environ, start_response): 
    10176         
    102         self._path = environ.get('PATH_INFO') 
    103         if self._path != '/': 
    104             self._path.rstrip('/') 
     77        log.debug("Calling SSLClientAuthNMiddleware.__call__ ...") 
     78        self._initCall(environ) 
    10579         
    106         self._environ = environ 
    107          
     80        if not self.isSSLRequest: 
     81            log.debug("ignoring path [%s] - assuming non-SSL request" %  
     82                      self.path) 
     83            return self._setResponse(environ, start_response) 
     84             
    10885        if not self.pathMatch: 
    109             log.debug("ignoring path [%s]" % self._path) 
     86            log.debug("ignoring path [%s]" % self.path) 
    11087            return self._setResponse(environ, start_response) 
    11188                     
    112         if not self.isSSLClientCertSet: 
    113             log.error("No SSL Client path set for request to [%s]"%self._path) 
     89        elif not self.isSSLClientCertSet: 
     90            log.error("No SSL Client path set for request to [%s]" % self.path) 
    11491            return self._setErrorResponse(environ, start_response, 
    11592                                          msg='No client SSL Certificate set') 
     
    125102                     notFoundMsg='No application set for ' 
    126103                                 'SSLClientAuthNMiddleware'): 
    127         super(SSLClientAuthNMiddleware, self)._setResponse(environ,  
    128                                                            start_response, 
    129                                                            notFoundMsg=msg) 
     104        return super(SSLClientAuthNMiddleware, self)._setResponse(environ,  
     105                                                       start_response, 
     106                                                       notFoundMsg=notFoundMsg) 
    130107 
    131108    def _setErrorResponse(self,  
     
    133110                          start_response, 
    134111                          msg='Invalid SSL client certificate'): 
    135         super(SSLClientAuthNMiddleware, self)._setResponse(environ,  
     112        return super(SSLClientAuthNMiddleware, self)._setResponse(environ,  
    136113                                                   start_response, 
    137114                                                   msg=msg, 
     
    159136             
    160137        return True 
    161          
    162  
    163 # Utility functions to support Paste Deploy application and filter function 
    164 # signatures         
    165 def filter_app_factory(app, app_conf, **local_conf): 
    166     '''Wrapper to SSLClientAuthNMiddleware for Paste Deploy filter''' 
    167     return SSLClientAuthNMiddleware(app, app_conf, **local_conf) 
    168     
    169 def app_factory(app_conf, **local_conf): 
    170     '''Wrapper to SSLClientAuthNMiddleware for Paste Deploy app''' 
    171     return SSLClientAuthNMiddleware(None, app_conf, **local_conf) 
Note: See TracChangeset for help on using the changeset viewer.