Ignore:
Timestamp:
09/06/09 16:41:23 (11 years ago)
Author:
pjkersha
Message:

Added code for validation of OpenID Provider by Relying Party using M2Crypto.m2urllib2 for SSL peer authN

Location:
TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/relyingparty
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/openid/relyingparty/__init__.py

    r5355 r5372  
    1717import urllib # decode quoted URI in query arg 
    1818from urlparse import urlsplit, urlunsplit 
     19 
    1920 
    2021from paste.request import parse_querystring, parse_formvars 
     
    4243    middleware to return to following OpenID sign in. 
    4344    ''' 
     45    sslPropertyDefaults = { 
     46        'certFilePath': '', 
     47        'priKeyFilePath': None, 
     48        'priKeyPwd': None, 
     49        'caCertDirPath': None, 
     50        'providerWhitelistFilePath': None 
     51    } 
    4452    propertyDefaults = { 
     53        'sslPeerCertAuthN': True, 
    4554        'signinInterfaceMiddlewareClass': None, 
    4655        'baseURL': '', 
    4756        'sessionKey': 'beaker.session.ndg.security' 
    4857    } 
     58    propertyDefaults.update(sslPropertyDefaults) 
    4959    propertyDefaults.update(NDGSecurityMiddlewareBase.propertyDefaults) 
    5060     
    5161    def __init__(self, app, global_conf, prefix='openid.relyingparty.',  
    5262                 **app_conf): 
    53         """Add AuthKit and Beaker middleware dependencies to WSGI stack 
     63        """Add AuthKit and Beaker middleware dependencies to WSGI stack and  
     64        set-up SSL Peer Certificate Authentication of OpenID Provider set by 
     65        the user 
    5466         
    5567        @type app: callable following WSGI interface signature 
     
    6476        format of propertyDefaults class variable"""     
    6577 
    66              
     78        # Default to set SSL peer cert authN where no flag is set in the config 
     79        # To override, it must explicitly be set to False in the config 
     80        if app_conf.get('sslPeerCertAuthN', 'true').lower() != 'false': 
     81             
     82            # Set parameters for SSL client connection to OpenID Provider Yadis 
     83            # retrieval URI 
     84            for paramName in self.__class__.sslPropertyDefaults: 
     85                paramDefault = self.__class__.sslPropertyDefaults[paramName] 
     86                setattr(self,  
     87                        paramName,  
     88                        app_conf.get(prefix+paramName, paramDefault)) 
     89                 
     90            self._initSSLPeerAuthN() 
     91         
    6792        # Check for sign in template settings 
    6893        if prefix+'signinInterfaceMiddlewareClass' in app_conf: 
     
    228253        return self._app(environ, _start_response) 
    229254 
     255    def _initSSLPeerAuthN(self): 
     256        """Initialise M2Crypto based urllib2 HTTPS handler to enable SSL  
     257        authentication of OpenID Providers""" 
     258        log.info("Setting parameters for SSL Authentication of OpenID " 
     259                 "Provider ...") 
     260         
     261        def verifySSLPeerCertCallback(preVerifyOK, x509StoreCtx): 
     262            '''SSL verify callback function used to control the behaviour when  
     263            the SSL_VERIFY_PEER flag is set 
     264             
     265            http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html 
     266             
     267            @type preVerifyOK: int 
     268            @param preVerifyOK: If a verification error is found, this parameter  
     269            will be set to 0 
     270            @type x509StoreCtx: M2Crypto.X509_Store_Context 
     271            @param x509StoreCtx: locate the certificate to be verified and perform  
     272            additional verification steps as needed 
     273            @rtype: int 
     274            @return: controls the strategy of the further verification process.  
     275            - If verify_callback returns 0, the verification process is immediately  
     276            stopped with "verification failed" state. If SSL_VERIFY_PEER is set,  
     277            a verification failure alert is sent to the peer and the TLS/SSL  
     278            handshake is terminated.  
     279            - If verify_callback returns 1, the verification process is continued.  
     280            If verify_callback always returns 1, the TLS/SSL handshake will not be  
     281            terminated with respect to verification failures and the connection  
     282            will be established. The calling process can however retrieve the error 
     283            code of the last verification error using SSL_get_verify_result or  
     284            by maintaining its own error storage managed by verify_callback. 
     285            ''' 
     286            if preVerifyOK == 0: 
     287                # Something is wrong with the certificate don't bother proceeding 
     288                # any further 
     289                log.error("verifyCallback: pre-verify OK flagged an error " 
     290                          "with the peer certificate, returning error state " 
     291                          "to caller ...") 
     292                return preVerifyOK 
     293             
     294            x509Cert = x509StoreCtx.get_current_cert() 
     295            x509Cert.get_subject() 
     296            x509CertChain = x509StoreCtx.get1_chain() 
     297            for cert in x509CertChain: 
     298                subject = cert.get_subject() 
     299                dn = subject.as_text() 
     300                log.debug("verifyCallback: dn = %r", dn) 
     301                 
     302            # If all is OK preVerifyOK will be 1.  Return this to the caller to 
     303            # that it's OK to proceed 
     304            return preVerifyOK 
     305            
     306        # Imports here so that if SSL Auth is not set the app will not need  
     307        # these packages  
     308        import urllib2 
     309        from M2Crypto import SSL 
     310        from M2Crypto.m2urllib2 import build_opener 
     311        from openid.fetchers import setDefaultFetcher, Urllib2Fetcher 
     312         
     313        # Create a context specifying verification of the peer but with an 
     314        # additional callback function 
     315        ctx = SSL.Context() 
     316        ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert,  
     317                       9,  
     318                       callback=verifySSLPeerCertCallback) 
     319 
     320        # Point to a directory containing CA certificates.  These must be named 
     321        # in their hashed form as expected by the OpenSSL API.  Use c_rehash 
     322        # utility to generate names or in the CA directory: 
     323        # 
     324        # $ for i in *.crt *.pem; do ln -s $i $(openssl x509 -hash -noout -in $i).0; done 
     325        ctx.load_verify_locations(capath=self.caCertDirPath) 
     326         
     327        # Load this client's certificate and private key to enable the peer  
     328        # OpenID Provider to authenticate it 
     329        ctx.load_cert(self.certFilePath,  
     330                      keyfile=self.priKeyFilePath,  
     331                      callback=lambda *arg, **kw: self.priKeyPwd) 
     332     
     333        setDefaultFetcher(Urllib2Fetcher()) 
     334         
     335        log.debug("Adding the M2Crypto SSL handler to urllib2's list of " 
     336                  "handlers...") 
     337        urllib2.install_opener(build_opener(ssl_context=ctx)) 
    230338     
    231339class SigninInterfaceError(Exception): 
Note: See TracChangeset for help on using the changeset viewer.