Changeset 4606 for TI12-security


Ignore:
Timestamp:
11/12/08 17:08:31 (11 years ago)
Author:
pjkersha
Message:

#1004 Security Filter:

  • SSLClientAuthNMiddleware initial version near completion
Location:
TI12-security/trunk/python
Files:
2 edited

Legend:

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

    r4603 r4606  
    347347        return x509Cert 
    348348         
    349 #_____________________________________________________________________________ 
    350349# Alternative AttCert constructors 
    351 # 
    352350def X509CertRead(filePath): 
    353351    """Create a new X509 certificate read in from a file""" 
     
    358356    return x509Cert 
    359357 
    360  
    361 #_____________________________________________________________________________ 
    362358def X509CertParse(x509CertTxt): 
    363359    """Create a new X509 certificate from string of file content""" 
     
    369365 
    370366 
    371 #_____________________________________________________________________________ 
    372 class X509StackError(Exception): 
     367class X509StackError(X509CertError): 
    373368    """Error from X509Stack type""" 
    374369 
    375 #_____________________________________________________________________________ 
    376 class CertIssuerNotFound(X509StackError): 
     370class X509StackEmptyError(X509CertError): 
     371    """Expecting non-zero length X509Stack""" 
     372 
     373class X509CertIssuerNotFound(X509CertError): 
    377374    """Raise from verifyCertChain if no certificate can be found to verify the 
    378375    input""" 
    379376 
    380 class SelfSignedCert(X509StackError): 
     377class SelfSignedCert(X509CertError): 
    381378    """Raise from verifyCertChain if cert. is self-signed and  
    382379    rejectSelfSignedCert=True""" 
     380 
     381class X509CertInvalidSignature(X509CertError): 
     382    """X.509 Certificate has an invalid signature""" 
    383383        
    384 #_____________________________________________________________________________ 
    385384class X509Stack(object): 
    386385    """Wrapper for M2Crypto X509_Stack""" 
     
    479478            # populated 
    480479            if n2Validate == 0: 
    481                 raise X509StackError, \ 
    482                 "Empty stack and no x509Cert2Verify set: no cert.s to verify" 
     480                raise X509StackEmptyError("Empty stack and no x509Cert2Verify " 
     481                                          "set: no cert.s to verify") 
    483482 
    484483            x509Cert2Verify = self[-1] 
     
    505504                # signature of the cert. to be verified 
    506505                if not x509Cert2Verify.verify(issuerX509Cert.pubKey): 
    507                     X509CertError, 'Signature is invalid for cert. "%s"' % \ 
    508                                     x509Cert2Verify.dn 
     506                    X509CertInvalidSignature('Signature is invalid for cert. ' 
     507                                             '"%s"' % x509Cert2Verify.dn) 
    509508                 
    510509                # In the next iteration the issuer cert. will be checked: 
     
    525524                # If only one iteration occured then it must be a self 
    526525                # signed certificate 
    527                 raise SelfSignedCert, "Certificate is self signed" 
     526                raise SelfSignedCert("Certificate is self signed: [DN=%s]" % 
     527                                     issuerX509Cert.dn) 
    528528            
    529529            if not caX509Stack: 
     
    531531                          
    532532        elif not caX509Stack: 
    533             raise CertIssuerNotFound, \ 
    534                     'No issuer cert. found for cert. "%s"'%x509Cert2Verify.dn 
     533            raise X509CertIssuerNotFound('No issuer cert. found for cert. ' 
     534                                         '"%s"' % x509Cert2Verify.dn) 
    535535             
    536536        for caCert in caX509Stack: 
     
    542542        if issuerX509Cert:    
    543543            if not x509Cert2Verify.verify(issuerX509Cert.pubKey): 
    544                 X509CertError, 'Signature is invalid for cert. "%s"' % \ 
    545                                 x509Cert2Verify.dn 
     544                X509CertInvalidSignature('Signature is invalid for cert. "%s"'% 
     545                                         x509Cert2Verify.dn) 
    546546             
    547547            # Chain is validated through to CA cert 
    548548            return 
    549549        else: 
    550             raise CertIssuerNotFound, 'No issuer cert. found for cert. "%s"'%\ 
    551                                 x509Cert2Verify.dn 
     550            raise X509CertIssuerNotFound('No issuer cert. found for ' 
     551                                         'certificate "%s"'%x509Cert2Verify.dn) 
    552552         
    553553        # If this point is reached then an issuing cert is missing from the 
    554554        # chain         
    555         raise X509CertError, 'Can\'t find issuer cert "%s" for cert "%s"' % \ 
    556                           (x509Cert2Verify.issuer, x509Cert2Verify.dn)   
     555        raise X509CertIssuerNotFound('Can\'t find issuer cert "%s" for ' 
     556                                     'certificate "%s"' % 
     557                                     (x509Cert2Verify.issuer,  
     558                                      x509Cert2Verify.dn)) 
    557559 
    558560 
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/sslclientauthn.py

    r4603 r4606  
     1"""SSL Client Authentication Middleware 
     2 
     3Apply to SSL client authentication to configured URL paths. 
     4 
     5SSL Client certificate is expected to be present in environ as SSL_CLIENT_CERT 
     6key as set by standard Apache SSL. 
     7 
     8NERC Data Grid Project 
     9 
     10This software may be distributed under the terms of the Q Public License, 
     11version 1.0 or later. 
     12""" 
     13__author__ = "P J Kershaw" 
     14__date__ = "11/12/08" 
     15__copyright__ = "(C) 2008 STFC & NERC" 
     16__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     17__revision__ = "$Id$" 
    118import logging 
    219log = logging.getLogger(__name__) 
    3 from ndg.security.common.X509 import X509Cert 
     20import httplib 
     21from ndg.security.common.X509 import X509Cert, X509CertError 
    422 
    523class SSLClientAuthNMiddleware(object): 
     
    1735    isSSLClientCertSet = property(fget=_isSSLClientCertSet, 
    1836                                  doc="Check for client cert. set in environ") 
     37     
     38    _pathMatch = lambda self: self._path in self.pathMatchList 
     39    pathMatch = property(fget=_pathMatch, 
     40                         doc="Check for input path match to list of paths" 
     41                             "to which SSL client AuthN is to be applied") 
    1942     
    2043    def __init__(self, app, app_conf, prefix='', **local_conf): 
     
    5881            raise TypeError('Expecting int or string type for ' 
    5982                            '"errorResponseCode" attribute') 
     83             
     84        if self._errorResponseCode not in httplib.responses:  
     85            raise ValueError("Error response code [%d] is not recognised " 
     86                             "standard HTTP response code" %  
     87                             self._errorResponseCode)   
    6088             
    6189    errorResponseCode = property(fget=_getErrorResponseCode, 
     
    145173                
    146174    def __call__(self, environ, start_response): 
     175         
     176        self._path = environ.get('PATH_INFO').rstrip('/') 
     177         
     178        if not self.pathMatch: 
     179            return self._setResponse() 
     180         
    147181        self._environ = environ 
    148         self._path = environ.get('PATH_INFO').rstrip('/') 
    149          
    150         if self.sslClientCertSet: 
    151             self.verifyClientCert() 
    152              
     182         
     183        if not self.sslClientCertSet: 
     184            return self._setErrorResponse() 
     185             
     186        if self.isValidClientCert():             
     187            return self._setResponse() 
     188        else: 
     189            return self._setErrorResponse() 
     190             
     191    def _setResponse(self): 
    153192        if self._app: 
    154193            return self._app(environ, start_response) 
    155194        else: 
    156             response = 'No app set for SSLClientAuthNMiddleware' 
    157             start_response('200 OK', 
     195            response = 'No application set for SSLClientAuthNMiddleware' 
     196            status = '%d %s' % (404, httplib.responses[404]) 
     197            start_response(status, 
    158198                           [('Content-type', 'text/plain'), 
    159199                            ('Content-Length', str(len(response)))]) 
    160200            return response 
    161                    
    162     def verifyClientCert(self): 
     201 
     202    def _setErrorResponse(self, msg='Invalid SSL client certificate'): 
     203        response = msg 
     204        status = '%d %s' % (self.errorResponseCode,  
     205                            httplib.responses[self.errorResponseCode]) 
     206         
     207        start_response(status, 
     208                       [('Content-type', 'text/plain'), 
     209                        ('Content-Length', str(len(response)))]) 
     210        return response 
     211 
     212    def isValidClientCert(self): 
    163213        x509Cert = X509Cert.Parse(filePath) 
    164214         
    165          
     215        if len(self._caCertStack) == 0: 
     216            log.warning("No CA certificates set for Client certificate " 
     217                        "signature verification") 
     218        else: 
     219            try: 
     220                self._caCertStack.verifyCertChain(x509Cert2Verify=x509Cert) 
     221 
     222            except X509CertError, e: 
     223                log.info("Client certificate verification failed: %s" % e) 
     224                return False 
     225             
     226            except Exception, e: 
     227                log.error("Client certificate verification failed with " 
     228                          "unexpected error: %s" % e) 
     229                return False 
     230             
     231        return True 
     232         
     233 
     234# Utility functions to support Paste Deploy application and filter function 
     235# signatures         
    166236def filter_app_factory(app, app_conf, **local_conf): 
     237    '''Wrapper to SSLClientAuthNMiddleware for Paste Deploy filter''' 
    167238    return SSLClientAuthNMiddleware(app, app_conf, **local_conf) 
    168239    
    169240def app_factory(app_conf, **local_conf): 
     241    '''Wrapper to SSLClientAuthNMiddleware for Paste Deploy app''' 
    170242    return SSLClientAuthNMiddleware(None, app_conf, **local_conf) 
Note: See TracChangeset for help on using the changeset viewer.