Ignore:
Timestamp:
12/02/10 17:05:04 (10 years ago)
Author:
pjkersha
Message:
  • Refactored classfactory module as a more generic factory for importing any module object
  • Started unit tests with refactored SAML SOAP bindings.
Location:
TI12-security/trunk/NDGSecurity/python
Files:
1 added
15 edited

Legend:

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

    r6243 r6570  
    44        <comment></comment> 
    55        <projects> 
     6                <project>ndg_security_saml</project> 
    67        </projects> 
    78        <buildSpec> 
  • TI12-security/trunk/NDGSecurity/python/.pydevproject

    r6243 r6570  
    55<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.5</pydev_property> 
    66<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property> 
     7<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> 
     8<path>/ndg_security_python</path> 
     9</pydev_pathproperty> 
     10<pydev_pathproperty name="org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH"> 
     11<path>/home/pjkersha/workspace/ndg_security_saml</path> 
     12</pydev_pathproperty> 
    713</pydev_project> 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/__init__.py

    r6440 r6570  
    22server and client packages 
    33 
    4 NERC Data Grid Project 
     4NERC DataGrid Project 
    55""" 
    66__author__ = "P J Kershaw" 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/credentialwallet.py

    r6512 r6570  
    759759        "This class will be deprecated in future releases.  Use " 
    760760        "SAMLCredentialWallet and " 
    761         "ndg.security.common.saml_utils.bindings.AttributeQuerySslSOAPbinding " 
    762         "client interface instead for retrieving and caching user attributes.") 
     761        "ndg.security.common.saml_utils.binding.soap.attributequery." 
     762        "AttributeQuerySslSOAPbinding client interface instead for retrieving " 
     763        "and caching user attributes.") 
    763764     
    764765    def __init__(self,  
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/__init__.py

    r6069 r6570  
    1 """SAML 2.0 common package for NDG Security.  This contains the bindings module 
    2 with an implementation of the SOAP Bindings for attribute queries 
     1"""SAML 2.0 common package for NDG Security.  This contains the bindings package 
     2with an implementation of the SOAP Bindings for attribute and authorisation 
     3decision queries 
    34 
    45NERC DataGrid Project 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/__init__.py

    r6567 r6570  
    1717from saml.common import SAMLObject 
    1818 
     19from ndg.security.common.utils.factory import importModuleObject 
    1920from ndg.security.common.utils.configfileparsers import ( 
    2021                                                    CaseSensitiveConfigParser) 
    21 from ndg.security.common.utils.etree import QName    
    22 from ndg.security.common.X509 import X500DN  
    2322from ndg.security.common.soap import SOAPEnvelopeBase 
    2423from ndg.security.common.soap.etree import SOAPEnvelope 
     
    4039class SOAPBinding(object): 
    4140    '''Client SAML SOAP Binding''' 
     41    REQUEST_ENVELOPE_CLASS_OPTNAME = 'requestEnvelopeClass' 
     42    RESPONSE_ENVELOPE_CLASS_OPTNAME = 'responseEnvelopeClass' 
     43    SERIALISE_OPTNAME = 'serialise' 
     44    DESERIALISE_OPTNAME = 'deserialise'   
     45     
     46    CONFIG_FILE_OPTNAMES = ( 
     47        REQUEST_ENVELOPE_CLASS_OPTNAME, 
     48        RESPONSE_ENVELOPE_CLASS_OPTNAME, 
     49        SERIALISE_OPTNAME, 
     50        DESERIALISE_OPTNAME 
     51    ) 
     52     
     53    __PRIVATE_ATTR_PREFIX = "__" 
     54    __slots__ = tuple([__PRIVATE_ATTR_PREFIX + i  
     55                       for i in CONFIG_FILE_OPTNAMES + ("__client",)]) 
     56    del i 
    4257     
    4358    isIterable = staticmethod(_isIterable) 
    44     __slots__ = ( 
    45         "__client", 
    46         "__requestEnvelopeClass", 
    47         "__serialise", 
    48         "__deserialise" 
    49     ) 
    5059     
    5160    def __init__(self,  
     
    5463                 serialise=None, 
    5564                 deserialise=None, 
    56                  handlers=(HTTPSHandler,)): 
     65                 handlers=()): 
    5766        '''Create SAML SOAP Client - Nb. serialisation functions must be set 
    5867        before send()ing the request''' 
     
    6978        self.client = UrlLib2SOAPClient() 
    7079         
    71         # ElementTree based envelope class 
     80        # Configurable envelope classes 
    7281        self.requestEnvelopeClass = requestEnvelopeClass 
    7382        self.client.responseEnvelopeClass = responseEnvelopeClass 
     
    8493 
    8594    def _setSerialise(self, value): 
    86         if not callable(value): 
     95        if isinstance(value, basestring): 
     96            self.__deserialise = importModuleObject(value) 
     97             
     98        elif callable(value): 
     99            self.__deserialise = value 
     100        else: 
    87101            raise TypeError('Expecting callable for "serialise"; got %r' %  
    88102                            value) 
     
    96110 
    97111    def _setDeserialise(self, value): 
    98         if not callable(value): 
     112        if isinstance(value, basestring): 
     113            self.__deserialise = importModuleObject(value) 
     114             
     115        elif callable(value): 
     116            self.__deserialise = value 
     117        else: 
    99118            raise TypeError('Expecting callable for "deserialise"; got %r' %  
    100119                            value) 
    101         self.__deserialise = value 
     120         
    102121 
    103122    deserialise = property(_getDeserialise,  
     
    110129 
    111130    def _setRequestEnvelopeClass(self, value): 
    112         if not issubclass(value, SOAPEnvelopeBase): 
    113             raise TypeError('Expecting %r for "requestEnvelopeClass"; got %r' %  
     131        if isinstance(value, basestring): 
     132            self.client.responseEnvelopeClass = importClass(value) 
     133             
     134        elif issubclass(value, SOAPEnvelopeBase): 
     135            self.client.responseEnvelopeClass = value 
     136        else: 
     137            raise TypeError('Expecting %r derived type or string for ' 
     138                            '"requestEnvelopeClass" attribute; got %r' %  
    114139                            (SOAPEnvelopeBase, value)) 
    115140         
     
    173198            raise SOAPBindingInvalidResponse("Expecting single child element " 
    174199                                             "is SOAP body") 
    175              
    176         if QName.getLocalPart(response.envelope.body.elem[0].tag)!='Response': 
    177             raise SOAPBindingInvalidResponse('Expecting "Response" element in ' 
    178                                              'SOAP body') 
    179200             
    180201        response = self.deserialise(response.envelope.body.elem[0]) 
     
    225246                # No prefix set - attempt to set all attributes    
    226247                setattr(self, optName, val) 
    227          
     248                 
     249    def __setattr__(self, name, value): 
     250        """Enable setting of SOAPBinding.client.responseEnvelopeClass as if it 
     251        were an attribute of self 
     252        """ 
     253        try: 
     254            super(SOAPBinding, self).__setattr__(name, value) 
     255             
     256        except AttributeError: 
     257            if 'name' == SOAPBinding.RESPONSE_ENVELOPE_CLASS_OPTNAME: 
     258                if isinstance(value, basestring): 
     259                    self.client.responseEnvelopeClass = importClass(value) 
     260                elif issubclass(value, SOAPEnvelopeBase): 
     261                    self.client.responseEnvelopeClass = value 
     262                else: 
     263                    raise TypeError('Expecting string or type instance for %r; ' 
     264                                    'got %r instead.' % (name, type(value))) 
     265            else: 
     266                raise 
     267                     
    228268    def __getstate__(self): 
    229269        '''Explicit implementation needed with __slots__''' 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/attributequery.py

    r6567 r6570  
    99__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1010__revision__ = '$Id: $' 
     11import re 
    1112import logging 
    1213log = logging.getLogger(__name__) 
     
    1718 
    1819from ndg.security.common.utils import TypedList 
    19 from ndg.security.common.sam_utils.binding.soap.subjectquery import ( 
     20from ndg.security.common.saml_utils.binding.soap.subjectquery import ( 
    2021                                                    SubjectQuerySOAPBinding, 
    2122                                                    SubjectQueryResponseError) 
     
    3536     
    3637 
    37 class AttributeQuerySOAPBinding(SubjectQuery):  
     38class AttributeQuerySOAPBinding(SubjectQuerySOAPBinding):  
    3839    """SAML Attribute Query SOAP Binding 
    3940    """ 
     
    9798        """ Create a SAML attribute query""" 
    9899        attributeQuery = super(AttributeQuerySOAPBinding, self)._createQuery( 
    99                                                     AttributeQuerySOAPBinding) 
     100                                                                AttributeQuery) 
    100101        # Add list of attributes to query                       
    101102        for attribute in self.queryAttributes: 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/subjectquery.py

    r6567 r6570  
    1313 
    1414from datetime import datetime, timedelta 
     15from uuid import uuid4 
    1516 
    1617from saml.common import SAMLObject 
    1718from saml.utils import SAMLDateTime 
    18 from saml.saml2.core import (Attribute, AttributeQuery, StatusCode, Response, 
     19from saml.saml2.core import (SubjectQuery, StatusCode, Response, 
    1920                             Issuer, Subject, SAMLVersion, NameID) 
    2021 
     22from ndg.security.common.utils import str2Bool 
    2123from ndg.security.common.saml_utils.binding.soap import (SOAPBinding, 
    2224    SOAPBindingInvalidResponse) 
     
    5557    SUBJECT_ID_OPTNAME = 'subjectID' 
    5658    ISSUER_NAME_OPTNAME = 'issuerName' 
     59    ISSUER_FORMAT_OPTNAME = 'issuerFormat' 
     60    SUBJECT_ID_FORMAT_OPTNAME = 'subjectIdFormat' 
    5761    CLOCK_SKEW_OPTNAME = 'clockSkewTolerance' 
    5862    VERIFY_TIME_CONDITIONS_OPTNAME = 'verifyTimeConditions' 
     
    6064    CONFIG_FILE_OPTNAMES = ( 
    6165        SUBJECT_ID_OPTNAME, 
    62         ISSUER_NAME_OPTNAME,                  
     66        SUBJECT_ID_FORMAT_OPTNAME, 
     67        ISSUER_NAME_OPTNAME,  
     68        ISSUER_FORMAT_OPTNAME,                 
    6369        CLOCK_SKEW_OPTNAME, 
    6470        VERIFY_TIME_CONDITIONS_OPTNAME             
     
    6672     
    6773    __PRIVATE_ATTR_PREFIX = "__" 
    68     __slots__ = tuple([__PRIVATE_ATTR_PREFIX + i  
    69                        for i in CONFIG_FILE_OPTNAMES]) 
     74    __slots__ = tuple([__PRIVATE_ATTR_PREFIX + i for i in CONFIG_FILE_OPTNAMES]) 
    7075    del i 
    7176     
     
    7479        self.__issuerName = None 
    7580        self.__issuerFormat = Issuer.X509_SUBJECT 
    76         self.__nameIdFormat = NameID.UNSPECIFIED 
     81        self.__subjectID = None 
     82        self.__subjectIdFormat = NameID.UNSPECIFIED 
    7783        self.__clockSkewTolerance = timedelta(seconds=0.) 
    7884        self.__verifyTimeConditions = True 
     
    8187 
    8288    def _getNameIdFormat(self): 
    83         return self.__nameIdFormat 
     89        return self.__subjectIdFormat 
    8490 
    8591    def _setNameIdFormat(self, value): 
    86         self.__nameIdFormat = value 
    87  
    88     nameIdFormat = property(_getNameIdFormat, _setNameIdFormat,  
     92        self.__subjectIdFormat = value 
     93 
     94    subjectIdFormat = property(_getNameIdFormat, _setNameIdFormat,  
    8995                            doc="Subject Name ID format") 
    9096 
     
    176182        @rtype: saml.saml2.core.SubjectQuery 
    177183        """ 
    178         if not isinstance(queryClass, SubjectQuery): 
     184        if not issubclass(queryClass, SubjectQuery): 
    179185            raise TypeError('Query class %r is not a SubjectQuery derived type' 
    180186                            % queryClass) 
     
    194200        query.subject = Subject()   
    195201        query.subject.nameID = NameID() 
    196         query.subject.nameID.format = self.nameIdFormat 
     202        query.subject.nameID.format = self.subjectIdFormat 
    197203        query.subject.nameID.value = self.subjectID 
    198204             
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/esg/__init__.py

    r6069 r6570  
    154154    ATTRIBUTES[0].name = EsgSamlNamespaces.FIRSTNAME_ATTRNAME  
    155155    ATTRIBUTES[0].friendlyName = EsgSamlNamespaces.FIRSTNAME_FRIENDLYNAME 
    156     ATTRIBUTES[0].format = XSSTRING_NS 
     156    ATTRIBUTES[0].nameFormat = XSSTRING_NS 
    157157 
    158158    ATTRIBUTES[1].name = EsgSamlNamespaces.LASTNAME_ATTRNAME  
    159159    ATTRIBUTES[1].friendlyName = EsgSamlNamespaces.LASTNAME_FRIENDLYNAME 
    160     ATTRIBUTES[1].format = XSSTRING_NS 
     160    ATTRIBUTES[1].nameFormat = XSSTRING_NS 
    161161     
    162162    ATTRIBUTES[2].name = EsgSamlNamespaces.EMAILADDRESS_ATTRNAME 
    163163    ATTRIBUTES[2].friendlyName = EsgSamlNamespaces.EMAILADDRESS_FRIENDLYNAME 
    164     ATTRIBUTES[2].format =  XSSTRING_NS 
     164    ATTRIBUTES[2].nameFormat =  XSSTRING_NS 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/utils/classfactory.py

    r6440 r6570  
    11""" 
    2 Generic parsers to use when reading in configuration data 
    3 - methods available to deal with both XML and INI (flat text key/val) formats 
     2Class Factory 
     3 
     4NERC DataGrid project 
    45""" 
    56__author__ = "C Byrom - Tessella" 
     
    910__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1011__revision__ = '$Id: $' 
    11 import traceback 
    12 import logging, os, sys 
    13 log = logging.getLogger(__name__) 
    14  
    15  
    16 class ClassFactoryError(Exception): 
    17     """Exception handling for NDG classfactory module.""" 
    18     def __init__(self, msg): 
    19         log.error(msg) 
    20         Exception.__init__(self, msg) 
    21  
    22  
    23 def importClass(moduleName, className=None, objectType=None): 
    24     '''Import a class from a string module name and class name. 
    25      
    26     @param moduleName: Name of module containing the class 
    27     @type moduleName: str  
    28     @param className: Name of the class to import.  If none is given, the  
    29     class name will be assumed to be the last component of modulePath 
    30     @type className: str 
    31     @rtype: class object 
    32     @return: imported class''' 
    33      
    34     if className is None: 
    35         _moduleName, className = moduleName.rsplit('.', 1) 
    36     else: 
    37         _moduleName = moduleName 
    38      
    39     log.debug("Importing class %s ..." % className)  
    40        
    41     module = __import__(_moduleName, globals(), locals(), []) 
    42     components = _moduleName.split('.') 
    43     try: 
    44         for component in components[1:]: 
    45             module = getattr(module, component) 
    46     except AttributeError, e: 
    47         raise AttributeError("Error importing class %s: %s" % 
    48                              (className, traceback.format_exc())) 
    49  
    50     importedClass = getattr(module, className) 
    51  
    52     # Check class inherits from a base class 
    53     if objectType and not issubclass(importedClass, objectType): 
    54         raise TypeError("Specified class %s must be derived from %s; got %s" % 
    55                         (className, objectType, importedClass)) 
    56      
    57     log.info('Imported "%s" class from module, "%s"', className, _moduleName) 
    58     return importedClass 
    59      
    60  
    61 def instantiateClass(moduleName, className=None, moduleFilePath=None,  
    62                      objectType=None, classArgs=(), classProperties={}): 
    63     ''' 
    64     Create and return an instance of the specified class 
    65     @param moduleName: Name of module containing the class 
    66     @type moduleName: str  
    67     @param className: Name of the class to instantiate.  May be None in  
    68     which case, the class name is parsed from the moduleName last element 
    69     @type className: str 
    70     @param moduleFilePath: Path to the module - if unset, assume module on  
    71     system path already 
    72     @type moduleFilePath: str 
    73     @param classProperties: dict of properties to use when instantiating the  
    74     class 
    75     @type classProperties: dict 
    76     @param objectType: expected type for the object to instantiate - to  
    77     enforce use of specific interfaces  
    78     @type objectType: object 
    79     @return: object - instance of the class specified  
    80     ''' 
    81  
    82      
    83     # ensure that classproperties is a dict - NB, it may be passed in as a null 
    84     # value which can override the default val 
    85     if not classProperties: 
    86         classProperties = {} 
    87  
    88     # variable to store original state of the system path 
    89     sysPathBak = None 
    90     try: 
    91         try: 
    92             # Module file path may be None if the new module to be loaded 
    93             # can be found in the existing system path             
    94             if moduleFilePath: 
    95                 if not os.path.exists(moduleFilePath): 
    96                     raise IOError("Module file path '%s' doesn't exist" %  
    97                                   moduleFilePath) 
    98                            
    99                 # Temporarily extend system path ready for import 
    100                 sysPathBak = sys.path 
    101                            
    102                 sys.path.append(moduleFilePath) 
     12from ndg.security.common.utils.factory import (importModuleObject, 
     13                                               callModuleObject) 
     14  
     15def importClass(*arg, **kw): 
     16    """Backwards compatibility - use importModuleObject instead""" 
     17    kw['objectName'] = kw.pop('className', None) 
     18    return importModuleObject(*arg, **kw) 
    10319 
    10420             
    105             # Import module name specified in properties file 
    106             importedClass = importClass(moduleName,  
    107                                         className=className, 
    108                                         objectType=objectType) 
    109         finally: 
    110             # revert back to original sys path, if necessary 
    111             # NB, python requires the use of a try/finally OR a try/except  
    112             # block - not both combined 
    113             if sysPathBak: 
    114                 sys.path = sysPathBak 
    115                              
    116     except Exception, e: 
    117         log.error('%s module import raised %s type exception: %s' %  
    118                   (moduleName, e.__class__, e)) 
    119         raise  
     21def instantiateClass(*arg, **kw): 
     22    """Wrapper to callModuleObject""" 
     23    kw['objectName'] = kw.pop('className', None) 
     24    kw['objectArgs'] = kw.pop('classargs', None) 
     25    kw['objectProperties'] = kw.pop('classProperties', None) 
    12026 
    121     # Instantiate class 
    122     log.debug('Instantiating class "%s"' % importedClass.__name__) 
    123     try: 
    124         if classArgs: 
    125             object = importedClass(*classArgs, **classProperties) 
    126         else: 
    127             object = importedClass(**classProperties) 
    128              
    129         return object 
    130  
    131     except Exception, e: 
    132         log.error("Instantiating class, %s: %s" % (importedClass.__name__,  
    133                                                    traceback.format_exc())) 
    134         raise 
    135              
    136                   
     27    return callModuleObject(*arg, **kw) 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/myproxy/certificate_extapp/saml_attribute_assertion.py

    r6068 r6570  
    3939from saml.xml.etree import AssertionElementTree, ResponseElementTree 
    4040    
    41 from ndg.security.common.saml_utils.bindings import AttributeQuerySslSOAPBinding 
     41from ndg.security.common.saml_utils.binding.soap.attributequery import \ 
     42                                                AttributeQuerySslSOAPBinding 
    4243from ndg.security.common.saml_utils.esg import (EsgSamlNamespaces, 
    4344                                                EsgDefaultQueryAttributes) 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/authz/__init__.py

    r6512 r6570  
    2323from ndg.security.common.utils.classfactory import importClass 
    2424from ndg.security.common.X509 import X509Cert 
    25 from ndg.security.common.saml_utils.bindings import AttributeQuerySslSOAPBinding 
     25from ndg.security.common.saml_utils.binding.soap.attributequery import \ 
     26                                                AttributeQuerySslSOAPBinding 
    2627 
    2728from ndg.security.common.credentialwallet import (NDGCredentialWallet, 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/integration/authz_lite/securedapp.ini

    r6271 r6570  
    9797# If omitted, DN of SSL Cert is used 
    9898pip.attributeQuery.issuerName =  
    99 pip.attributeQuery.clockSkew = 0. 
     99pip.attributeQuery.subjectIdFormat = urn:esg:openid 
     100pip.attributeQuery.clockSkewTolerance = 0. 
    100101pip.attributeQuery.queryAttributes.0 = urn:siteA:security:authz:1.0:attr, , http://www.w3.org/2001/XMLSchema#string 
    101102pip.attributeQuery.sslCACertDir=%(testConfigDir)s/ca 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/attributeauthorityclient/attAuthorityClientTest.cfg

    r6062 r6570  
    7777uri = http://localhost:5000/AttributeAuthority/saml 
    7878subject = https://openid.localhost/philip.kershaw 
    79 attributeQuery.clockSkew = 0. 
     79 
     80attributeQuery.subjectIdFormat = urn:esg:openid 
     81attributeQuery.clockSkewTolerance = 0. 
    8082attributeQuery.issuerName = /O=Site A/CN=Authorisation Service 
    8183attributeQuery.queryAttributes.0 = urn:esg:first:name, FirstName, http://www.w3.org/2001/XMLSchema#string 
     
    8688subject = https://openid.localhost/philip.kershaw 
    8789 
    88 attributeQuery.clockSkew = 0. 
     90attributeQuery.subjectIdFormat = urn:esg:openid 
     91attributeQuery.clockSkewTolerance = 0. 
    8992attributeQuery.issuerName = /O=Site A/CN=Authorisation Service 
    9093attributeQuery.queryAttributes.0 = urn:esg:email:address, EmailAddress, http://www.w3.org/2001/XMLSchema#string 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/attributeauthorityclient/test_attributeauthorityclient.py

    r6052 r6570  
    4040from saml.xml.etree import ResponseElementTree 
    4141 
    42 from ndg.security.common.saml_utils.bindings import SOAPBinding as \ 
     42from ndg.security.common.saml_utils.binding.soap import SOAPBinding as \ 
    4343                                                            SamlSoapBinding 
    44 from ndg.security.common.saml_utils.bindings import AttributeQuerySOAPBinding 
    45 from ndg.security.common.saml_utils.bindings import AttributeQuerySslSOAPBinding 
     44from ndg.security.common.saml_utils.binding.soap.attributequery import ( 
     45                                                AttributeQuerySslSOAPBinding, 
     46                                                AttributeQuerySOAPBinding) 
    4647from ndg.security.common.saml_utils.esg import (EsgSamlNamespaces,  
    4748                                                XSGroupRoleAttributeValue, 
Note: See TracChangeset for help on using the changeset viewer.