Changeset 6686 for TI12-security


Ignore:
Timestamp:
05/03/10 16:56:35 (10 years ago)
Author:
pjkersha
Message:

Refactoring Attribute Authority to remove NDG Attribute Certificate and role mapping code.

Location:
TI12-security/trunk/NDGSecurity/python
Files:
1 deleted
9 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/NDGSecurity/python/.pydevproject

    r6673 r6686  
    55<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property> 
    66<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property> 
     7<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> 
     8<path>/ndg_security_python/ndg_security_common</path> 
     9<path>/ndg_security_python/ndg_security_server</path> 
     10<path>/ndg_security_python/ndg_security_test</path> 
     11</pydev_pathproperty> 
     12<pydev_pathproperty name="org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH"> 
     13<path>/home/pjkersha/workspace/ndg_saml</path> 
     14<path>/home/pjkersha/workspace/MyProxyClient</path> 
     15<path>/home/pjkersha/workspace/AuthKit/trunk</path> 
     16</pydev_pathproperty> 
    717</pydev_project> 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/utils/factory.py

    r6572 r6686  
    44NERC DataGrid project 
    55""" 
    6 __author__ = "C Byrom - Tessella" 
    7 __date__ = "28/08/08" 
    8 __copyright__ = "(C) 2009 Science and Technology Facilities Council" 
     6__author__ = "Philip Kershaw" 
     7__date__ = "15/02/10" 
     8__copyright__ = "(C) 2010 Science and Technology Facilities Council" 
    99__license__ = "BSD - see LICENSE file in top-level directory" 
    1010__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     
    2828    if objectName is None: 
    2929        if ':' in moduleName: 
    30             # Support PAste style import syntax with rhs of colon denoting  
     30            # Support Paste style import syntax with rhs of colon denoting  
    3131            # module content to import 
    3232            _moduleName, objectName = moduleName.rsplit(':', 1) 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/attributeauthority.py

    r6673 r6686  
    3636 
    3737from ndg.security.common.saml_utils.esg import EsgSamlNamespaces 
     38from ndg.security.common.X509 import X500DN 
    3839from ndg.security.common.utils import TypedList 
    3940from ndg.security.common.utils.classfactory import instantiateClass 
     
    5455    def __init__(self, msg): 
    5556        log.error(msg) 
    56         Exception.__init__(self, msg) 
    57          
    58          
    59 class AttributeAuthorityAccessDenied(AttributeAuthorityError): 
    60     """NDG Attribute Authority - access denied exception. 
    61  
    62     Raise from getAttCert method where no roles are available for the user 
    63     but that the request is otherwise valid.  In all other error cases raise 
    64     AttributeAuthorityError"""    
    65      
    66      
    67 class AttributeAuthorityNoTrustedHosts(AttributeAuthorityError): 
    68     """Raise from getTrustedHosts if there are no trusted hosts defined in 
    69     the map configuration""" 
    70  
    71  
    72 class AttributeAuthorityNoMatchingRoleInTrustedHosts(AttributeAuthorityError): 
    73     """Raise from getTrustedHosts if there is no mapping to any of the  
    74     trusted hosts for the given input role name""" 
     57        Exception.__init__(self, msg)  
    7558 
    7659 
     
    11295    attributeInterfacePropertyDefaults = { 
    11396        'modFilePath':  '', 
    114         'modName':      '', 
    11597        'className':    '' 
    11698    } 
     
    120102    # in the config 
    121103    propertyDefaults = {  
    122         'name':                         '', 
    123         'attCertLifetime':              -1, 
    124         'attCertNotBeforeOff':          0., 
    125         'clockSkew':                    timedelta(seconds=0.), 
     104        'issuerName':                   '', 
     105        'assertionLifetime':              -1, 
    126106        'dnSeparator':                  '/', 
    127107        ATTRIBUTE_INTERFACE_KEYNAME:    attributeInterfacePropertyDefaults 
    128108    } 
    129      
    130     mapConfigHostDefaults = { 
    131         'siteName':                 None, 
    132         'aaURI':                    NotImplemented, 
    133         'aaDN':                     NotImplemented, 
    134         'loginURI':                 NotImplemented, 
    135         'loginServerDN':            NotImplemented, 
    136         'loginRequestServerDN':     NotImplemented 
    137     } 
    138109 
    139110    def __init__(self): 
     
    145116            setattr(self, '_AttributeAuthority__%s' % name, val) 
    146117         
    147         self.__caCertFilePathList = TypedList(basestring) 
    148          
    149118        self.__propFilePath = None         
    150119        self.__propFileSection = 'DEFAULT' 
    151120        self.__propPrefix = '' 
    152                  
    153         self.__cert = None 
    154          
    155         # Issuer details - serialise using the separator string set in the 
    156         # properties file 
    157         self.__issuer = None 
    158         self.__issuerSerialNumber = None 
    159         self.__attCertLog = None 
    160         self.__name = None 
    161121         
    162122        self.__attributeInterfaceCfg = {} 
    163123 
    164     def _getCert(self): 
    165         return self.__cert 
    166  
    167     def _getIssuer(self): 
    168         return self.__issuer 
    169  
    170     def _getIssuerSerialNumber(self): 
    171         return self.__issuerSerialNumber 
    172  
    173     def _getName(self): 
    174         return self.__name 
    175  
    176     def _getAttCertLifetime(self): 
    177         return self.__attCertLifetime 
    178  
    179     def _getAttCertNotBeforeOff(self): 
    180         return self.__attCertNotBeforeOff 
    181  
    182     def _getClockSkew(self): 
    183         return self.__clockSkew 
     124    def _getAssertionLifetime(self): 
     125        return self.__assertionLifetime 
    184126 
    185127    def _getAttributeInterface(self): 
    186128        return self.__attributeInterface 
    187129 
    188     def _setCert(self, value): 
    189         if not isinstance(value, X509Cert): 
    190             raise TypeError('Expecting %r type for "cert"; got %r' % 
    191                             (X509Cert, type(value))) 
    192              
    193         self.__cert = value 
    194  
    195     def _setIssuer(self, value): 
    196         self.__issuer = value 
    197  
    198     def _setIssuerSerialNumber(self, value): 
    199         if not isinstance(value, (long, int)): 
    200             raise TypeError('Expecting long or int type for "name"; got %r' % 
    201                             type(value)) 
    202         self.__issuerSerialNumber = value 
    203  
    204     def _setName(self, value): 
    205         if not isinstance(value, basestring): 
    206             raise TypeError('Expecting string type for "name"; got %r' % 
    207                             type(value)) 
    208         self.__name = value 
    209  
    210     def _setAttCertLifetime(self, value): 
     130    def _setAssertionLifetime(self, value): 
    211131        if isinstance(value, float): 
    212             self.__attCertLifetime = value 
     132            self.__assertionLifetime = value 
    213133             
    214134        elif isinstance(value, (basestring, int, long)): 
    215             self.__attCertLifetime = float(value) 
     135            self.__assertionLifetime = float(value) 
    216136        else: 
    217137            raise TypeError('Expecting float, int, long or string type for ' 
    218                             '"attCertLifetime"; got %r' % type(value)) 
    219  
    220     def _setAttCertNotBeforeOff(self, value): 
    221         if isinstance(value, float): 
    222             self.__attCertNotBeforeOff = value 
    223              
    224         elif isinstance(value, (basestring, int, long)): 
    225             self.__attCertNotBeforeOff = float(value) 
    226         else: 
    227             raise TypeError('Expecting float, int, long or string type for ' 
    228                             '"attCertNotBeforeOff"; got %r' % type(value)) 
    229  
    230     def _setClockSkew(self, value): 
    231         if isinstance(value, (float, int, long)): 
    232             self.__clockSkew = timedelta(seconds=value) 
    233              
    234         elif isinstance(value, basestring): 
    235             self.__clockSkew = timedelta(seconds=float(value)) 
    236         else: 
    237             raise TypeError('Expecting float, int, long or string type for ' 
    238                             '"clockSkew"; got %r' % type(value)) 
     138                            '"assertionLifetime"; got %r' % type(value)) 
    239139 
    240140    def _setAttributeInterface(self, value): 
     
    245145             
    246146        self.__attributeInterface = value 
    247  
    248     def _get_caCertFilePathList(self): 
    249         return self.__caCertFilePathList 
    250  
    251     def _set_caCertFilePathList(self, val): 
    252         if not isinstance(val, (list, tuple)): 
    253             raise TypeError('Expecting list or tuple type for ' 
    254                             '"caCertFilePathList"; got %r' % type(val)) 
    255              
    256         # Overwrite any original settings 
    257         self.__caCertFilePathList = TypedList(basestring) 
    258          
    259         # Update with new items 
    260         self.__caCertFilePathList += val 
    261     
    262     caCertFilePathList = property(fget=_get_caCertFilePathList, 
    263                                   fset=_set_caCertFilePathList, 
    264                                   doc="list of file paths for CA certificates " 
    265                                       "used to validate an Attribute " 
    266                                       "Certificate") 
    267147 
    268148    def _get_attributeInterfaceCfg(self): 
     
    395275                          doc="Set a prefix for ini file properties")    
    396276 
    397     cert = property(fget=_getCert,  
    398                     fset=_setCert,  
    399                     doc="X.509 Issuer Certificate") 
    400  
    401     issuer = property(fget=_getIssuer,  
    402                       fset=_setIssuer,  
    403                       doc="Issuer name") 
    404  
    405     issuerSerialNumber = property(fget=_getIssuerSerialNumber,  
    406                                   fset=_setIssuerSerialNumber,  
    407                                   doc="Issuer Serial Number") 
    408  
    409     name = property(fget=_getName,  
    410                     fset=_setName,  
    411                     doc="Issuer organisation name") 
    412  
    413     attCertLifetime = property(fget=_getAttCertLifetime,  
    414                                fset=_setAttCertLifetime,  
    415                                doc="Attribute certificate lifetime") 
    416  
    417     attCertNotBeforeOff = property(fget=_getAttCertNotBeforeOff,  
    418                                    fset=_setAttCertNotBeforeOff,  
    419                                    doc="Attribute certificate clock skew in " 
    420                                        "seconds") 
    421  
    422     clockSkew = property(fget=_getClockSkew,  
    423                          fset=_setClockSkew,  
    424                          doc="Allow a clock skew in seconds for SAML Attribute" 
    425                              " Query issueInstant parameter check") 
     277    assertionLifetime = property(fget=_getAssertionLifetime,  
     278                                 fset=_setAssertionLifetime,  
     279                                 doc="validity lifetime (s) for Attribute " 
     280                                     "assertions issued") 
    426281 
    427282    attributeInterface = property(fget=_getAttributeInterface,  
    428283                                  fset=_setAttributeInterface, 
    429284                                  doc="Attribute Interface object") 
    430  
    431     name = property(fget=_getName, fset=_setName, doc="Organisation Name") 
    432285         
    433286    @classmethod 
    434287    def fromPropertyFile(cls, propFilePath=None, propFileSection='DEFAULT', 
    435                          propPrefix='attributeauthority.',  
    436                          bReadMapConfig=True): 
     288                         propPrefix='attributeauthority.'): 
    437289        """Create new NDG Attribute Authority instance from the property file 
    438290        settings 
     
    463315        attributeAuthority.propFilePath = propFilePath             
    464316        attributeAuthority.readProperties() 
    465         attributeAuthority.initialise(bReadMapConfig=bReadMapConfig) 
     317        attributeAuthority.initialise() 
    466318     
    467319        return attributeAuthority 
    468320 
    469321    @classmethod 
    470     def fromProperties(cls, propPrefix='attributeauthority.',  
    471                        bReadMapConfig=True, **prop): 
     322    def fromProperties(cls, propPrefix='attributeauthority.', **prop): 
    472323        """Create new NDG Attribute Authority instance from input property 
    473324        keywords 
     
    477328        property names - useful where properties are being parsed from a file 
    478329        section containing parameter names for more than one application 
    479         @type bReadMapConfig: boolean 
    480         @param bReadMapConfig: by default the Map Configuration file is  
    481         read.  Set this flag to False to override. 
    482330        """ 
    483331        attributeAuthority = AttributeAuthority() 
     
    486334                
    487335        attributeAuthority.setProperties(**prop) 
    488         attributeAuthority.initialise(bReadMapConfig=bReadMapConfig) 
     336        attributeAuthority.initialise() 
    489337         
    490338        return attributeAuthority 
    491339     
    492     def initialise(self, bReadMapConfig=True): 
     340    def initialise(self): 
    493341        """Convenience method for set up of Attribute Interface, map 
    494342        configuration and PKI""" 
    495          
    496         # Read the Map Configuration file 
    497         if bReadMapConfig: 
    498             self.readMapConfig() 
    499343 
    500344        # Instantiate Certificate object 
    501345        log.debug("Reading and checking Attribute Authority X.509 cert. ...") 
    502         self.cert = X509Cert.Read(self.signingCertFilePath) 
    503  
    504         # Check it's valid 
    505         try: 
    506             self.cert.isValidTime(raiseExcep=True) 
    507              
    508         except Exception, e: 
    509             raise AttributeAuthorityError("Attribute Authority's certificate " 
    510                                           "is invalid: %s" % e) 
    511          
    512         # Check CA certificate 
    513         log.debug("Reading and checking X.509 CA certificate ...") 
    514         for caCertFile in self.caCertFilePathList: 
    515             caCert = X509Cert(caCertFile) 
    516             caCert.read() 
    517              
    518             try: 
    519                 caCert.isValidTime(raiseExcep=True) 
    520                  
    521             except Exception, e: 
    522                 raise AttributeAuthorityError('CA certificate "%s" is ' 
    523                                               'invalid: %s'% (caCert.dn, e)) 
    524          
    525         # Issuer details - serialise using the separator string set in the 
    526         # properties file 
    527         self.issuer = self.cert.dn.serialise(separator=self.dnSeparator) 
    528  
    529         self.issuerSerialNumber = self.cert.serialNumber 
    530346         
    531347        # Load user - user attribute look-up plugin  
    532348        self.initAttributeInterface() 
    533          
    534         attCertFilePath = os.path.join(self.attCertDir, self.attCertFileName) 
    535349 
    536350    def setProperties(self, **prop): 
     
    594408        classProperties.update(self.attributeInterfaceCfg) 
    595409         
    596         modName = classProperties.pop('modName') 
    597         className = classProperties.pop('className')   
     410        className = classProperties.pop('className', None)   
     411        if className is None: 
     412            raise AttributeAuthorityConfigError('No Attribute Interface ' 
     413                                                '"className" property set') 
    598414         
    599415        # file path may be omitted     
     
    724540 
    725541        return samlResponse 
    726          
    727     def getRoles(self, userId): 
    728         """Get the roles available to the registered user identified userId. 
    729  
    730         @type dn: string  
    731         @param dn: user identifier - could be a X500 Distinguished Name 
    732         @return: list of roles for the given user ID""" 
    733  
    734         log.debug('Calling getRoles for user "%s" ...' % userId) 
    735          
    736         # Call to AttributeInterface derived class.  Each Attribute Authority 
    737         # should define it's own roles class derived from AttributeInterface to 
    738         # define how roles are accessed 
    739         try: 
    740             return self.__attributeInterface.getRoles(userId) 
    741  
    742         except Exception, e: 
    743             raise AttributeAuthorityError("Getting user roles: %s" % e) 
    744         
    745     def getAttCertFactory(self): 
     542 
     543    def samlAttributeQueryFactory(self): 
    746544        """Factory method to create SAML Attribute Query wrapper function 
    747         @rtype: function 
    748         @return getAttCert method function wrapper 
    749         """ 
    750         def getAttCertWrapper(*arg, **kw): 
    751             """ 
    752             @type *arg: tuple 
    753             @param *arg: getAttCert arguments 
    754             @type **kw: dict 
    755             @param **kw: getAttCert keyword arguments 
    756             @rtype: ndg.security.common.AttCert.AttCert 
    757             @return: new attribute certificate 
    758             """ 
    759             return self.getAttCert(*arg, **kw) 
    760          
    761         return getAttCertWrapper 
    762  
    763     def samlAttributeQueryFactory(self): 
    764         """Factory method to create SAML Attribute Qeury wrapper function 
    765545        @rtype: function 
    766546        @return: samlAttributeQuery method function wrapper 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/attributeauthority.py

    r6586 r6686  
    1515from ndg.security.server.attributeauthority import AttributeAuthority 
    1616from ndg.security.server.wsgi import NDGSecurityMiddlewareBase 
    17 from ndg.security.server.wsgi.zsi import SOAPBindingMiddleware 
    1817 
    1918 
     
    173172                              doc="Attribute Authority SAML attribute query " 
    174173                                  "function") 
    175  
    176  
    177 from ndg.security.server.zsi.attributeauthority import AttributeAuthorityWS 
    178  
    179 class AttributeAuthoritySOAPBindingMiddlewareConfigError(Exception): 
    180     """Raise if a configuration problem is found""" 
    181      
    182      
    183 class AttributeAuthoritySOAPBindingMiddleware(NDGSecurityMiddlewareBase, 
    184                                               AttributeAuthorityWS): 
    185     """Inheritance from NDGSecurityMiddlewareBase provides a __call__ 
    186     implementation which sets a reference to environ as an object attribute. 
    187      
    188     Inheritance from AttributeAuthorityWS enables preservation of the same 
    189     SOAP callbacks but with the  
    190     ndg.security.server.attributeauthority.AttributeAuthority instance provided 
    191     from environ 
    192      
    193     @type DEFAULT_ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME: basestring 
    194     @cvar DEFAULT_ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME: Key name used to index the  
    195     ndg.security.server.attributeauthority.AttributeAuthority instance in the  
    196     environ dictionary 
    197     @type ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME_CFG_OPTNAME: basestring 
    198     @cvar ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME_CFG_OPTNAME: configuration option name 
    199     for the attribute authority environ key 
    200     @type DEFAULT_ENVIRON_KEYNAME: basestring 
    201     @cvar DEFAULT_ENVIRON_KEYNAME: default value for Key name used to index  
    202     THIS SOAP Service Binding middleware instance in the environ dictionary 
    203     @type ENVIRON_KEYNAME_CFG_OPTNAME: basestring 
    204     @cvar ENVIRON_KEYNAME_CFG_OPTNAME: configuration option name for this  
    205     middleware's environ key 
    206     """ 
    207     DEFAULT_ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME = \ 
    208                 "ndg.security.server.attributeauthority.AttributeAuthority" 
    209     ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME_CFG_OPTNAME = \ 
    210                 'attributeAuthorityEnvironKeyName' 
    211      
    212     DEFAULT_ENVIRON_KEYNAME = ("ndg.security.server.wsgi.attributeauthority." 
    213                                "AttributeAuthoritySOAPBindingMiddleware") 
    214     ENVIRON_KEYNAME_CFG_OPTNAME = 'environKeyName' 
    215      
    216     def __init__(self, app): 
    217         """Don't call AttributeAuthorityWS.__init__ - AttributeAuthority  
    218         instance is provided via environ through upstream  
    219         AttributeAuthorityMiddleware 
    220         """ 
    221         # Call this base class initialiser to set-up the environ attribute 
    222         NDGSecurityMiddlewareBase.__init__(self, app, None) 
    223         AttributeAuthorityWS.__init__(self) 
    224          
    225         self.__keyName = None 
    226         self.__attributeAuthorityKeyName = None 
    227          
    228     def _getKeyName(self): 
    229         return self.__keyName 
    230  
    231     def _setKeyName(self, val): 
    232         if not isinstance(val, basestring): 
    233             raise TypeError('Expecting %r for "keyName" attribute; got %r' % 
    234                             (basestring, type(val))) 
    235         self.__keyName = val 
    236          
    237     keyName = property(fget=_getKeyName,  
    238                        fset=_setKeyName,  
    239                        doc="Key name used to index THIS SOAP Service Binding " 
    240                            "middleware instance in the environ dictionary")    
    241  
    242     def _getAttributeAuthorityKeyName(self): 
    243         return self.__attributeAuthorityKeyName 
    244  
    245     def _setAttributeAuthorityKeyName(self, val): 
    246         if not isinstance(val, basestring): 
    247             raise TypeError('Expecting %r for "attributeAuthorityKeyName" ' 
    248                             'attribute; got %r' %(basestring, type(val))) 
    249         self.__attributeAuthorityKeyName = val 
    250          
    251     attributeAuthorityKeyName = property(fget=_getAttributeAuthorityKeyName,  
    252                                          fset=_setAttributeAuthorityKeyName,  
    253                                          doc="Key name used to index the " 
    254                                              "ndg.security.server.attribute" 
    255                                              "authority.AttributeAuthority " 
    256                                              "instance in the environ " 
    257                                              "dictionary")  
    258               
    259     @classmethod 
    260     def filter_app_factory(cls, app, global_conf,  
    261         attributeAuthoritySOAPBindingPrefix='attributeauthority.soapbinding.',  
    262         **app_conf): 
    263         """Set-up Attribute Authority SOAP Binding middleware using a Paste app 
    264         factory pattern.  Overloaded base class method to enable custom  
    265         settings from app_conf 
    266          
    267         @type app: callable following WSGI interface 
    268         @param app: next middleware application in the chain       
    269         @type global_conf: dict         
    270         @param global_conf: PasteDeploy global configuration dictionary 
    271         @type prefix: basestring 
    272         @param prefix: prefix for configuration items 
    273         @type app_conf: dict         
    274         @param app_conf: PasteDeploy application specific configuration  
    275         dictionary 
    276         """ 
    277         # Generic Binding middleware intercepts the SOAP_ACTION set in environ 
    278         # and maps it to the matching soap_{SOAP_ACTION} method from this class 
    279         soapBindingApp = SOAPBindingMiddleware.filter_app_factory(app,  
    280                                                                   global_conf, 
    281                                                                   **app_conf) 
    282          
    283         # Make the SOAP Binding wrapper pick up this Attribute Authority 
    284         # specific SOAP Binding 
    285         optName = attributeAuthoritySOAPBindingPrefix + \ 
    286                 cls.ENVIRON_KEYNAME_CFG_OPTNAME 
    287         soapBindingApp.serviceSOAPBindingKeyName = app_conf.get(optName, 
    288                                                 cls.DEFAULT_ENVIRON_KEYNAME) 
    289          
    290         # Instantiate this middleware and copy the environ key name setting for 
    291         # the Attribute Authority Service SOAP Binding 
    292         app = cls(soapBindingApp) 
    293         app.keyName = soapBindingApp.serviceSOAPBindingKeyName 
    294          
    295         # envrion key name for the  
    296         # ndg.security.server.attributeauthority.AttributeAuthority instance 
    297         optName = attributeAuthoritySOAPBindingPrefix + \ 
    298                 cls.ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME_CFG_OPTNAME 
    299                  
    300         app.attributeAuthorityKeyName = app_conf.get(optName, 
    301                            cls.DEFAULT_ATTRIBUTE_AUTHORITY_ENVIRON_KEYNAME) 
    302  
    303              
    304         # Extract local WS-Security signature verification filter 
    305         optName = attributeAuthoritySOAPBindingPrefix + \ 
    306                             cls.WSSE_SIGNATURE_VERIFICATION_FILTER_ID_OPTNAME 
    307         app.wsseSignatureVerificationFilterID = app_conf.pop(optName, None) 
    308         if app.wsseSignatureVerificationFilterID is None: 
    309             log.warning('No "%s" option was set in the input config' %  
    310                         cls.WSSE_SIGNATURE_VERIFICATION_FILTER_ID_OPTNAME) 
    311         else:    
    312             log.info('Updated setting from "%s" option' %  
    313                      cls.WSSE_SIGNATURE_VERIFICATION_FILTER_ID_OPTNAME) 
    314                      
    315         return app 
    316   
    317     @NDGSecurityMiddlewareBase.initCall 
    318     def __call__(self, environ, start_response): 
    319         """Set a reference to self in environ for the SOAPBindingMiddleware  
    320         instance to pick up downstream 
    321          
    322         @type environ: dict 
    323         @param environ: WSGI environment variables dictionary 
    324         @type start_response: function 
    325         @param start_response: standard WSGI start response function 
    326         """ 
    327  
    328         environ[self.keyName] = self 
    329         return self._app(environ, start_response) 
    330      
    331     def soap_getAttCert(self, ps): 
    332         '''Retrieve an Attribute Certificate 
    333          
    334         @type ps: ZSI ParsedSoap 
    335         @param ps: client SOAP message 
    336         @rtype: ndg.security.common.zsi.attributeauthority.AttributeAuthority_services_types.getAttCertResponse_Holder 
    337         @return: response''' 
    338         self._setAttributeAuthorityFromEnviron() 
    339         return AttributeAuthorityWS.soap_getAttCert(self, ps) 
    340  
    341     def soap_getHostInfo(self, ps): 
    342         '''Get information about this host 
    343                  
    344         @type ps: ZSI ParsedSoap 
    345         @param ps: client SOAP message 
    346         @rtype: response 
    347         @return: response''' 
    348         self._setAttributeAuthorityFromEnviron() 
    349         return AttributeAuthorityWS.soap_getHostInfo(self, ps) 
    350      
    351     def soap_getAllHostsInfo(self, ps): 
    352         '''Get information about all hosts 
    353                  
    354         @type ps: ZSI ParsedSoap 
    355         @param ps: client SOAP message 
    356         @rtype: tuple 
    357         @return: response object''' 
    358         self._setAttributeAuthorityFromEnviron() 
    359         return AttributeAuthorityWS.soap_getAllHostsInfo(self, ps) 
    360      
    361     def soap_getTrustedHostInfo(self, ps): 
    362         '''Get information about other trusted hosts 
    363                  
    364         @type ps: ZSI ParsedSoap 
    365         @param ps: client SOAP message 
    366         @rtype: tuple 
    367         @return: response object''' 
    368         self._setAttributeAuthorityFromEnviron() 
    369         return AttributeAuthorityWS.soap_getTrustedHostInfo(self, ps) 
    370      
    371     def _setAttributeAuthorityFromEnviron(self): 
    372         self.aa = self.environ.get(self.attributeAuthorityKeyName) 
    373         if self.aa is None: 
    374             raise AttributeAuthoritySOAPBindingMiddlewareConfigError( 
    375                                             'No "%s" key found in environ' %  
    376                                             self.attributeAuthorityKeyName) 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/saml/__init__.py

    r6615 r6686  
    8989        self.__serialise = None 
    9090        self.__deserialise = None 
     91        self.__issuer = None 
     92        self.__clockSkewTolerance = 0. 
     93        self.__verifyTimeConditions = True 
    9194                  
    9295    def initialise(self, global_conf, prefix='', **app_conf): 
     
    145148                            value) 
    146149         
    147  
    148150    deserialise = property(_getDeserialise,  
    149151                           _setDeserialise,  
    150152                           doc="callable to de-serialise response from XML " 
    151153                               "type")         
     154 
     155    def _getIssuer(self): 
     156        return self.__issuer 
     157 
     158    def _setIssuer(self, value): 
     159        if not isinstance(value, basestring): 
     160            raise TypeError('Expecting string type for "issuer"; got %r' % 
     161                            type(value)) 
     162             
     163        self.__issuer = value 
     164         
     165    issuer = property(fget=_getIssuer,  
     166                      fset=_setIssuer,  
     167                      doc="Name of issuing authority") 
     168 
     169    def _getVerifyTimeConditions(self): 
     170        return self.__verifyTimeConditions 
     171 
     172    def _setVerifyTimeConditions(self, value): 
     173        if isinstance(value, bool): 
     174            self.__verifyTimeConditions = value 
     175             
     176        if isinstance(value, basestring): 
     177            self.__verifyTimeConditions = str2Bool(value) 
     178        else: 
     179            raise TypeError('Expecting bool or string type for ' 
     180                            '"verifyTimeConditions"; got %r instead' %  
     181                            type(value)) 
     182 
     183    verifyTimeConditions = property(_getVerifyTimeConditions,  
     184                                    _setVerifyTimeConditions,  
     185                                    doc='Set to True to verify any time ' 
     186                                        'Conditions set in the returned ' 
     187                                        'response assertions') 
     188     
     189    def _getClockSkewTolerance(self): 
     190        return self.__clockSkewTolerance 
     191 
     192    def _setClockSkewTolerance(self, value): 
     193        if isinstance(value, (float, int, long)): 
     194            self.__clockSkewTolerance = timedelta(seconds=value) 
     195             
     196        elif isinstance(value, basestring): 
     197            self.__clockSkewTolerance = timedelta(seconds=float(value)) 
     198        else: 
     199            raise TypeError('Expecting float, int, long or string type for ' 
     200                            '"clockSkew"; got %r' % type(value))   
     201                 
     202    clockSkewTolerance = property(fget=_getClockSkewTolerance,  
     203                                  fset=_setClockSkewTolerance,  
     204                                  doc="Set a tolerance of +/- n seconds to " 
     205                                      "allow for clock skew when checking " 
     206                                      "timestamps of client queries") 
     207 
    152208    @classmethod 
    153209    def filter_app_factory(cls, app, global_conf, **app_conf): 
     
    227283        queryElem = soapRequest.body.elem[0] 
    228284         
     285        # Create a response with basic attributes if provided in the  
     286        # initialisation config 
     287        samlResponse = self._initResponse() 
     288         
    229289        try: 
    230             query = self.deserialise(queryElem) 
     290            samlQuery = self.deserialise(queryElem) 
     291             
    231292        except UnknownAttrProfile: 
    232293            log.exception("%r raised parsing incoming query: " %  
    233294                          (type(e), traceback.format_exc())) 
    234             samlResponse = self._makeErrorResponse( 
    235                                         StatusCode.UNKNOWN_ATTR_PROFILE_URI) 
     295            samlResponse.statusCode.value = StatusCode.UNKNOWN_ATTR_PROFILE_URI 
    236296        else:    
    237297            # Check for Query Interface in environ 
     
    242302                                self.queryInterfaceKeyName) 
    243303             
     304            # Basic validation 
     305            self._validateQuery(samlQuery) 
     306             
     307            samlResponse.inResponseTo = samlQuery.id 
     308             
    244309            # Call query interface         
    245             samlResponse = queryInterface(query) 
     310            queryInterface(samlQuery, samlResponse) 
    246311         
    247312        # Convert to ElementTree representation to enable attachment to SOAP 
     
    263328                        ('Content-type', 'text/xml')]) 
    264329        return [response] 
    265  
    266     def _makeErrorResponse(self, code): 
    267         """Convenience method for making a basic response following an error 
     330     
     331    def _validateQuery(self, query): 
     332        if not self.verifyTimeConditions: 
     333            log.debug("Skipping verification of SAML Response time conditions") 
     334             
     335        utcNow = datetime.utcnow()  
     336        nowPlusSkew = utcNow + self.clockSkewTolerance 
     337         
     338        if response.issueInstant > nowPlusSkew: 
     339            msg = ('SAML Attribute Query issueInstant [%s] is after ' 
     340                   'the clock time [%s] (skewed +%s)' %  
     341                   (query.issueInstant,  
     342                    SAMLDateTime.toString(nowPlusSkew), 
     343                    self.clockSkewTolerance)) 
     344              
     345            samlRespError = QueryIssueInstantInvalid(msg) 
     346            samlRespError.response = response 
     347            raise samlRespError 
     348 
     349    def _initResponse(self): 
     350        """Create a SAML Response object with basic settings if any have been 
     351        provided at initialisation of this class - see initialise 
     352         
     353        @return: SAML response object 
     354        @rtype: ndg.saml.saml2.core.Response 
    268355        """ 
    269356        samlResponse = Response() 
    270          
    271         samlResponse.issueInstant = datetime.utcnow()             
     357        utcNow = datetime.utcnow() 
     358         
     359        samlResponse.issueInstant = utcNow 
    272360        samlResponse.id = str(uuid4()) 
     361        samlResponse.issuer = Issuer() 
     362         
     363        # Nb. SAML 2.0 spec says issuer format must be omitted 
     364        if self.issuer is not None: 
     365            samlResponse.issuer.value = self.issuer 
    273366         
    274367        # Initialise to success status but reset on error 
    275368        samlResponse.status = Status() 
    276369        samlResponse.status.statusCode = StatusCode() 
    277         samlResponse.status.statusCode.value = code 
    278          
     370        samlResponse.status.statusMessage = StatusMessage() 
     371        samlResponse.status.statusCode.value = StatusCode.SUCCESS_URI 
     372         
     373        samlResponse.status.statusMessage = StatusMessage() 
     374 
    279375        return samlResponse 
    280376 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/config/attributeauthority/sitea/site-a.ini

    r6615 r6686  
    2727[pipeline:main] 
    2828pipeline = AttributeAuthorityFilter  
    29                    wsseSignatureVerificationFilter  
    30                    AttributeAuthorityWsdlSoapBindingFilter 
    31                    wsseSignatureFilter  
    3229                   AttributeAuthoritySamlSoapBindingFilter 
    3330                   mainApp 
     
    6259attributeAuthority.clockSkew: 180.0 
    6360 
    64 # All Attribute Certificates issued are recorded in this dir 
    65 attributeAuthority.attCertDir: %(here)s/attributeCertificateLog 
    66  
    67 # Files in attCertDir are stored using a rotating file handler 
    68 # attCertFileLogCnt sets the max number of files created before the first is  
    69 # overwritten 
    70 attributeAuthority.attCertFileName: ac.xml 
    71 attributeAuthority.attCertFileLogCnt: 16 
    7261attributeAuthority.dnSeparator:/ 
    73  
    74 # Location of role mapping file 
    75 attributeAuthority.mapConfigFilePath: %(here)s/siteAMapConfig.xml 
    7662 
    7763# Settings for custom AttributeInterface derived class to get user roles for given  
     
    8066attributeAuthority.attributeInterface.modName: siteAUserRoles 
    8167attributeAuthority.attributeInterface.className: TestUserRoles 
    82  
    83 # Config for XML signature of Attribute Certificate 
    84 attributeAuthority.signingPriKeyFilePath: %(here)s/siteA-aa.key 
    85 attributeAuthority.signingCertFilePath: %(here)s/siteA-aa.crt 
    86 attributeAuthority.caCertFilePathList: $NDGSEC_TEST_CONFIG_DIR/ca/ndg-test-ca.crt 
    87  
    88  
    89 # SOAP WSDL Based Binding to the Attribute Authority 
    90 [filter:AttributeAuthorityWsdlSoapBindingFilter] 
    91 paste.filter_app_factory = ndg.security.server.wsgi.attributeauthority:AttributeAuthoritySOAPBindingMiddleware.filter_app_factory 
    92 prefix = service.soap.binding. 
    93 attributeAuthoritySOAPBindingPrefix = attributeauthority.service.soap.binding. 
    94  
    95 service.soap.binding.referencedFilters = wsseSignatureVerificationFilter01 
    96 service.soap.binding.path = %(attributeAuthoritySoapWsdlServicePath)s 
    97 service.soap.binding.enableWSDLQuery = True 
    98 service.soap.binding.charset = utf-8 
    99 service.soap.binding.serviceSOAPBindingEnvironKeyName = ndg.security.server.wsgi.attributeauthority.AttributeAuthoritySOAPBindingMiddleware 
    100  
    101 attributeauthority.service.soap.binding.attributeAuthorityEnvironKeyName = %(attributeAuthorityEnvironKeyName)s 
    102 attributeauthority.service.soap.binding.wsseSignatureVerificationFilterID = wsseSignatureVerificationFilter01 
    103  
    10468 
    10569# SAML SOAP Binding to the Attribute Authority 
     
    11579saml.soapbinding.pathMatchList = /AttributeAuthority/saml 
    11680saml.soapbinding.queryInterfaceKeyName = %(attributeQueryInterfaceEnvironKeyName)s 
    117  
    118  
    119 [filter:wsseSignatureVerificationFilter] 
    120 paste.filter_app_factory = ndg.security.server.wsgi.wssecurity:SignatureVerificationFilter.filter_app_factory 
    121 filterID = wsseSignatureVerificationFilter01 
    122 path = %(attributeAuthoritySoapWsdlServicePath)s 
    123  
    124 # Settings for WS-Security SignatureHandler class used by this filter 
    125 wsseCfgFilePrefix = wssecurity 
    126  
    127 # Verify against known CAs - Provide a space separated list of file paths 
    128 wssecurity.caCertFilePathList=$NDGSEC_TEST_CONFIG_DIR/ca/ndg-test-ca.crt 
    129  
    130 [filter:wsseSignatureFilter] 
    131 paste.filter_app_factory = ndg.security.server.wsgi.wssecurity:ApplySignatureFilter.filter_app_factory 
    132 path = %(attributeAuthoritySoapWsdlServicePath)s 
    133  
    134 # Reference the verification filter in order to be able to apply signature 
    135 # confirmation 
    136 referencedFilters = wsseSignatureVerificationFilter01 
    137 wsseSignatureVerificationFilterID = wsseSignatureVerificationFilter01 
    138  
    139 # Last filter in chain SOAP handlers writes the response 
    140 writeResponse = True 
    141  
    142 # Settings for WS-Security SignatureHandler class used by this filter 
    143 wsseCfgFilePrefix = wssecurity 
    144  
    145 # Certificate associated with private key used to sign a message.  The sign  
    146 # method will add this to the BinarySecurityToken element of the WSSE header.   
    147 wssecurity.signingCertFilePath=%(here)s/siteA-aa.crt 
    148  
    149 # PEM encoded private key file 
    150 wssecurity.signingPriKeyFilePath=%(here)s/siteA-aa.key 
    151  
    152 # Set the ValueType for the BinarySecurityToken added to the WSSE header for a 
    153 # signed message.  See __setReqBinSecTokValType method and binSecTokValType  
    154 # class variable for options - it may be one of X509, X509v3, X509PKIPathv1 or  
    155 # give full namespace to alternative - see  
    156 # ZSI.wstools.Namespaces.OASIS.X509TOKEN 
    157 # 
    158 # binSecTokValType determines whether signingCert or signingCertChain  
    159 # attributes will be used. 
    160 wssecurity.reqBinSecTokValType=X509v3 
    161  
    162 # Add a timestamp element to an outbound message 
    163 wssecurity.addTimestamp=True 
    164  
    165 # For WSSE 1.1 - service returns signature confirmation containing signature  
    166 # value sent by client 
    167 wssecurity.applySignatureConfirmation=True 
    16881 
    16982 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/attributeauthority/test_attributeauthority.cfg

    r5681 r6686  
    88 
    99[DEFAULT] 
    10 siteBPropFilePath=$NDGSEC_TEST_CONFIG_DIR/attributeauthority/siteb/siteBAttAuthority.cfg 
    11  
    12 [setUp] 
    13 # ! SiteBMapConfig.xml trusted site A aaURI setting must agree with this  
    14 # setting for test6GetMappedAttCert 
    15 propFilePath=$NDGSEC_TEST_CONFIG_DIR/attributeauthority/sitea/siteAAttributeAuthority.cfg 
    16  
    17 # For https connections only.  !Omit ssl* settings if using http! 
    18 # sslpeercertcn is the expected CommonName of peer cert.  Omit if it's the  
    19 # same as peer hostname.  
    20 sslPeerCertCN = AttributeAuthority 
    21 sslCACertFilePathList = $NDGSEC_TEST_CONFIG_DIR/ca/ndg-test-ca.crt 
    22  
    23 [test02GetTrustedHostInfo] 
    24 role = urn:siteA:security:authz:1.0:attr:postgrad 
    25  
    26 [test03GetTrustedHostInfoWithNoMatchingRoleFound] 
    27 # Set an alternative role to test no matching role found exception 
    28 role = blah 
    29   
    30 [test05GetAttCert] 
    31 issuingClntCertFilePath = $NDGSEC_TEST_CONFIG_DIR/pki/user.crt 
    32  
    33 # Setup for use by test08GetMappedAttCert test 
    34 attCertFilePath = $NDGSEC_AA_UNITTEST_DIR/ac-clnt.xml 
    35  
    36 [test06GetAttCertWithUserIdSet] 
    37 userId = system 
    38 attCertFilePath = $NDGSEC_AA_UNITTEST_DIR/ac-clnt-test6.xml 
    39  
    40 [test07GetMappedAttCert] 
    41 issuingClntCertFilePath = $NDGSEC_TEST_CONFIG_DIR/pki/user.crt 
    42 userAttCertFilePath = $NDGSEC_AA_UNITTEST_DIR/ac-clnt.xml 
    43 mappedAttCertFilePath = $NDGSEC_AA_UNITTEST_DIR/mapped-ac.xml 
    44  
    45 [test08GetMappedAttCertStressTest] 
    46 issuingClntCertFilePath = $NDGSEC_TEST_CONFIG_DIR/pki/user.crt 
    47 userAttCertFilePathList = $NDGSEC_AA_UNITTEST_DIR/ac-clnt.xml 
    48  
     10prefix='attribute-authority.' 
     11attribute-authority.assertionLifetime = 3600 
     12attribute-authority.issuerName = /O=My Organisation/OU=Centre/CN=Attribute Authority  
     13attribute-authority.attributeInterface.className = ndg.security.server.attributeauthority.AttributeInterface 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/attributeauthority/test_attributeauthority.py

    r6615 r6686  
    1919logging.basicConfig(level=logging.DEBUG) 
    2020 
    21 from os.path import expandvars as xpdVars 
    22 from os.path import join as jnPath 
    23 mkPath = lambda file:jnPath(os.environ['NDGSEC_AA_UNITTEST_DIR'], file) 
     21from warnings import warn 
     22from uuid import uuid4 
     23from datetime import datetime 
     24from os import path 
    2425 
    2526from ndg.security.test.unit import BaseTestCase 
     
    2829    CaseSensitiveConfigParser) 
    2930from ndg.security.server.attributeauthority import (AttributeAuthority,  
    30     AttributeAuthorityNoMatchingRoleInTrustedHosts,  
    3131    SQLAlchemyAttributeInterface, InvalidAttributeFormat) 
    3232 
    33 from ndg.security.common.AttCert import AttCert 
    34  
    35  
    36 class AttributeAuthorityTestCase(BaseTestCase): 
    37     clntPriKeyPwd = None 
    38  
    39     def setUp(self): 
    40         super(AttributeAuthorityTestCase, self).setUp() 
    41          
    42         if 'NDGSEC_INT_DEBUG' in os.environ: 
    43             import pdb 
    44             pdb.set_trace() 
    45          
    46         if 'NDGSEC_AA_UNITTEST_DIR' not in os.environ: 
    47             os.environ['NDGSEC_AA_UNITTEST_DIR'] = \ 
    48                 os.path.abspath(os.path.dirname(__file__)) 
    49  
    50         self.cfgParser = CaseSensitiveConfigParser() 
    51         cfgFilePath = mkPath('test_attributeauthority.cfg') 
    52         self.cfgParser.read(cfgFilePath) 
    53          
    54         self.cfg = {} 
    55         for section in self.cfgParser.sections() + ['DEFAULT']: 
    56             self.cfg[section] = dict(self.cfgParser.items(section)) 
    57              
    58         self.aa = AttributeAuthority.fromPropertyFile( 
    59                                             self.cfg['setUp']['propFilePath']) 
    60  
    61     _mkSiteBAttributeAuthority = lambda self: \ 
    62         AttributeAuthority.fromPropertyFile( 
    63                         propFilePath=self.cfg['DEFAULT']['siteBPropFilePath']) 
    64      
    65     def test01GetHostInfo(self): 
    66         """test01GetHostInfo: retrieve info for AA host""" 
    67         hostInfo = self.aa.hostInfo 
    68         print("Host Info:\n %s" % hostInfo)      
    69  
    70     def test02GetTrustedHostInfo(self): 
    71         """test02GetTrustedHostInfo: retrieve trusted host info matching a 
    72         given role""" 
    73         thisSection = self.cfg['test02GetTrustedHostInfo'] 
    74          
    75         trustedHostInfo = self.aa.getTrustedHostInfo(thisSection['role']) 
    76         for hostname, hostInfo in trustedHostInfo.items(): 
    77             self.assert_(hostname, "Hostname not set") 
    78             for k, v in hostInfo.items(): 
    79                 self.assert_(k, "hostInfo value key unset") 
    80  
    81         print("Trusted Host Info:\n %s" % trustedHostInfo) 
    82  
    83     def test03GetTrustedHostInfoWithNoMatchingRoleFound(self): 
    84         """test03GetTrustedHostInfoWithNoMatchingRoleFound: test the case  
    85         where the input role doesn't match any roles in the target AA's map  
    86         config file""" 
    87         thisSection = self.cfg[ 
    88                             'test03GetTrustedHostInfoWithNoMatchingRoleFound'] 
    89         try: 
    90             trustedHostInfo = self.aa.getTrustedHostInfo(thisSection['role']) 
    91             self.fail("Expecting NoMatchingRoleInTrustedHosts exception") 
    92              
    93         except AttributeAuthorityNoMatchingRoleInTrustedHosts, e: 
    94             print('PASSED - no match for role "%s": %s' % (thisSection['role'], 
    95                                                            e)) 
    96  
    97  
    98     def test04GetTrustedHostInfoWithNoRole(self): 
    99         """test04GetTrustedHostInfoWithNoRole: retrieve trusted host info  
    100         irrespective of role""" 
    101         trustedHostInfo = self.aa.getTrustedHostInfo() 
    102         for hostname, hostInfo in trustedHostInfo.items(): 
    103             self.assert_(hostname, "Hostname not set") 
    104             for k, v in hostInfo.items(): 
    105                 self.assert_(k, "hostInfo value key unset") 
    106                     
    107         print("Trusted Host Info:\n %s" % trustedHostInfo) 
    108  
    109     def test05GetAttCert(self):         
    110         """test05GetAttCert: Request attribute certificate from NDG Attribute  
    111         Authority Web Service.""" 
    112         thisSection = self.cfg['test05GetAttCert'] 
    113          
    114         # Read user Certificate into a string ready for passing via WS 
    115         try: 
    116             userX509CertFilePath = xpdVars(thisSection.get( 
    117                                                     'issuingClntCertFilePath')) 
    118             userX509CertTxt = open(userX509CertFilePath, 'r').read() 
    119          
    120         except TypeError: 
    121             # No issuing cert set 
    122             userX509CertTxt = None 
    123                  
    124         except IOError, ioErr: 
    125             raise Exception("Error reading certificate file \"%s\": %s" % 
    126                                     (ioErr.filename, ioErr.strerror)) 
    127  
    128         # Make attribute certificate request 
    129         attCert = self.aa.getAttCert(holderX509Cert=userX509CertTxt) 
    130          
    131         print("Attribute Certificate: \n\n:" + str(attCert)) 
    132          
    133         attCert.filePath = xpdVars(thisSection['attCertFilePath']) 
    134         attCert.write() 
    135          
    136          
    137     def test06GetAttCertWithUserIdSet(self):         
    138         """test06GetAttCertWithUserIdSet: Request attribute certificate from  
    139         NDG Attribute Authority Web Service setting a specific user Id  
    140         independent of the signer of the SOAP request.""" 
    141         thisSection = self.cfg['test06GetAttCertWithUserIdSet'] 
    142          
    143         # Make attribute certificate request 
    144         userId = thisSection['userId'] 
    145         attCert = self.aa.getAttCert(userId=userId) 
    146          
    147         print("Attribute Certificate: \n\n:" + str(attCert)) 
    148          
    149         attCert.filePath = xpdVars(thisSection['attCertFilePath']) 
    150         attCert.write() 
    151  
    152  
    153     def test07GetMappedAttCert(self):         
    154         """test07GetMappedAttCert: Request mapped attribute certificate from  
    155         NDG Attribute Authority Web Service.""" 
    156         thisSection = self.cfg['test07GetMappedAttCert'] 
    157          
    158         # Read user Certificate into a string ready for passing via WS 
    159         try: 
    160             userX509CertFilePath = xpdVars(thisSection.get( 
    161                                                     'issuingClntCertFilePath')) 
    162             userX509CertTxt = open(userX509CertFilePath, 'r').read() 
    163          
    164         except TypeError: 
    165             # No issuing cert set 
    166             userX509CertTxt = None 
    167                  
    168         except IOError, ioErr: 
    169             raise Exception("Error reading certificate file \"%s\": %s" %  
    170                                     (ioErr.filename, ioErr.strerror)) 
    171      
    172         # Simlarly for Attribute Certificate  
    173         try: 
    174             userAttCert = AttCert.Read( 
    175                                 xpdVars(thisSection['userAttCertFilePath'])) 
    176              
    177         except IOError, ioErr: 
    178             raise Exception("Error reading attribute certificate file \"%s\": " 
    179                             "%s" % (ioErr.filename, ioErr.strerror)) 
    180          
    181         # Make client to site B Attribute Authority 
    182         siteBAA = self._mkSiteBAttributeAuthority() 
    183      
    184         # Make attribute certificate request 
    185         attCert = siteBAA.getAttCert(holderX509Cert=userX509CertTxt, 
    186                                      userAttCert=userAttCert) 
    187         print("Attribute Certificate: \n\n:" + str(attCert)) 
    188          
    189         attCert.filePath = xpdVars(thisSection['mappedAttCertFilePath']) 
    190         attCert.write() 
    191          
    192          
    193     def test08GetMappedAttCertStressTest(self):         
    194         """test08GetMappedAttCertStressTest: Request mapped attribute  
    195         certificate from NDG Attribute Authority Web Service.""" 
    196         thisSection = self.cfg['test08GetMappedAttCertStressTest'] 
    197          
    198         # Read user Certificate into a string ready for passing via WS 
    199         try: 
    200             userX509CertFilePath = xpdVars(thisSection.get( 
    201                                                     'issuingClntCertFilePath')) 
    202             userX509CertTxt = open(userX509CertFilePath, 'r').read() 
    203          
    204         except TypeError: 
    205             # No issuing cert set 
    206             userX509CertTxt = None 
    207                  
    208         except IOError, ioErr: 
    209             raise Exception("Error reading certificate file \"%s\": %s" %  
    210                                     (ioErr.filename, ioErr.strerror)) 
    211  
    212         # Make client to site B Attribute Authority 
    213         siteBAA = self._mkSiteBAttributeAuthority() 
    214  
    215         acFilePathList = [xpdVars(file) for file in \ 
    216                           thisSection['userAttCertFilePathList'].split()] 
    217  
    218         passed = True 
    219         for acFilePath in acFilePathList: 
    220             try: 
    221                 userAttCert = AttCert.Read(acFilePath) 
    222                  
    223             except IOError, ioErr: 
    224                 raise Exception("Error reading attribute certificate file " 
    225                                 '"%s": %s' % (ioErr.filename, ioErr.strerror)) 
    226          
    227             # Make attribute certificate request 
    228             try: 
    229                 attCert = siteBAA.getAttCert(holderX509Cert=userX509CertTxt, 
    230                                              userAttCert=userAttCert) 
    231             except Exception, e: 
    232                 passed = True 
    233                 outFilePfx = 'test08GetMappedAttCertStressTest-%s' % \ 
    234                         os.path.basename(acFilePath)     
    235                 msgFile = open(outFilePfx+".msg", 'w') 
    236                 msgFile.write('Failed for "%s": %s\n' % (acFilePath, e)) 
    237                  
    238         self.assert_(passed,  
    239                      "At least one Attribute Certificate request failed.  " 
    240                      "Check the .msg files in this directory") 
    241  
    242  
    243 from warnings import warn 
    244 from uuid import uuid4 
    245 from datetime import datetime 
    246 from ndg.saml.saml2.core import (Response, Attribute, SAMLVersion, Subject, NameID, 
    247                              Issuer, AttributeQuery, XSStringAttributeValue,  
    248                              Status, StatusMessage, StatusCode) 
     33from ndg.saml.saml2.core import (Response, Attribute, SAMLVersion, Subject,  
     34                                 NameID, Issuer, AttributeQuery,  
     35                                 XSStringAttributeValue, Status, StatusMessage,  
     36                                 StatusCode) 
    24937from ndg.saml.xml import XMLConstants 
    25038from ndg.security.common.saml_utils.esg import EsgSamlNamespaces 
    25139 
     40THIS_DIR = path.dirname(__file__) 
     41 
     42 
     43class AttributeAuthorityTestCase(BaseTestCase): 
     44    THIS_DIR = THIS_DIR 
     45    PROPERTIES_FILENAME = 'test_attributeauthority.cfg' 
     46    PROPERTIES_FILEPATH = path.join(THIS_DIR, PROPERTIES_FILENAME) 
     47    ISSUER_NAME = '/O=My Organisation/OU=Centre/CN=Attribute Authority' 
     48     
     49    def test01ParsePropertiesFile(self): 
     50        cls = AttributeAuthorityTestCase 
     51        aa = AttributeAuthority.fromPropertyFile(cls.PROPERTIES_FILEPATH) 
     52        self.assert_(aa) 
     53        self.assert_(aa.assertionLifetime == 3600) 
     54        self.assert_(aa.issuerName == cls.ISSUER_NAME) 
     55         
     56    def test02FromPropertis(self): 
     57         
     58        # Casts from string to float 
     59        assertionLifetime = "86400" 
     60        issuerName = 'My issuer' 
     61        aa = AttributeAuthority.fromProperties(issuerName=issuerName, 
     62                                            assertionLifetime=assertionLifetime) 
     63        self.assert_(aa) 
     64        self.assert_(aa.assertionLifetime == float(assertionLifetime)) 
     65        self.assert_(aa.issuerName == issuerName) 
     66 
    25267 
    25368class SQLAlchemyAttributeInterfaceTestCase(BaseTestCase): 
     69    THIS_DIR = THIS_DIR 
     70    PROPERTIES_FILENAME = 'test_sqlalchemyattributeinterface.cfg' 
     71    PROPERTIES_FILEPATH = path.join(THIS_DIR, PROPERTIES_FILENAME) 
     72     
    25473    SAML_SUBJECT_SQLQUERY = ("select count(*) from users where openid = " 
    25574                             "'${userId}'") 
     
    364183            return 
    365184        cfgParser = CaseSensitiveConfigParser() 
    366         cfgFilePath = mkPath('test_sqlalchemyattributeinterface.cfg') 
     185        cls = SQLAlchemyAttributeInterfaceTestCase 
     186        cfgFilePath = cls.PROPERTIES_FILEPATH 
    367187        cfgParser.read(cfgFilePath) 
    368188         
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/saml/test_samlinterface.py

    r6615 r6686  
    2020from xml.etree import ElementTree 
    2121 
     22from ndg.saml.utils import SAMLDateTime 
    2223from ndg.saml.saml2.core import (Response, Assertion, Attribute,  
    2324                             AttributeStatement, SAMLVersion, Subject, NameID, 
     
    3132from ndg.security.common.soap.etree import SOAPEnvelope 
    3233from ndg.security.common.utils.etree import QName, prettyPrint 
     34from ndg.security.common.saml_utils.binding.soap.subjectquery import ( 
     35    SubjectQuerySOAPBinding, ResponseIssueInstantInvalid,  
     36    AssertionIssueInstantInvalid, AssertionConditionNotBeforeInvalid,  
     37    AssertionConditionNotOnOrAfterInvalid) 
     38     
    3339from ndg.security.common.saml_utils.esg import (EsgSamlNamespaces,  
    3440                                          XSGroupRoleAttributeValue) 
     
    160166    """TODO: test SAML Attribute Authority interface""" 
    161167    thisDir = os.path.dirname(os.path.abspath(__file__)) 
     168    RESPONSE = '''\ 
     169<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> 
     170   <SOAP-ENV:Body> 
     171      <samlp:Response ID="05680cb2-4973-443d-9d31-7bc99bea87c1" InResponseTo="e3183380-ae82-4285-8827-8c40613842de" IssueInstant="%(issueInstant)s" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> 
     172         <saml:Issuer Format="urn:esg:issuer" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">ESG-NCAR</saml:Issuer> 
     173         <samlp:Status> 
     174            <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /> 
     175         </samlp:Status> 
     176         <saml:Assertion ID="192c67d9-f9cd-457a-9242-999e7b943166" IssueInstant="%(assertionIssueInstant)s" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> 
     177            <saml:Issuer Format="urn:esg:issuer">ESG-NCAR</saml:Issuer> 
     178            <saml:Subject> 
     179               <saml:NameID Format="urn:esg:openid">https://esg.prototype.ucar.edu/myopenid/testUser</saml:NameID> 
     180            </saml:Subject> 
     181            <saml:Conditions NotBefore="%(notBefore)s" NotOnOrAfter="%(notOnOrAfter)s" /> 
     182            <saml:AttributeStatement> 
     183               <saml:Attribute FriendlyName="FirstName" Name="urn:esg:first:name" NameFormat="http://www.w3.org/2001/XMLSchema#string"> 
     184                  <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Test</saml:AttributeValue> 
     185               </saml:Attribute> 
     186               <saml:Attribute FriendlyName="LastName" Name="urn:esg:last:name" NameFormat="http://www.w3.org/2001/XMLSchema#string"> 
     187                  <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">User</saml:AttributeValue> 
     188               </saml:Attribute> 
     189               <saml:Attribute FriendlyName="EmailAddress" Name="urn:esg:first:email:address" NameFormat="http://www.w3.org/2001/XMLSchema#string"> 
     190                  <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">ejn@ucar.edu</saml:AttributeValue> 
     191               </saml:Attribute> 
     192               <saml:Attribute FriendlyName="GroupRole" Name="urn:esg:group:role" NameFormat="groupRole"> 
     193                  <saml:AttributeValue> 
     194                     <esg:groupRole group="CCSM" role="default" xmlns:esg="http://www.esg.org" /> 
     195                  </saml:AttributeValue> 
     196                  <saml:AttributeValue> 
     197                     <esg:groupRole group="Dynamical Core" role="default" xmlns:esg="http://www.esg.org" /> 
     198                  </saml:AttributeValue> 
     199                  <saml:AttributeValue> 
     200                     <esg:groupRole group="NARCCAP" role="default" xmlns:esg="http://www.esg.org" /> 
     201                  </saml:AttributeValue> 
     202               </saml:Attribute> 
     203            </saml:AttributeStatement> 
     204         </saml:Assertion> 
     205      </samlp:Response> 
     206   </SOAP-ENV:Body> 
     207</SOAP-ENV:Envelope> 
     208''' 
    162209 
    163210    def __init__(self, *args, **kwargs): 
     
    167214        BaseTestCase.__init__(self, *args, **kwargs) 
    168215         
    169  
    170216    def test01AttributeQuery(self): 
    171217        attributeQuery = AttributeQuery() 
     
    389435        self.assert_(response) 
    390436 
     437    def _parseResponse(self, responseStr): 
     438        """Helper to parse a response from a string""" 
     439        soapResponse = SOAPEnvelope() 
     440         
     441        responseStream = StringIO() 
     442        responseStream.write(responseStr) 
     443        responseStream.seek(0) 
     444         
     445        soapResponse.parse(responseStream) 
     446         
     447        print("Parsed response ...") 
     448        print(soapResponse.serialize()) 
     449         
     450        toSAMLTypeMap = [XSGroupRoleAttributeValueElementTree.factoryMatchFunc] 
     451        response = ResponseElementTree.fromXML(soapResponse.body.elem[0], 
     452                                            customToSAMLTypeMap=toSAMLTypeMap) 
     453        return response 
     454         
     455    def test03ParseResponse(self): 
     456        utcNow = datetime.utcnow() 
     457        respDict = { 
     458            'issueInstant': SAMLDateTime.toString(utcNow), 
     459            'assertionIssueInstant': SAMLDateTime.toString(utcNow), 
     460            'notBefore': SAMLDateTime.toString(utcNow), 
     461            'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta( 
     462                                                            seconds=60*60*8)) 
     463        } 
     464        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \ 
     465                                                                        respDict 
     466        response = self._parseResponse(responseStr) 
     467        self.assert_(response) 
     468 
     469    def test04AssertionConditionExpired(self): 
     470        # issued 9 hours ago 
     471        issueInstant = datetime.utcnow() - timedelta(seconds=60*60*9) 
     472        respDict = { 
     473            'issueInstant': SAMLDateTime.toString(issueInstant), 
     474            'assertionIssueInstant': SAMLDateTime.toString(issueInstant), 
     475            'notBefore': SAMLDateTime.toString(issueInstant), 
     476            # It lasts for 8 hours so it's expired by one hour 
     477            'notOnOrAfter': SAMLDateTime.toString(issueInstant + timedelta( 
     478                                                            seconds=60*60*8)) 
     479        } 
     480        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \ 
     481                                                                    respDict 
     482        response = self._parseResponse(responseStr) 
     483        binding = SubjectQuerySOAPBinding() 
     484        try: 
     485            binding._verifyTimeConditions(response) 
     486            self.fail("Expecting not on or after timestamp error") 
     487        except AssertionConditionNotOnOrAfterInvalid, e: 
     488            print("PASSED: %s" % e) 
     489 
     490    def test05ResponseIssueInstantInvalid(self): 
     491        utcNow = datetime.utcnow() 
     492        respDict = { 
     493            'issueInstant': SAMLDateTime.toString(utcNow + timedelta( 
     494                                                                    seconds=1)), 
     495            'assertionIssueInstant': SAMLDateTime.toString(utcNow), 
     496            'notBefore': SAMLDateTime.toString(utcNow), 
     497            'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta( 
     498                                                            seconds=60*60*8)) 
     499        } 
     500        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \ 
     501                                                                    respDict 
     502        response = self._parseResponse(responseStr) 
     503        binding = SubjectQuerySOAPBinding() 
     504        try: 
     505            binding._verifyTimeConditions(response) 
     506            self.fail("Expecting issue instant timestamp error") 
     507        except ResponseIssueInstantInvalid, e: 
     508            print("PASSED: %s" % e) 
     509 
     510    def test06NotBeforeConditionInvalid(self): 
     511        utcNow = datetime.utcnow() 
     512        respDict = { 
     513            'issueInstant': SAMLDateTime.toString(utcNow), 
     514            'assertionIssueInstant': SAMLDateTime.toString(utcNow), 
     515            'notBefore': SAMLDateTime.toString(utcNow + timedelta(seconds=1)), 
     516            'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta( 
     517                                                            seconds=60*60*8)) 
     518        } 
     519        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \ 
     520                                                                    respDict 
     521        response = self._parseResponse(responseStr) 
     522        binding = SubjectQuerySOAPBinding() 
     523        try: 
     524            binding._verifyTimeConditions(response) 
     525            self.fail("Expecting issue instant timestamp error") 
     526        except AssertionConditionNotBeforeInvalid, e: 
     527            print("PASSED: %s" % e) 
     528 
     529    def test07AssertionIssueInstantInvalid(self): 
     530        utcNow = datetime.utcnow() 
     531        respDict = { 
     532            'issueInstant': SAMLDateTime.toString(utcNow), 
     533            'assertionIssueInstant': SAMLDateTime.toString(utcNow + timedelta( 
     534                                                                    seconds=1)), 
     535            'notBefore': SAMLDateTime.toString(utcNow), 
     536            'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta( 
     537                                                            seconds=60*60*8)) 
     538        } 
     539        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \ 
     540                                                                    respDict 
     541        response = self._parseResponse(responseStr) 
     542        binding = SubjectQuerySOAPBinding() 
     543        try: 
     544            binding._verifyTimeConditions(response) 
     545            self.fail("Expecting issue instant timestamp error") 
     546        except AssertionIssueInstantInvalid, e: 
     547            print("PASSED: %s" % e) 
     548 
     549    def test07ClockSkewCorrectedAssertionIssueInstantInvalid(self): 
     550        utcNow = datetime.utcnow() 
     551        respDict = { 
     552            'issueInstant': SAMLDateTime.toString(utcNow), 
     553            'assertionIssueInstant': SAMLDateTime.toString(utcNow + timedelta( 
     554                                                                    seconds=1)), 
     555            'notBefore': SAMLDateTime.toString(utcNow), 
     556            'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta( 
     557                                                            seconds=60*60*8)) 
     558        } 
     559        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \ 
     560                                                                    respDict 
     561        response = self._parseResponse(responseStr) 
     562        binding = SubjectQuerySOAPBinding() 
     563         
     564        # Set a skew to correct the error 
     565        binding.clockSkewTolerance = 1 
     566         
     567        try: 
     568            binding._verifyTimeConditions(response) 
     569        except AssertionIssueInstantInvalid, e: 
     570            self.fail("issue instant timestamp error should be corrected for") 
     571 
     572    def test08ClockSkewCorrectedAssertionConditionExpired(self): 
     573        # Issued 9 hours ago 
     574        issueInstant = datetime.utcnow() - timedelta(seconds=60*60*9) 
     575        respDict = { 
     576            'issueInstant': SAMLDateTime.toString(issueInstant), 
     577            'assertionIssueInstant': SAMLDateTime.toString(issueInstant), 
     578            'notBefore': SAMLDateTime.toString(issueInstant), 
     579            # Assertion lasts 8 hours so it has expired by one hour 
     580            'notOnOrAfter': SAMLDateTime.toString(issueInstant + timedelta( 
     581                                                            seconds=60*60*8)) 
     582        } 
     583        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \ 
     584                                                                    respDict 
     585        response = self._parseResponse(responseStr) 
     586        binding = SubjectQuerySOAPBinding() 
     587         
     588        # Set a skew of over one hour to correct for the assertion expiry 
     589        binding.clockSkewTolerance = 60*60 + 3 
     590         
     591        try: 
     592            binding._verifyTimeConditions(response) 
     593             
     594        except AssertionConditionNotOnOrAfterInvalid, e: 
     595            self.fail("Not on or after timestamp error should be corrected for") 
     596             
    391597             
    392598if __name__ == "__main__": 
Note: See TracChangeset for help on using the changeset viewer.