Changeset 5770


Ignore:
Timestamp:
25/09/09 17:02:25 (10 years ago)
Author:
pjkersha
Message:

Adding SSL Client authentication step into authz_lite integration test. Broken redirecting back from authn step to requested resource.

Location:
TI12-security/trunk/python
Files:
7 edited

Legend:

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

    r5766 r5770  
    3131        'mountPath': '/', 
    3232    } 
    33  
    34     USERNAME_ENVIRON_KEYNAME = 'REMOTE_USER' 
    3533     
    3634    def __init__(self, app, app_conf, prefix='', **local_conf): 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/authn.py

    r5766 r5770  
    5555    return to URI between initiator and consumer classes""" 
    5656    RETURN2URI_ARGNAME = 'ndg.security.r' 
    57 #     
    58 #    _isAuthenticated = lambda self: \ 
    59 #            AuthnRedirectMiddleware.USERNAME_ENVIRON_KEYNAME in self.environ 
    60 #             
    61 #    isAuthenticated = property(fget=_isAuthenticated, 
    62 #                               doc='boolean for, "is user logged in?"') 
     57 
    6358 
    6459class AuthnRedirectInitiatorMiddleware(AuthnRedirectMiddleware): 
     
    192187            params = {} 
    193188         
     189        # Store the return URI query argument in a beaker session 
    194190        quotedReferrer = params.get(self.__class__.RETURN2URI_ARGNAME, '') 
    195191        referrerURI = urllib.unquote(quotedReferrer) 
     
    198194            session.save() 
    199195             
     196        # Check for a return URI setting in the beaker session and if the user 
     197        # is authenticated, redirect to this URL deleting the beaker session 
     198        # URL setting 
    200199        return2URI = session.get(self.__class__.RETURN2URI_ARGNAME)     
    201200        if self.isAuthenticated and return2URI: 
     
    207206 
    208207 
     208class AuthKitRedirectResponseMiddleware(AuthnRedirectResponseMiddleware): 
     209    """Overload isAuthenticated method in parent class to set Authenticated  
     210    state based on presence of AuthKit 'REMOTE_USER' environ variable 
     211    """ 
     212    _isAuthenticated = lambda self: \ 
     213        AuthnRedirectResponseMiddleware.USERNAME_ENVIRON_KEYNAME in self.environ 
     214         
     215    isAuthenticated = property(fget=_isAuthenticated, 
     216                               doc="Boolean indicating if AuthKit " 
     217                                   "'REMOTE_USER' environment variable is set") 
     218    def __init__(self, app, app_conf, **local_conf): 
     219        super(AuthKitRedirectResponseMiddleware, self).__init__(app, app_conf, 
     220                                                                **local_conf) 
     221    @NDGSecurityMiddlewareBase.initCall 
     222    def __call__(self, environ, start_response): 
     223        return super(AuthKitRedirectResponseMiddleware, self).__call__(environ, 
     224                                                                start_response) 
     225        
     226         
    209227class SessionHandlerMiddlewareConfigError(Exception): 
    210228    """Configuration errors from SessionHandlerMiddleware""" 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/openid/relyingparty/__init__.py

    r5766 r5770  
    2121from paste.request import parse_querystring, parse_formvars 
    2222import authkit.authenticate 
     23from authkit.authenticate.open_id import AuthOpenIDHandler 
    2324from beaker.middleware import SessionMiddleware 
    2425 
     
    125126        _app = app 
    126127        while True: 
    127             if isinstance(_app,authkit.authenticate.open_id.AuthOpenIDHandler): 
     128            if isinstance(_app, AuthOpenIDHandler): 
    128129                authOpenIDHandler = _app 
    129130                self._authKitVerifyPath = authOpenIDHandler.path_verify 
     
    170171        @return: response 
    171172        ''' 
     173        # Skip Relying Party interface set-up if user has been authenticated 
     174        # by other middleware 
     175        if 'REMOTE_USER' in environ: 
     176            log.debug("Found REMOTE_USER=%s in environ, AuthKit " 
     177                      "based authentication has taken place in other " 
     178                      "middleware, skipping OpenID Relying Party interface" % 
     179                      environ['REMOTE_USER']) 
     180            return self._app(environ, start_response) 
     181         
    172182        session = environ.get(self.sessionKey) 
    173183        if session is None: 
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/ssl.py

    r5757 r5770  
    1717log = logging.getLogger(__name__) 
    1818import os 
    19 import re # Pattern matching to determine which URI paths to apply SSL AuthN to 
     19# Pattern matching to determine which URI paths to apply SSL AuthN to and to 
     20# parse SSL certificate environment variable 
     21import re  
     22 
     23# Decode SSL certificate environment variable 
     24import base64         
    2025 
    2126from ndg.security.server.wsgi import NDGSecurityMiddlewareBase 
    2227from ndg.security.common.X509 import X509Stack, X509Cert, X509CertError, X500DN 
    2328from ndg.security.common.utils.classfactory import instantiateClass 
    24  
    25  
    26 class ClientCertVerificationInterface(object): 
    27     """Interface to enable customised verification of the client certificate  
    28     Distinguished Name""" 
    29     def __init__(self, **cfg): 
    30         """@type cfg: dict 
    31         @param cfg: configuration parameters, derived class may customise 
    32         """ 
    33         raise NotImplementedError() 
    34      
    35     def __call__(self, x509Cert): 
    36         """Derived class implementation should return True if the certificate 
    37         DN is valid, False otherwise 
    38         @type x509Cert: ndg.security.common.X509.X509Cert 
    39         @param x509Cert: client X.509 certificate received from Apache 
    40         environment""" 
    41         raise NotImplementedError() 
    42  
    43  
    44 class NoClientCertVerification(ClientCertVerificationInterface): 
    45     """Implementation of ClientCertVerificationInterface ignoring the  
    46     client certificate DN set""" 
    47     def __init__(self, **cfg): 
    48         pass 
    49      
    50     def __call__(self, x509Cert): 
    51         return True 
    52      
    53 class ClientCertVerificationList(ClientCertVerificationInterface): 
    54     """Implementation of ClientCertVerificationInterface matching the input 
    55     client certificate DN against a configurable list""" 
    56      
    57     def __init__(self, validDNList=[]): 
    58         self.validDNList = validDNList 
    59      
    60     def __call__(self, x509Cert): 
    61         inputDN = x509Cert.dn 
    62         return inputDN in self._validDNList 
    63      
    64     def _setValidDNList(self, dnList): 
    65         '''Read CA certificates from file and add them to an X.509 Cert. 
    66         stack 
    67          
    68         @type dnList: list or tuple 
    69         @param dnList: list of DNs to match against the input certificate DN 
    70         ''' 
    71          
    72         if isinstance(dnList, basestring): 
    73             # Try parsing a space separated list of file paths 
    74             dnList = dnList.split() 
    75              
    76         elif not isinstance(dnList, (list, tuple)): 
    77             raise TypeError('Expecting a list or tuple for "dnList"') 
    78  
    79         self._validDNList = [X500DN(dn) for dn in dnList] 
    80  
    81      
    82     def _getValidDNList(self): 
    83         return self._validDNList 
    84      
    85     validDNList = property(fset=_setValidDNList, 
    86                            fget=_getValidDNList, 
    87                            doc="list of permissible certificate Distinguished " 
    88                                "Names permissible") 
    8929     
    9030 
     
    10141    """ 
    10242    SSL_KEYNAME = 'HTTPS' 
    103     SSL_KEYVALUE = '1' 
    104      
    105     _isSSLRequest = lambda self: self.environ.get( 
    106                                     ApacheSSLAuthnMiddleware.SSL_KEYNAME) == \ 
    107                                     ApacheSSLAuthnMiddleware.SSL_KEYVALUE 
     43    SSL_KEYVALUES = ('1', 'on') 
     44     
     45    _isSSLRequest = lambda self: self.environ.get(self.sslKeyName) in \ 
     46                                    ApacheSSLAuthnMiddleware.SSL_KEYVALUES 
    10847    isSSLRequest = property(fget=_isSSLRequest, 
    10948                            doc="Is an SSL request boolean - depends on " 
     
    11150     
    11251    SSL_CLIENT_CERT_KEYNAME = 'SSL_CLIENT_CERT' 
     52    PEM_CERT_PREFIX = '-----BEGIN CERTIFICATE-----' 
    11353     
    11454    # Options for ini file 
     
    11656    CACERT_FILEPATH_LIST_OPTNAME = 'caCertFilePathList' 
    11757    CLIENT_CERT_DN_MATCH_LIST_OPTNAME = 'clientCertDNMatchList' 
     58    SSL_KEYNAME_OPTNAME = 'sslKeyName' 
     59    SSL_CLIENT_CERT_KEYNAME_OPTNAME = 'sslClientCertKeyName' 
    11860     
    11961    propertyDefaults = { 
    12062        RE_PATH_MATCH_LIST_OPTNAME: [], 
    12163        CACERT_FILEPATH_LIST_OPTNAME: [], 
    122         CLIENT_CERT_DN_MATCH_LIST_OPTNAME: [] 
     64        CLIENT_CERT_DN_MATCH_LIST_OPTNAME: [], 
     65        SSL_KEYNAME_OPTNAME: SSL_KEYNAME, 
     66        SSL_CLIENT_CERT_KEYNAME_OPTNAME: SSL_CLIENT_CERT_KEYNAME 
    12367    } 
    12468    propertyDefaults.update(NDGSecurityMiddlewareBase.propertyDefaults) 
    125          
    126     _isSSLClientCertSet = lambda self: bool(self.environ.get( 
    127                             ApacheSSLAuthnMiddleware.SSL_CLIENT_CERT_KEYNAME))  
    128     isSSLClientCertSet = property(fget=_isSSLClientCertSet, 
    129                                   doc="Check for client X.509 certificate " 
    130                                       "'SSL_CLIENT_CERT' setting in environ") 
    131      
    132     def __init__(self, app, global_conf, prefix='sslAuthn.', **app_conf): 
     69     
     70    PARAM_PREFIX = 'sslAuthn.' 
     71     
     72    def __init__(self, app, global_conf, prefix=PARAM_PREFIX, **app_conf): 
    13373         
    13474        super(ApacheSSLAuthnMiddleware, self).__init__(app,  
     
    13676                                                       prefix=prefix, 
    13777                                                       **app_conf) 
    138          
     78 
    13979        self.__caCertFilePathList = None 
    14080        self.__caCertStack = None 
    14181        self.__clientCertDNMatchList = None 
    14282        self.__clientCert = None 
    143          
    144         rePathMatchListVal = app_conf.get( 
    145                 ApacheSSLAuthnMiddleware.RE_PATH_MATCH_LIST_OPTNAME, '') 
     83        self.__sslClientCertKeyName = None 
     84        self.__sslKeyName = None 
     85         
     86        rePathMatchListParamName = prefix + \ 
     87                    ApacheSSLAuthnMiddleware.RE_PATH_MATCH_LIST_OPTNAME 
     88        rePathMatchListVal = app_conf.get(rePathMatchListParamName, '') 
     89         
    14690        self.rePathMatchList = [re.compile(r)  
    14791                                for r in rePathMatchListVal.split()] 
    148  
    149         self.caCertStack = app_conf.get( 
    150                 ApacheSSLAuthnMiddleware.CACERT_FILEPATH_LIST_OPTNAME, []) 
    151          
     92         
     93        caCertFilePathListParamName = prefix + \ 
     94                    ApacheSSLAuthnMiddleware.CACERT_FILEPATH_LIST_OPTNAME 
     95                         
     96        self.caCertStack = app_conf.get(caCertFilePathListParamName, []) 
     97         
     98        clientCertDNMatchListParamName = prefix + \ 
     99                    ApacheSSLAuthnMiddleware.CLIENT_CERT_DN_MATCH_LIST_OPTNAME 
     100                     
    152101        self.clientCertDNMatchList = app_conf.get( 
    153                 ApacheSSLAuthnMiddleware.CLIENT_CERT_DN_MATCH_LIST_OPTNAME, []) 
    154                  
     102                                        clientCertDNMatchListParamName, []) 
     103         
     104        sslClientCertParamName = prefix + \ 
     105                    ApacheSSLAuthnMiddleware.SSL_CLIENT_CERT_KEYNAME_OPTNAME    
     106        self.sslClientCertKeyName = app_conf.get(sslClientCertParamName,  
     107                            ApacheSSLAuthnMiddleware.SSL_CLIENT_CERT_KEYNAME) 
     108         
     109        sslKeyNameParamName = prefix + \ 
     110                    ApacheSSLAuthnMiddleware.SSL_KEYNAME_OPTNAME    
     111        self.sslKeyName = app_conf.get(sslKeyNameParamName,  
     112                                       ApacheSSLAuthnMiddleware.SSL_KEYNAME) 
     113 
     114    def _getSslClientCertKeyName(self): 
     115        return self.__sslClientCertKeyName 
     116 
     117    def _setSslClientCertKeyName(self, value): 
     118        if not isinstance(value, basestring): 
     119            raise TypeError('Expecting %r type for "sslClientCertKeyName"; ' 
     120                            'got %r' % (basestring, type(value))) 
     121        self.__sslClientCertKeyName = value 
     122 
     123    sslClientCertKeyName = property(_getSslClientCertKeyName,  
     124                                    _setSslClientCertKeyName,  
     125                                    doc="SslClientCertKeyName's Docstring") 
     126 
     127    def _getSslKeyName(self): 
     128        return self.__sslKeyName 
     129 
     130    def _setSslKeyName(self, value):        
     131        if not isinstance(value, basestring): 
     132            raise TypeError('Expecting %r type for "sslKeyName"; got %r' % 
     133                            (basestring, type(value))) 
     134        self.__sslKeyName = value 
     135 
     136    sslKeyName = property(_getSslKeyName,  
     137                          _setSslKeyName,  
     138                          doc="SslKeyName's Docstring") 
     139 
     140                
    155141    def _setCACertStack(self, caCertList): 
    156142        '''Read CA certificates from file and add them to an X.509 Cert. 
     
    254240                          doc="Client certificate for verification set by " 
    255241                              "isValidClientCert()") 
     242 
    256243     
    257244    @NDGSecurityMiddlewareBase.initCall          
     
    311298             
    312299        return False 
     300         
     301    def _isSSLClientCertSet(self): 
     302        """Check for SSL Certificate set in environ""" 
     303        sslClientCert = self.environ.get( 
     304                        self.sslClientCertKeyName, '') 
     305        return sslClientCert.startswith( 
     306                                    ApacheSSLAuthnMiddleware.PEM_CERT_PREFIX)  
     307         
     308    isSSLClientCertSet = property(fget=_isSSLClientCertSet, 
     309                                  doc="Check for client X.509 certificate " 
     310                                      "%r setting in environ" % 
     311                                      SSL_CLIENT_CERT_KEYNAME) 
    313312     
    314313    def isValidClientCert(self): 
    315         sslClientCert = self.environ[ 
    316                             ApacheSSLAuthnMiddleware.SSL_CLIENT_CERT_KEYNAME] 
    317         self.__clientCert = X509Cert.Parse(sslClientCert) 
     314        sslClientCert = self.environ[self.sslClientCertKeyName] 
     315         
     316        # Certificate string passed through a proxy has spaces in place of 
     317        # newline delimiters.  Fix by re-organising the string into a single  
     318        # line and remove the BEGIN CERTIFICATE / END CERTIFICATE delimiters. 
     319        # Then, treat as a base64 encoded string decoding and passing as DER 
     320        # format to the X.509 parser 
     321        x509CertPat = re.compile('(\s?-----[A-Z]+\sCERTIFICATE-----\s?)|\s+') 
     322        cert = x509CertPat.sub('', sslClientCert) 
     323        derCert = base64.decodestring(cert) 
     324        self.__clientCert = X509Cert.Parse(derCert, format=X509Cert.formatDER) 
    318325         
    319326        if len(self.caCertStack) == 0: 
     
    340347             
    341348        return True 
    342 #         
    343 #        # Check certificate Distinguished Name via  
    344 #        # ClientCertVerificationInterface object 
    345 #        return self.verifyClientCert(x509Cert) 
    346349     
    347350 
     
    373376 
    374377        elif not self.isSSLRequest: 
    375             log.warning("AuthKitSSLAuthnMiddleware: 'HTTPS' environment " 
     378            log.debug("AuthKitSSLAuthnMiddleware: 'HTTPS' environment " 
    376379                        "variable not found in environment; ignoring request") 
    377380                         
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/integration/authz_lite/securedapp.ini

    r5555 r5770  
    5555 
    5656# Set redirect for OpenID Relying Party in the Security Services app instance 
    57 authN.redirectURI = http://localhost:7443/verify 
     57#authN.redirectURI = http://localhost:7443/verify 
     58authN.redirectURI = https://localhost/verify 
    5859 
    5960# AuthKit Set-up 
     
    115116# Add a timestamp element to an outbound message 
    116117pip.wssecurity.addTimestamp=True 
     118 
     119# Logging configuration 
     120[loggers] 
     121keys = root, ndg 
     122 
     123[handlers] 
     124keys = console 
     125 
     126[formatters] 
     127keys = generic 
     128 
     129[logger_root] 
     130level = INFO 
     131handlers = console 
     132 
     133[logger_ndg] 
     134level = DEBUG 
     135handlers = 
     136qualname = ndg 
     137 
     138[handler_console] 
     139class = StreamHandler 
     140args = (sys.stderr,) 
     141level = NOTSET 
     142formatter = generic 
     143 
     144[formatter_generic] 
     145format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s 
     146datefmt = %H:%M:%S 
     147 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/integration/authz_lite/securityservices.ini

    r5738 r5770  
    5050document_root = %(here)s/openidprovider 
    5151 
     52# Ordering of filters and app is critical 
    5253[pipeline:main] 
    5354pipeline = wsseSignatureVerificationFilter  
     
    5758           AttributeAuthoritySamlSoapBindingFilter 
    5859                   SessionMiddlewareFilter 
     60                   SSLClientAuthenticationFilter 
     61                   SSLCientAuthKitFilter 
     62                   SSLCientAuthenticationRedirectFilter 
    5963                   OpenIDRelyingPartyFilter 
    6064                   OpenIDProviderApp 
     
    7680# Key name for keying into environ dictionary 
    7781environ_key = %(beakerSessionKeyName)s 
     82 
     83[filter:SSLCientAuthKitFilter] 
     84paste.filter_app_factory = authkit.authenticate:middleware 
     85 
     86# AuthKit Set-up 
     87setup.method=cookie 
     88 
     89# This cookie name and secret MUST agree with the name used by the  
     90# Authentication Filter used to secure a given app 
     91cookie.name=ndg.security.auth 
     92 
     93cookie.secret=9wvZObs9anUEhSIAnJNoY2iJq59FfYZr 
     94cookie.signoutpath = /logout 
     95 
     96# Disable inclusion of client IP address from cookie signature due to  
     97# suspected problem with AuthKit setting it when a HTTP Proxy is in place 
     98cookie.includeip = False 
     99 
     100# SSL Client Certificate based authentication is invoked if the client passed 
     101# a certificate with request.  This bypasses OpenID based authn. 
     102[filter:SSLClientAuthenticationFilter] 
     103paste.filter_app_factory = ndg.security.server.wsgi.ssl:AuthKitSSLAuthnMiddleware 
     104prefix = ssl. 
     105ssl.caCertFilePathList = %(testConfigDir)s/ca/ndg-test-ca.crt 
     106 
     107# HTTP_ prefix is set when passed through a proxy 
     108ssl.sslKeyName = HTTP_HTTPS 
     109ssl.sslClientCertKeyName = HTTP_SSL_CLIENT_CERT 
     110 
     111# Set the URI pattern match here to interrupt a redirect to the OpenID Relying  
     112# Party from the service running over HTTP and see if a client certificate has  
     113# been set 
     114ssl.rePathMatchList = ^/verify.* 
    78115 
    79116[filter:OpenIDRelyingPartyFilter] 
     
    134171#authkit.openid.urltouser =  
    135172 
     173# Redirect to original requested URI following SSL Client Authentication.  This 
     174# filter must be placed AFTER the AuthKit cookie setting middleware.  In this 
     175# case its configured in the OpenIDRelyingPartyMiddleware filter.  If the 
     176# OpenID Relying Party filter is removed, a separate AuthKit middleware entry 
     177# would need to be made so that this redirect filter can still function 
     178[filter:SSLCientAuthenticationRedirectFilter] 
     179paste.filter_app_factory = ndg.security.server.wsgi.authn:AuthKitRedirectResponseMiddleware 
     180prefix = ssl. 
     181ssl.sessionKey = %(beakerSessionKeyName)s 
     182 
    136183#______________________________________________________________________________ 
    137184# OpenID Provider WSGI Settings 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/wsgi/authn/ssl-test.ini

    r5766 r5770  
    6666paste.filter_app_factory = ndg.security.server.wsgi.ssl:AuthKitSSLAuthnMiddleware 
    6767prefix = ssl. 
    68 caCertFilePathList = %(testConfigDir)s/ca/ndg-test-ca.crt 
    69 clientCertVerificationClassName =  
    70 rePathMatchList = ^/ssl-client-authn.* 
     68ssl.caCertFilePathList = %(testConfigDir)s/ca/ndg-test-ca.crt 
     69ssl.rePathMatchList = ^/ssl-client-authn.* 
Note: See TracChangeset for help on using the changeset viewer.