Changeset 6033


Ignore:
Timestamp:
20/11/09 16:13:44 (10 years ago)
Author:
pjkersha
Message:

Refactoring Credential Wallet to enable caching of SAML assertions.

Location:
TI12-security/trunk/python
Files:
1 added
10 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/ndg_security_common/ndg/security/common/authz/msi.py

    r6018 r6033  
    1818 
    1919from ndg.security.common.utils import TypedList 
    20  
    21 # For parsing: ElementTree helpers  
    22 getNs = lambda elem: elem.tag.split('}')[0][1:] 
    23 getLocalName = lambda elem: elem.tag.rsplit('}', 1)[ - 1] 
     20from ndg.security.common.utils.etree import QName 
     21 
    2422 
    2523class PolicyParseError(Exception): 
    2624    """Error reading policy attributes from file""" 
    2725 
    28 class Policy(object): 
    29     """NDG MSI Policy.""" 
     26class InvalidPolicyXmlNsError(Exception): 
     27    """Invalid XML namespace for policy document""" 
     28 
     29class PolicyComponent(object): 
     30    """Base class for Policy and Policy subelements""" 
     31    VERSION_1_0_XMLNS = "urn:ndg:security:authz:1.0:policy" 
     32    VERSION_1_1_XMLNS = "urn:ndg:security:authz:1.1:policy" 
     33    XMLNS = (VERSION_1_0_XMLNS, VERSION_1_1_XMLNS) 
     34    __slots__ = ('xmlns', '_PolicyComponent__xmlns') 
     35 
     36    def __init__(self): 
     37        self.__xmlns = None 
     38         
     39    def _getXmlns(self): 
     40        return self.__xmlns 
     41 
     42    def _setXmlns(self, value): 
     43        if not isinstance(value, basestring): 
     44            raise TypeError('Expecting string type for "xmlns" ' 
     45                            'attribute; got %r' % type(value)) 
     46        self.__xmlns = value 
     47 
     48    xmlns = property(_getXmlns, _setXmlns,  
     49                     doc="XML Namespace for policy the document") 
     50     
     51    @property 
     52    def isValidXmlns(self): 
     53        return self.xmlns in PolicyComponent.XMLNS 
     54     
     55     
     56class Policy(PolicyComponent): 
     57    """NDG MSI Policy."""    
     58    DESCRIPTION_LOCALNAME = "Description" 
     59    TARGET_LOCALNAME = "Target" 
     60     
    3061    __slots__ = ( 
    3162        'policyFilePath', 
    3263        'description', 
    33         'targets' 
     64        'targets', 
    3465    ) 
    3566    __slots__ += tuple(["_Policy__%s" % name for name in __slots__]) 
    3667    del name 
     68#    __slots__ += PolicyComponent.__slots__ 
    3769     
    3870    def __init__(self, policyFilePath=None): 
     71        super(Policy, self).__init__() 
    3972        self.__policyFilePath = policyFilePath 
    4073        self.__description = None 
    4174        self.__targets = TypedList(Target) 
    4275 
    43     def getPolicyFilePath(self): 
     76    def _getPolicyFilePath(self): 
    4477        return self.__policyFilePath 
    4578 
    46     def setPolicyFilePath(self, value): 
     79    def _setPolicyFilePath(self, value): 
    4780        if not isinstance(value, basestring): 
    4881            raise TypeError('Expecting string type for "policyFilePath" ' 
     
    5184        self.__policyFilePath = value 
    5285 
    53     policyFilePath = property(getPolicyFilePath, setPolicyFilePath,  
     86    policyFilePath = property(_getPolicyFilePath, _setPolicyFilePath,  
    5487                              doc="Policy file path") 
    5588 
    56     def getTargets(self): 
     89    def _getTargets(self): 
    5790        return self.__targets 
    5891 
    59     def setTargets(self, value): 
     92    def _setTargets(self, value): 
    6093        if (not isinstance(value, TypedList) and  
    6194            not issubclass(value.elementType, Target.__class__)): 
     
    6497        self.__targets = value 
    6598 
    66     targets = property(getTargets, setTargets,  
     99    targets = property(_getTargets, _setTargets,  
    67100                       doc="list of Policy targets") 
    68101 
    69     def getDescription(self): 
     102    def _getDescription(self): 
    70103        return self.__description 
    71104 
    72     def setDescription(self, value): 
     105    def _setDescription(self, value): 
    73106        if not isinstance(value, basestring): 
    74107            raise TypeError('Expecting string type for "description" ' 
     
    76109        self.__description = value 
    77110 
    78     description = property(getDescription, setDescription,  
     111    description = property(_getDescription, _setDescription,  
    79112                           doc="Policy Description text") 
    80113    
     
    84117        elem = ElementTree.parse(self.policyFilePath) 
    85118        root = elem.getroot() 
    86  
     119         
     120        self.xmlns = QName.getNs(root.tag) 
     121        if not self.isValidXmlns: 
     122            raise InvalidPolicyXmlNsError("Namespace %r is recognised; valid " 
     123                                          "namespaces are: %r" % 
     124                                          (self.xmlns, Policy.XMLNS)) 
     125             
    87126        for elem in root: 
    88             localName = getLocalName(elem) 
    89             if localName == "Description": 
     127            localName = QName.getLocalPart(elem.tag) 
     128            if localName == Policy.DESCRIPTION_LOCALNAME: 
    90129                self.description = elem.text.strip() 
    91130                 
    92             elif localName == "Target": 
     131            elif localName == Policy.TARGET_LOCALNAME: 
    93132                self.targets.append(Target.Parse(elem)) 
    94133                 
     
    103142        return policy 
    104143 
    105 class TargetParseError(Exception): 
     144 
     145class TargetParseError(PolicyParseError): 
    106146    """Error reading resource attributes from file""" 
    107147 
    108148import re 
    109149    
    110 class Target(object): 
     150class Target(PolicyComponent): 
    111151    """Define access behaviour for a resource match a given URI pattern""" 
    112152    URI_PATTERN_LOCALNAME = "URIPattern" 
    113     ATTRIBUTE_LOCALNAME = "Attributes" 
     153    ATTRIBUTES_LOCALNAME = "Attributes" 
    114154    ATTRIBUTE_AUTHORITY_LOCALNAME = "AttributeAuthority" 
    115155     
    116156    __slots__ = ( 
    117         URI_PATTERN_LOCALNAME, 
    118         ATTRIBUTE_LOCALNAME, 
    119         ATTRIBUTE_LOCALNAME        
     157        'uriPattern', 
     158        'attributes', 
     159        'regEx'        
    120160    ) 
    121161    __slots__ += tuple(["_Target__%s" % name for name in __slots__]) 
    122162    del name 
     163 
     164    ATTRIBUTE_AUTHORITY_LOCALNAME_DEPRECATED_MSG = """\ 
     165Use of a <%r/> child element within Target elements will be deprecated for future 
     166releases.  Put the Attribute Authority setting in an Attribute  
     167<AttributeAuthorityURI/> element e.g. 
     168 
     169<Target> 
     170    <uriPattern>^/.*</uriPattern> 
     171    <Attributes> 
     172        <Attribute> 
     173            <Name>myattribute</Name> 
     174            <AttributeAuthorityURI>https://myattributeauthority.ac.uk</AttributeAuthorityURI> 
     175        </Attribute> 
     176    </Attributes> 
     177</Target> 
     178"""  % ATTRIBUTE_AUTHORITY_LOCALNAME   
    123179     
    124180    def __init__(self): 
     181        super(Target, self).__init__() 
    125182        self.__uriPattern = None 
    126183        self.__attributes = [] 
     
    160217        self.__regEx = value 
    161218 
    162     regEx = property(getRegEx, setRegEx, dpc="RegEx's Docstring") 
     219    regEx = property(getRegEx, setRegEx, doc="RegEx's Docstring") 
    163220         
    164221    def parse(self, root): 
     222         
     223        self.xmlns = QName.getNs(root.tag) 
     224        version1_0attributeAuthorityURI = None 
     225         
    165226        for elem in root: 
    166             localName = getLocalName(elem) 
     227            localName = QName.getLocalPart(elem.tag) 
    167228            if localName == Target.URI_PATTERN_LOCALNAME: 
    168229                self.uriPattern = elem.text.strip() 
     
    171232            elif localName == Target.ATTRIBUTES_LOCALNAME: 
    172233                for attrElem in elem: 
    173                     self.attributes.append(Attribute(attrElem)) 
     234                    if self.xmlns == Target.VERSION_1_1_XMLNS: 
     235                        self.attributes.append(Attribute.Parse(attrElem)) 
     236                    else: 
     237                        attribute = Attribute() 
     238                        attribute.name = attrElem.text.strip() 
     239                        self.attributes.append(attribute) 
    174240                     
    175241            elif localName == Target.ATTRIBUTE_AUTHORITY_LOCALNAME: 
    176242                # Expecting first element to contain the URI 
    177                 warnings.warn("Use of a %r child element is deprecated for " 
    178                               "Target elements.  Put the Attribute Authority " 
    179                               "setting in an Attribute AttributeAuthorityURI " 
    180                               "element e.g.\n\n" 
    181                               "<Target>\n" 
    182                               "    <Attribute>\n" 
    183                               "        <Name>myattribute</Name>" 
    184                               "        <AttributeAuthorityURI>" 
    185                               "https://myattributeauthority.ac.uk" 
    186                               "</AttributeAuthorityURI>\n" 
    187                               "    </Attribute>\n" 
    188                               "</Target>"                              
    189                                % Target.ATTRIBUTE_AUTHORITY_LOCALNAME,  
    190                               DeprecationWarning) 
     243                warnings.warn( 
     244                        Target.ATTRIBUTE_AUTHORITY_LOCALNAME_DEPRECATED_MSG, 
     245                        PendingDeprecationWarning) 
     246                 
     247                version1_0attributeAuthorityURI = elem[-1].text.strip() 
    191248            else: 
    192                 raise ResourceParseError("Invalid resource attribute: %s" %  
    193                                          localName) 
     249                raise TargetParseError("Invalid Target attribute: %s" %  
     250                                       localName) 
     251                 
     252        if self.xmlns == Target.VERSION_1_0_XMLNS: 
     253            msg = ("Setting all attributes with Attribute Authority " 
     254                   "URI set read using Version 1.0 schema.  This will " 
     255                   "be deprecated in future releases") 
     256             
     257            warnings.warn(msg, PendingDeprecationWarning) 
     258            log.warning(msg) 
     259             
     260            if version1_0attributeAuthorityURI is None: 
     261                raise TargetParseError("Assuming version 1.0 schema " 
     262                                       "for Attribute Authority URI setting " 
     263                                       "but no URI has been set") 
     264                 
     265            for attribute in self.attributes: 
     266                attribute.attributeAuthorityURI = \ 
     267                    version1_0attributeAuthorityURI 
    194268     
    195269    @classmethod 
     
    203277 
    204278 
    205 class Attribute(object): 
     279class AttributeParseError(PolicyParseError): 
     280    """Error parsing a Policy Attribute element""" 
     281     
     282 
     283class Attribute(PolicyComponent): 
    206284    """encapsulate a target attribute including the name and an Attribute 
    207285    Authority from which user attribute information may be queried 
    208286    """ 
    209     NAME_LOCALNAME = "name" 
    210     ATTRIBUTE_AUTHORITY_URI_LOCALNAME = "attributeAuthorityURI" 
     287    NAME_LOCALNAME = "Name" 
     288    ATTRIBUTE_AUTHORITY_URI_LOCALNAME = "AttributeAuthorityURI" 
     289     
     290    __slots__ = ('name', 'attributeAuthorityURI') 
     291    __slots__ += tuple(["_Attribute__%s" % name for name in __slots__]) 
     292    del name 
    211293     
    212294    def __init__(self): 
     295        super(Attribute, self).__init__() 
    213296        self.__name = '' 
    214297        self.__attributeAuthorityURI = None 
     
    217300        return self.__name 
    218301     
    219     def getName(self): 
     302    def _getName(self): 
    220303        return self.__name 
    221304 
    222     def setName(self, value): 
     305    def _setName(self, value): 
    223306        if not isinstance(value, basestring): 
    224307            raise TypeError('Expecting string type for "name"; got %r' % 
     
    230313                    doc="Attribute name") 
    231314         
    232     def getAttributeAuthorityURI(self): 
     315    def _getAttributeAuthorityURI(self): 
    233316        return self.__attributeAuthorityURI 
    234317 
    235     def setAttributeAuthorityURI(self, value): 
     318    def _setAttributeAuthorityURI(self, value): 
    236319        self.__attributeAuthorityURI = value 
    237320 
    238     attributeAuthorityURI = property(getAttributeAuthorityURI,  
    239                                      setAttributeAuthorityURI,  
     321    attributeAuthorityURI = property(_getAttributeAuthorityURI,  
     322                                     _setAttributeAuthorityURI,  
    240323                                     doc="Attribute Authority URI") 
    241324         
    242325    def parse(self, root): 
    243326        """Parse from an ElementTree Element""" 
     327        self.xmlns = QName.getNs(root.tag) 
     328         
    244329        for elem in root: 
    245             localName = getLocalName(elem) 
     330            localName = QName.getLocalPart(elem.tag) 
    246331            if localName == Attribute.ATTRIBUTE_AUTHORITY_URI_LOCALNAME: 
    247332                self.attributeAuthorityURI = elem.text.strip() 
     
    250335                self.name = elem.text.strip() 
    251336            else: 
    252                 raise ResourceParseError("Invalid Attribute element name: %s" %  
     337                raise AttributeParseError("Invalid Attribute element name: %s" %  
    253338                                         localName) 
    254339     
     
    285370        for dictArg in (d, kw): 
    286371            for k in dictArg: 
    287                 if key not in self.__class__.namespaces: 
     372                if k not in self.__class__.namespaces: 
    288373                    raise KeyError('Namespace "%s" not recognised.  Valid ' 
    289374                                   'namespaces are: %s' %  
     
    438523 
    439524from ndg.security.common.wssecurity import WSSecurityConfig 
    440 from ndg.security.common.credentialwallet import CredentialWallet 
     525 
    441526 
    442527class PIP(object): 
     
    461546        # List of CA certificates used to verify peer certificate with SSL 
    462547        # connections to Attribute Authority 
    463         self.sslCACertFilePathList = cfg.get(prefix+'sslCACertFilePathList',[]) 
     548        self.sslCACertFilePathList = cfg.get(prefix+'sslCACertFilePathList', []) 
    464549         
    465550        # List of CA certificates used to verify the signatures of  
  • TI12-security/trunk/python/ndg_security_common/ndg/security/common/credentialwallet.py

    r5355 r6033  
    1 """NDG Credential Wallet 
    2  
    3 NERC Data Grid Project 
     1"""Credential Wallet classes 
     2 
     3NERC DataGrid Project 
    44""" 
    55__author__ = "P J Kershaw" 
     
    1313log = logging.getLogger(__name__) 
    1414 
    15 # Temporary store of certificates for use with CredentialWallet getAttCert() 
    16 import tempfile 
     15import traceback 
    1716 
    1817# Check Attribute Certificate validity times 
    19 from datetime import datetime 
    20 from datetime import timedelta 
    21  
     18from datetime import datetime, timedelta 
    2219 
    2320# Access Attribute Authority's web service using ZSI - allow pass if not  
     
    2825    # AttributeAuthority client package resides with CredentialWallet module in  
    2926    # ndg.security.common 
    30     from ndg.security.common.attributeauthority import \ 
    31         AttributeAuthorityClient, AttributeAuthorityClientError, \ 
    32         AttributeRequestDenied, NoMatchingRoleInTrustedHosts 
     27    from ndg.security.common.attributeauthority import ( 
     28        AttributeAuthorityClient, AttributeAuthorityClientError,  
     29        AttributeRequestDenied, NoMatchingRoleInTrustedHosts) 
    3330    aaImportError = False 
    3431except ImportError: 
    3532    log.warning('Loading CredentialWallet without SOAP interface imports') 
    36     pass 
    3733 
    3834# Likewise - may not want to use WS and use AttributeAuthority locally in which 
    3935# case no need to import it 
    4036try: 
    41     from ndg.security.server.attributeauthority import AttributeAuthority, \ 
    42         AttributeAuthorityError, AttributeAuthorityAccessDenied 
     37    from ndg.security.server.attributeauthority import (AttributeAuthority,  
     38        AttributeAuthorityError, AttributeAuthorityAccessDenied) 
    4339    aaImportError = False 
    4440except: 
    4541    log.warning('Loading CredentialWallet without Attribute Authority ' 
    4642                'interface imports') 
    47     pass 
    4843 
    4944if aaImportError: 
     
    154149 
    155150 
    156 # CredentialWallet is a 'new-style' class inheriting from "object" and making  
    157 # use of new Get/Set methods for hiding of attributes 
    158 class CredentialWallet(object): 
     151class CredentialWalletBase(object): 
     152    """Abstract base class for NDG and SAML Credential Wallet implementations 
     153    """ 
     154    __slots__ = ( 
     155        "userId", 
     156        "attributeAuthorityURI" 
     157        "credentials", 
     158        "credentialsKeyedByURI", 
     159    ) 
     160    __slots__ += tuple(["_CredentialWalletBase__%s" % name  
     161                        for name in __slots__]) 
     162    del name 
     163     
     164    def __init__(self): 
     165        self.__userId = None 
     166        self.__attributeAuthorityURI = None 
     167        self.__credentials = {} 
     168        self.__credentialsKeyedByURI = {} 
     169 
     170    def parseConfig(self, cfg, prefix='', section='DEFAULT'): 
     171        '''Virtual method defines interface to read config file settings 
     172        @type cfg: basestring /ConfigParser derived type 
     173        @param cfg: configuration file path or ConfigParser type object 
     174        @type prefix: basestring 
     175        @param prefix: prefix for option names e.g. "certExtApp." 
     176        @type section: baestring 
     177        @param section: configuration file section from which to extract 
     178        parameters. 
     179        ''' 
     180        raise NotImplementedError(CredentialWalletBase.parseConfig.__doc__) 
     181 
     182    def addCredential(self,  
     183                      credential,  
     184                      attributeAuthorityURI=None, 
     185                      bUpdateCredentialRepository=True): 
     186        """Add a new attribute certificate to the list of credentials held. 
     187 
     188        @type credential: determined by derived class implementation e.g. 
     189        SAML assertion 
     190        @param credential: new attribute Certificate to be added 
     191        @type attributeAuthorityURI: basestring 
     192        @param attributeAuthorityURI: input the Attribute Authority URI from 
     193        which credential was retrieved.  This is added to a dict to enable  
     194        access to a given Attribute Certificate keyed by Attribute Authority  
     195        URI. See the getCredential method. 
     196        @type bUpdateCredentialRepository: bool 
     197        @param bUpdateCredentialRepository: if set to True, and a repository  
     198        exists it will be updated with the new credentials also 
     199         
     200        @rtype: bool 
     201        @return: True if certificate was added otherwise False.  - If an 
     202        existing certificate from the same issuer has a later expiry it will 
     203        take precedence and the new input certificate is ignored.""" 
     204        raise NotImplementedError(BaseCredentialWallet.addCredential.__doc__) 
     205             
     206    def audit(self): 
     207        """Check the credentials held in the wallet removing any that have 
     208        expired or are otherwise invalid.""" 
     209        raise NotImplementedError(BaseCredentialWallet.audit.__doc__) 
     210 
     211    def updateCredentialRepository(self, auditCred=True): 
     212        """Copy over non-persistent credentials held by wallet into the 
     213        perminent repository. 
     214         
     215        @type auditCred: bool 
     216        @param auditCred: filter existing credentials in the repository 
     217        removing invalid ones""" 
     218        raise NotImplementedError( 
     219                    BaseCredentialWallet.updateCredentialRepository.__doc__) 
     220         
     221    def _getCredentials(self): 
     222        """Get Property method.  Credentials dict is read-only but also see  
     223        addCredential method 
     224         
     225        @rtype: dict 
     226        @return: cached ACs indesed by issuing organisation name""" 
     227        return self.__credentials 
     228 
     229    # Publish attribute 
     230    credentials = property(fget=_getCredentials, 
     231                           doc="List of credentials linked to issuing " 
     232                               "authorities") 
     233 
     234    def _getCredentialsKeyedByURI(self): 
     235        """Get Property method for credentials keyed by Attribute Authority URI 
     236        Credentials dict is read-only but also see addCredential method 
     237         
     238        @rtype: dict 
     239        @return: cached ACs indexed by issuing Attribute Authority""" 
     240        return self.__credentialsKeyedByURI 
     241     
     242    # Publish attribute 
     243    credentialsKeyedByURI = property(fget=_getCredentialsKeyedByURI, 
     244                                     doc="List of Attribute Certificates " 
     245                                         "linked to attribute authority URI") 
     246         
     247    def _getUserId(self): 
     248        return self.__userId 
     249 
     250    def _setUserId(self, value): 
     251        if not isinstance(value, basestring): 
     252            raise TypeError('Expecting string type for "userId"; got %r ' 
     253                            'instead' % type(value)) 
     254        self.__userId = value 
     255 
     256    userId = property(_getUserId, _setUserId,  
     257                      doc="User Identity for this wallet") 
     258 
     259    def _getAttributeAuthorityURI(self): 
     260        return self.__attributeAuthorityURI 
     261 
     262    def _setAttributeAuthorityURI(self, value): 
     263        if not isinstance(value, basestring): 
     264            raise TypeError('Expecting string type for "attributeAuthorityURI";' 
     265                            ' got %r instead' % type(value)) 
     266        self.__attributeAuthorityURI = value 
     267 
     268    attributeAuthorityURI = property(_getAttributeAuthorityURI, 
     269                                     _setAttributeAuthorityURI,  
     270                                     doc="Attribute Authority Service URI") 
     271 
     272    def __getstate__(self): 
     273        '''Enable pickling for use with beaker.session''' 
     274        return dict([(attrName, getattr(self, attrName)) 
     275                     for attrName in self.__class__.__slots__]) 
     276         
     277    def __setstate__(self, attrDict): 
     278        '''Enable pickling for use with beaker.session''' 
     279        for attr, val in attrDict.items(): 
     280            setattr(self, attr, val) 
     281             
     282    
     283class CredentialWallet(CredentialWalletBase): 
    159284    """Volatile store of user credentials associated with a user session 
    160285     
     
    267392 
    268393    propertyDefaults = dict( 
    269         userId=None, 
    270394        userX509Cert=None, 
    271395        userX509CertFilePath=None, 
     
    298422        '_attributeAuthority', 
    299423        '_caCertFilePathList', 
    300         '_sslCACertFilePathList', 
    301         '_credentialRepository', 
    302424        '_mapFromTrustedHosts', 
    303425        '_rtnExtAttCertList', 
    304426        '_attCertRefreshElapse', 
    305427        '_cfg', 
    306         '_credentials', 
    307         '_credentialsKeyedByURI', 
    308         '_dn', 
    309         '_attributeAuthorityURI' 
     428        '_dn' 
    310429    ] 
    311430     
     
    336455        log.debug("Calling CredentialWallet.__init__ ...") 
    337456 
     457        super(CredentialWallet, self).__init__() 
     458         
    338459        # Initialise attributes - 1st protected ones 
    339460        attr = {}.fromkeys(CredentialWallet._protectedAttrs) 
     
    358479        if self._userX509Cert: 
    359480            self._dn = self._userX509Cert.dn.serialise() 
    360          
    361          
    362         # Credentials are stored as a dictionary one element per attribute 
    363         # certificate held and indexed by certificate issuer name 
    364         self._credentials = {} 
    365          
    366         # A second dictionary indexes by Attribute Authority URI: 
    367         self._credentialsKeyedByURI = {} 
    368  
    369481 
    370482        # Make a connection to the Credentials Repository 
    371         if self._credentialRepository is None: 
     483        if self.credentialRepository is None: 
    372484            log.info('Applying default CredentialRepository %r for user ' 
    373485                     '"%s"' % (NullCredentialRepository, self.userId)) 
    374             self._credentialRepository = NullCredentialRepository() 
     486            self.credentialRepository = NullCredentialRepository() 
    375487        else: 
    376488            log.info('Checking CredentialRepository for credentials for user ' 
    377489                     '"%s"' % self.userId) 
    378490             
    379             if not issubclass(self._credentialRepository,CredentialRepository): 
    380                 raise CredentialWalletError("Input Credential Repository instance " 
    381                                       "must be of a class derived from " 
    382                                       "\"CredentialRepository\"") 
     491            if not issubclass(self.credentialRepository, CredentialRepository): 
     492                raise CredentialWalletError("Input Credential Repository " 
     493                                            "instance must be of a class " 
     494                                            "derived from " 
     495                                            "\"CredentialRepository\"") 
    383496     
    384497        
    385498            # Check for valid attribute certificates for the user 
    386499            try: 
    387                 self._credentialRepository.auditCredentials(self.userId) 
    388                 userCred=self._credentialRepository.getCredentials(self.userId) 
     500                self.credentialRepository.auditCredentials(self.userId) 
     501                userCred=self.credentialRepository.getCredentials(self.userId) 
    389502     
    390503            except Exception, e: 
     
    402515                    issuerName = attCert['issuerName'] 
    403516                     
    404                     self._credentials[issuerName] = {'id':cred.id,  
     517                    self.credentials[issuerName] = {'id':cred.id,  
    405518                                                     'attCert':attCert}     
    406519            except Exception, e: 
     
    416529            # Filter out expired or otherwise invalid certificates 
    417530            self.audit() 
    418  
    419     def __getstate__(self): 
    420         '''Enable pickling for use with beaker.session''' 
    421         return dict([(attrName, getattr(self, attrName)) \ 
    422                      for attrName in CredentialWallet._protectedAttrs]) 
    423          
    424     def __setstate__(self, attrDict): 
    425         '''Enable pickling for use with beaker.session''' 
    426         for attr, val in attrDict.items(): 
    427             setattr(self, attr, val) 
    428531     
    429532    def parseConfig(self, cfg, prefix='', section='DEFAULT'): 
    430         '''Extract parameters from _cfg config object''' 
     533        '''Extract parameters from cfg config object''' 
    431534         
    432535        if isinstance(cfg, basestring): 
     
    516619    def _setUserX509Cert(self, userX509Cert): 
    517620        "Set property method for X.509 user cert." 
    518         self._userX509Cert = self._setX509Cert(userX509Cert) 
    519          
     621        self._userX509Cert = self._setX509Cert(userX509Cert)        
    520622 
    521623    def _getUserX509Cert(self): 
     
    644746                             doc="Password protecting user private key file") 
    645747         
    646     def _getCredentials(self): 
    647         """Get Property method.  Credentials doct is read-only but also see  
    648         addCredential method 
    649          
    650         @rtype: dict 
    651         @return: cached ACs indesed by issuing organisation name""" 
    652         return self._credentials 
    653  
    654     # Publish attribute 
    655     credentials = property(fget=_getCredentials, 
    656                            doc="List of Attribute Certificates linked to " 
    657                                "issuing authorities") 
    658  
    659     def _getCredentialsKeyedByURI(self): 
    660         """Get Property method for credentials keyed by Attribute Authority URI 
    661         Credentials dict is read-only but also see addCredential method 
    662          
    663         @rtype: dict 
    664         @return: cached ACs indexed by issuing Attribute Authority""" 
    665         return self._credentialsKeyedByURI 
    666      
    667     # Publish attribute 
    668     credentialsKeyedByURI = property(fget=_getCredentialsKeyedByURI, 
    669                                      doc="List of Attribute Certificates " 
    670                                          "linked to attribute authority URI") 
    671          
    672748    def _getCACertFilePathList(self): 
    673749        """Get CA cert or certs used to validate AC signatures and signatures 
     
    697773 
    698774        elif caCertFilePathList is not None: 
    699             raise CredentialWalletError("Input CA Certificate file path is not a " 
    700                                   "valid string")       
     775            raise TypeError('Expecting string/list/tuple or None type for ' 
     776                            '"caCertFilePathList"; got %r type' %  
     777                            type(caCertFilePathList))       
    701778         
    702779    caCertFilePathList = property(fget=_getCACertFilePathList, 
     
    705782                                      "verification of AC and SOAP message " 
    706783                                      "signatures") 
    707  
    708     def _getSSLCACertFilePathList(self): 
    709         """Get CA cert or certs used to validate AC signatures and signatures 
    710         of peer SOAP messages. 
    711          
    712         @rtype sslCACertFilePathList: basestring, list or tuple 
    713         @return sslCACertFilePathList: file path(s) to CA certificates.""" 
    714         return self._sslCACertFilePathList 
    715      
    716     def _setSSLCACertFilePathList(self, sslCACertFilePathList): 
    717         """Set CA cert or certs to validate AC signatures, signatures 
    718         of Attribute Authority SOAP responses and SSL connections where  
    719         AA SOAP service is run over SSL. 
    720          
    721         @type sslCACertFilePathList: basestring, list, tuple or None 
    722         @param sslCACertFilePathList: file path(s) to CA certificates.  If None 
    723         then the input is quietly ignored.""" 
    724          
    725         if isinstance(sslCACertFilePathList, basestring): 
    726            self._sslCACertFilePathList = [sslCACertFilePathList] 
    727             
    728         elif isinstance(sslCACertFilePathList, list): 
    729            self._sslCACertFilePathList = sslCACertFilePathList 
    730             
    731         elif isinstance(sslCACertFilePathList, tuple): 
    732            self._sslCACertFilePathList = list(sslCACertFilePathList) 
    733  
    734         elif sslCACertFilePathList is not None: 
    735             raise CredentialWalletError("Input CA Certificate file path is " 
    736                                         "not a valid string")       
    737          
    738     sslCACertFilePathList = property(fget=_getSSLCACertFilePathList, 
    739                                   fset=_setSSLCACertFilePathList, 
    740                                   doc="CA Certificates - used for " 
    741                                       "verification of peer certs in SSL " 
    742                                       "connections") 
    743          
    744     def _getAttributeAuthorityURI(self): 
    745         """Get property method for Attribute Authority Web Service URI to 
    746         connect to.""" 
    747         return self._attributeAuthorityURI 
    748784             
    749785    def _setAttributeAuthorityURI(self, attributeAuthorityURI): 
     
    755791        @param attributeAuthorityURI: Attribute Authority Web Service URI.  Set 
    756792        to None to initialise.""" 
    757         if attributeAuthorityURI is not None and \ 
    758            not isinstance(attributeAuthorityURI, basestring): 
    759             raise AttributeError("URI must be a string or None type") 
    760          
    761         self._attributeAuthorityURI = attributeAuthorityURI 
    762          
     793        super(CredentialWallet, self)._setAttributeAuthorityURI( 
     794                                                        attributeAuthorityURI) 
     795               
    763796        # Re-initialize local instance 
    764         self._attributeAuthority = \ 
    765                     CredentialWallet.propertyDefaults['attributeAuthority'] 
    766              
    767     attributeAuthorityURI = property(fget=_getAttributeAuthorityURI, 
    768                                      fset=_setAttributeAuthorityURI, 
    769                                      doc="Attribute Authority address - " 
    770                                          "setting also sets up " 
    771                                          "AttributeAuthorityClient instance!") 
     797        self._attributeAuthority = CredentialWallet.propertyDefaults[ 
     798                                                        'attributeAuthority'] 
     799             
     800    attributeAuthorityURI = property( 
     801                            fget=CredentialWalletBase._getAttributeAuthorityURI, 
     802                            fset=_setAttributeAuthorityURI, 
     803                            doc="Attribute Authority address - setting also " 
     804                            "sets up AttributeAuthorityClient instance!") 
    772805 
    773806    def _getAttributeAuthority(self): 
     
    870903                        "wallet") 
    871904            return True 
    872  
    873905 
    874906    def addCredential(self,  
     
    895927 
    896928        # Check input 
    897         if not isinstance(attCert, AttCert): 
    898             raise CredentialWalletError("Attribute Certificate must be an " 
    899                                         "AttCert type object") 
    900  
     929        if not isinstance(credential, attCert): 
     930            raise CredentialWalletError("Credential must be an %r type object" % 
     931                                        AttCert) 
     932             
    901933        # Check certificate validity 
    902934        try: 
     
    905937        except AttCertError, e: 
    906938            raise CredentialWalletError("Adding Credential: %s" % e) 
    907          
    908939 
    909940        # Check to see if there is an existing Attribute Certificate held 
     
    914945        issuerName = attCert['issuerName'] 
    915946         
    916         if issuerName in self._credentials: 
     947        if issuerName in self.credentials: 
    917948            # There is an existing certificate held with the same issuing 
    918949            # host name as the new certificate 
    919             attCertOld = self._credentials[issuerName]['attCert'] 
     950            attCertOld = self.credentials[issuerName]['attCert'] 
    920951 
    921952            # Get expiry times in datetime format to allow comparison 
     
    932963            # from the CredentialRepository during creation of the wallet will 
    933964            # have +ve IDs previously allocated by the database 
    934             self._credentials[issuerName] = { 
     965            self.credentials[issuerName] = { 
    935966                'id': -1,  
    936967                'attCert': attCert, 
     
    940971 
    941972            if attributeAuthorityURI: 
    942                 self._credentialsKeyedByURI[attributeAuthorityURI] = \ 
    943                     self._credentials[issuerName] 
     973                self.credentialsKeyedByURI[attributeAuthorityURI] = \ 
     974                    self.credentials[issuerName] 
    944975             
    945976            # Update the Credentials Repository - the permanent store of user 
    946977            # authorisation credentials.  This allows credentials for previous 
    947978            # sessions to be re-instated 
    948             if self._credentialRepository and bUpdateCredentialRepository: 
     979            if self.credentialRepository and bUpdateCredentialRepository: 
    949980                self.updateCredentialRepository() 
    950981 
     
    966997        # 
    967998        # P J Kershaw 12/09/05 
    968         for key, val in self._credentials.items(): 
     999        for key, val in self.credentials.items(): 
    9691000            if not val['attCert'].isValid(chkSig=False): 
    970                 del self._credentials[key] 
    971  
     1001                del self.credentials[key] 
    9721002 
    9731003    def updateCredentialRepository(self, auditCred=True): 
     
    9811011        log.debug("CredentialWallet.updateCredentialRepository ...") 
    9821012         
    983         if not self._credentialRepository: 
    984             raise CredentialWalletError("No Credential Repository has been created " 
    985                                   "for this wallet") 
     1013        if not self.credentialRepository: 
     1014            raise CredentialWalletError("No Credential Repository has been " 
     1015                                        "created for this wallet") 
    9861016                             
    9871017        # Filter out invalid certs unless auditCred flag is explicitly set to 
     
    9901020 
    9911021        # Update the database - only add new entries i.e. with an ID of -1 
    992         attCertList = [i['attCert'] for i in self._credentials.values() \ 
     1022        attCertList = [i['attCert'] for i in self.credentials.values()  
    9931023                       if i['id'] == -1] 
    9941024 
    995         self._credentialRepository.addCredentials(self.userId, attCertList) 
    996  
     1025        self.credentialRepository.addCredentials(self.userId, attCertList) 
    9971026 
    9981027    def _createAttributeAuthorityClnt(self, attributeAuthorityURI): 
     
    10101039        attributeAuthorityClnt = AttributeAuthorityClient( 
    10111040                            uri=attributeAuthorityURI, 
    1012                             sslCACertFilePathList=self._sslCACertFilePathList, 
     1041                            sslCACertFilePathList=self.sslCACertFilePathList, 
    10131042                            cfg=self.wssCfgFilePath or self._cfg, 
    10141043                            cfgFileSection=self.wssCfgSection, 
     
    10271056                attributeAuthorityClnt.signatureHandler.reqBinSecTokValType = \ 
    10281057                            SignatureHandler.binSecTokValType["X509PKIPathv1"] 
    1029                 attributeAuthorityClnt.signatureHandler.signingCertChain = \ 
    1030                                     (self.issuingX509Cert, self.userX509Cert)                 
     1058                attributeAuthorityClnt.signatureHandler.signingCertChain = ( 
     1059                                    self.issuingX509Cert, self.userX509Cert)                 
    10311060 
    10321061                attributeAuthorityClnt.signatureHandler.signingPriKey = \ 
     
    10581087         
    10591088        @type attributeAuthorityURI: string 
    1060         @param attributeAuthorityURI: to call as a web service, specify the URI for the  
    1061         Attribute Authority. 
     1089        @param attributeAuthorityURI: to call as a web service, specify the URI  
     1090        for the Attribute Authority. 
    10621091         
    10631092        @type attributeAuthority: ndg.security.server.attributeauthority.AttributeAuthority 
     
    11491178        return attCert 
    11501179 
    1151  
    11521180    def _getAAHostInfo(self,  
    11531181                       attributeAuthority=None, 
     
    11611189         
    11621190        @type attributeAuthorityURI: string 
    1163         @param attributeAuthorityURI: to call as a web service, specify the URI for the  
    1164         Attribute Authority. 
     1191        @param attributeAuthorityURI: to call as a web service, specify the URI 
     1192        for the Attribute Authority. 
    11651193         
    11661194        @type attributeAuthority: string 
     
    12051233            raise 
    12061234 
    1207  
    12081235    def _getAATrustedHostInfo(self,  
    12091236                              userRole=None, 
     
    12191246         
    12201247        @type attributeAuthorityURI: string 
    1221         @param attributeAuthorityURI: to call as a web service, specify the URI for the  
    1222         Attribute Authority. 
     1248        @param attributeAuthorityURI: to call as a web service, specify the URI  
     1249        for the Attribute Authority. 
    12231250         
    12241251        @type attributeAuthority: string 
     
    12631290            log.error("Requesting trusted host info: %s" % e) 
    12641291            raise 
    1265  
    12661292 
    12671293    def getAttCert(self, 
     
    13861412            self.attributeAuthority = attributeAuthority 
    13871413            
    1388         if not refreshAttCert and self._credentials: 
     1414        if not refreshAttCert and self.credentials: 
    13891415            # Refresh flag is not set so it's OK to check for any existing 
    13901416            # Attribute Certificate in the wallet whose issuerName match the  
     
    14011427             
    14021428            # Look in the wallet for an AC with the same issuer name 
    1403             if aaName in self._credentials: 
     1429            if aaName in self.credentials: 
    14041430                # Existing Attribute Certificate found in wallet - Check that  
    14051431                # it will be valid for at least the next 2 hours 
     
    14101436                        timedelta(seconds=self.attCertRefreshElapse) 
    14111437                 
    1412                 attCert = self._credentials[aaName]['attCert'] 
     1438                attCert = self.credentials[aaName]['attCert'] 
    14131439                if attCert.isValidTime(dtNow=dtNow): 
    14141440                    log.info("Retrieved an existing %s AC from the wallet" %  
    14151441                             aaName) 
    14161442                    return attCert 
    1417              
    1418              
     1443                       
    14191444        # Check for settings from input, if not set use previous settings 
    14201445        # made 
     
    14241449        if rtnExtAttCertList is not None: 
    14251450            self.rtnExtAttCertList = rtnExtAttCertList 
    1426  
    14271451 
    14281452        # Check for list of external trusted hosts (other trusted NDG data  
     
    14421466            # Nb. Any extAttCertList is overriden by extTrustedHostList being 
    14431467            # set 
    1444             extAttCertList = [self._credentials[hostName]['attCert'] \ 
    1445                               for hostName in extTrustedHostList \ 
    1446                               if hostName in self._credentials] 
     1468            extAttCertList = [self.credentials[hostName]['attCert']  
     1469                              for hostName in extTrustedHostList  
     1470                              if hostName in self.credentials] 
    14471471 
    14481472        # Set an empty list to trigger an AttributeError by initialising it to 
     
    14701494                # List has been emptied without attribute request succeeding - 
    14711495                # give up 
    1472                 errMsg = "Attempting to obtained a mapped certificate: " + \ 
    1473                          "no external attribute certificates are available" 
     1496                errMsg = ("Attempting to obtained a mapped certificate: " 
     1497                          "no external attribute certificates are available") 
    14741498                     
    14751499                # Add the exception form the last call to the Attribute 
     
    15271551                        "which to make a mapping") 
    15281552 
    1529                  
    15301553                # Initialise external certificate list here - if none are 
    15311554                # found IndexError will be raised on the next iteration and 
     
    15371560                log.debug("Checking wallet for ACs issued by one of the " 
    15381561                          "trusted hosts...") 
    1539                 for hostName in self._credentials: 
     1562                for hostName in self.credentials: 
    15401563 
    15411564                    # Nb. Candidate certificates for mappings must have 
    15421565                    # original provenance and contain at least one of the 
    15431566                    # required roles 
    1544                     attCert = self._credentials[hostName]['attCert'] 
     1567                    attCert = self.credentials[hostName]['attCert'] 
    15451568                     
    15461569                    if hostName in trustedHostInfo and attCert.isOriginal():                         
     
    15481571                            if role in trustedHostInfo[hostName]['role']:                                 
    15491572                                extAttCertList.append(attCert) 
    1550  
    15511573 
    15521574                if not extAttCertList: 
     
    15631585                        try: 
    15641586                            # Try request to trusted host 
    1565                             extAttCert = self._getAttCert(\ 
     1587                            extAttCert = self._getAttCert( 
    15661588                                        attributeAuthorityURI=info['aaURI']) 
    15671589 
    15681590                            # Check the certificate contains at least one of 
    15691591                            # the required roles 
    1570                             if [True for r in extAttCert.roles \ 
     1592                            if [True for r in extAttCert.roles  
    15711593                                if r in info['role']]: 
    15721594                               extAttCertList.append(extAttCert) 
     
    15821604                                        ' resulted in: %s' % (info['aaURI'],e)) 
    15831605                             
    1584                      
    15851606                if not extAttCertList:                         
    15861607                    raise CredentialWalletAttributeRequestDenied( 
     
    16021623                                            trustedHostInfo=trustedHostInfo)             
    16031624 
    1604  
     1625"""Alias to CredentialWallet to make distinction between this and the SAML 
     1626implementation""" 
     1627NDGCredentialWallet = CredentialWallet 
     1628 
     1629 
     1630class SamlCredentialWalletAttributeQueryResponseError(CredentialWalletError): 
     1631    """Attribute Authority returned a SAML Response error code""" 
     1632    def __init__(self, *arg, **kw): 
     1633        SamlCredentialWalletError.__init__(self, *arg, **kw) 
     1634        self.__status = Status() 
     1635        self.__status.statusCode = StatusCode() 
     1636        self.__status.statusMessage = StatusMessage() 
     1637     
     1638    def _getStatus(self): 
     1639        '''Gets the Status of this response. 
     1640         
     1641        @return the Status of this response 
     1642        ''' 
     1643        return self.__status 
     1644 
     1645    def _setStatus(self, value): 
     1646        '''Sets the Status of this response. 
     1647         
     1648        @param value: the Status of this response 
     1649        ''' 
     1650        if not isinstance(value, Status): 
     1651            raise TypeError('"status" must be a %r, got %r' % (Status, 
     1652                                                               type(value))) 
     1653        self.__status = value 
     1654         
     1655    status = property(fget=_getStatus, fset=_setStatus,  
     1656                      doc="Attribute Authority SAML Response error status") 
     1657     
     1658    def __str__(self): 
     1659        if self.status is not None: 
     1660            return self.status.statusMessage.value or '' 
     1661        else: 
     1662            return '' 
     1663         
     1664from uuid import uuid4 
     1665try: # >= python 2.5 
     1666    from xml.etree import ElementTree 
     1667except ImportError: 
     1668    import ElementTree 
     1669  
     1670import saml    
     1671from saml.utils import SAMLDateTime 
     1672from saml.common.xml import SAMLConstants 
     1673from saml.saml2.core import (Attribute, 
     1674                             Assertion,  
     1675                             SAMLVersion,  
     1676                             Subject,  
     1677                             NameID,  
     1678                             Issuer,  
     1679                             AttributeQuery,  
     1680                             XSStringAttributeValue,  
     1681                             Status, 
     1682                             StatusCode, 
     1683                             StatusMessage) 
     1684from saml.xml.etree import AssertionElementTree, ResponseElementTree 
     1685    
     1686from ndg.security.common.saml.bindings import SOAPBinding as SamlSoapBinding 
     1687from ndg.security.common.saml.esg import EsgSamlNamespaces 
     1688from ndg.security.common.X509 import X500DN 
     1689from ndg.security.common.utils.m2crypto import SSLContextProxy 
     1690from ndg.security.common.utils.etree import prettyPrint 
     1691from ndg.security.common.utils.configfileparsers import (      
     1692                                                    CaseSensitiveConfigParser,) 
     1693 
     1694 
     1695class SamlCredentialWallet(CredentialWalletBase, SSLContextProxy): 
     1696    """CredentialWallet for Earth System Grid supporting SAML based Attribute  
     1697    Queries 
     1698     
     1699    @cvar DEFAULT_ATTR_DESCR: default attribute to query""" 
     1700     
     1701    XSSTRING_NS = "%s#%s" % ( 
     1702        SAMLConstants.XSD_NS, 
     1703        XSStringAttributeValue.TYPE_LOCAL_NAME 
     1704    ) 
     1705    N_ATTR_DESCR_ELEM_ITEMS = 3 
     1706     
     1707    DEFAULT_ATTR_DESCR = ( 
     1708        (EsgSamlNamespaces.FIRSTNAME_ATTRNAME,  
     1709         EsgSamlNamespaces.FIRSTNAME_FRIENDLYNAME,  
     1710         XSSTRING_NS), 
     1711        (EsgSamlNamespaces.LASTNAME_ATTRNAME,  
     1712         EsgSamlNamespaces.LASTNAME_FRIENDLYNAME,  
     1713         XSSTRING_NS), 
     1714        (EsgSamlNamespaces.EMAILADDRESS_ATTRNAME,  
     1715         EsgSamlNamespaces.EMAILADDRESS_FRIENDLYNAME,  
     1716         XSSTRING_NS), 
     1717    ) 
     1718    ESG_NAME_ID_FORMAT = EsgSamlNamespaces.NAMEID_FORMAT 
     1719     
     1720    ATTRIBUTE_AUTHORITY_URI_OPTNAME = 'attributeAuthorityURI' 
     1721    ISSUER_DN_OPTNAME = 'issuerDN' 
     1722    CLOCK_SKEW_OPTNAME = 'clockSkew' 
     1723     
     1724    CONFIG_FILE_OPTNAMES = ( 
     1725        ATTRIBUTE_AUTHORITY_URI_OPTNAME, 
     1726        ISSUER_DN_OPTNAME,                  
     1727        CLOCK_SKEW_OPTNAME             
     1728    ) 
     1729    __slots__ = ( 
     1730       'attributeDescr' 
     1731    ) 
     1732    __slots__ += CONFIG_FILE_OPTNAMES 
     1733    __PRIVATE_ATTR_PREFIX = '_SamlCredentialWallet__' 
     1734    __slots__ += tuple([__PRIVATE_ATTR_PREFIX + i for i in __slots__]) 
     1735    del i 
     1736     
     1737    CREDENTIAL_REPOSITORY_NOT_SUPPORTED_MSG = ("SamlCredentialWallet doesn't " 
     1738                                               "support the CredentialRepository" 
     1739                                               " interface") 
     1740    def __init__(self): 
     1741        super(SamlCredentialWallet, self).__init__() 
     1742         
     1743        self.__issuerDN = None 
     1744        self.__clockSkew = timedelta(seconds=0.) 
     1745                
     1746        # Use property here as a safeguard in case DEFAULT_ATTR_DESCR has been 
     1747        # altered 
     1748        self.attributeDescr = SamlCredentialWallet.DEFAULT_ATTR_DESCR 
     1749 
     1750    @classmethod 
     1751    def fromConfig(cls, cfg, **kw): 
     1752        '''Alternative constructor makes object from config file settings 
     1753        @type cfg: basestring /ConfigParser derived type 
     1754        @param cfg: configuration file path or ConfigParser type object 
     1755        @rtype: ndg.security.common.credentialWallet.SamlCredentialWallet 
     1756        @return: new instance of this class 
     1757        ''' 
     1758        credentialWallet = cls() 
     1759        credentialWallet.parseConfig(cfg, **kw) 
     1760         
     1761        return credentialWallet 
     1762 
     1763    def parseConfig(self, cfg, prefix='', section='DEFAULT'): 
     1764        '''Read config file settings 
     1765        @type cfg: basestring /ConfigParser derived type 
     1766        @param cfg: configuration file path or ConfigParser type object 
     1767        @type prefix: basestring 
     1768        @param prefix: prefix for option names e.g. "certExtApp." 
     1769        @type section: baestring 
     1770        @param section: configuration file section from which to extract 
     1771        parameters. 
     1772        ''' 
     1773         
     1774        if isinstance(cfg, basestring): 
     1775            cfgFilePath = os.path.expandvars(cfg) 
     1776            _cfg = CaseSensitiveConfigParser() 
     1777            _cfg.read(configFilePath) 
     1778             
     1779        elif isinstance(cfg, ConfigParser): 
     1780            _cfg = cfg    
     1781        else: 
     1782            raise AttributeError('Expecting basestring or ConfigParser type ' 
     1783                                 'for "cfg" attribute; got %r type' % type(cfg))      
     1784         
     1785        for optName in SamlCredentialWallet.CONFIG_FILE_OPTNAMES: 
     1786            val = _cfg.get(section, prefix+optName) 
     1787            setattr(self, optName, val) 
     1788             
     1789    def _getAttributeDescr(self): 
     1790        return self.__attributeDescr 
     1791 
     1792    def _setAttributeDescr(self, value): 
     1793        if not isinstance(value, tuple): 
     1794            raise TypeError('Expecting tuple type for "attributeDescr";' 
     1795                            ' got %r instead' % type(value)) 
     1796             
     1797        for i in value: 
     1798            if not isinstance(value, tuple): 
     1799                raise TypeError('Expecting tuple type for "attributeDescr" ' 
     1800                                'tuple sub-elements; got %r instead' %  
     1801                                type(value)) 
     1802            if len(i) != SamlCredentialWallet.N_ATTR_DESCR_ELEM_ITEMS: 
     1803                raise TypeError('Expecting %d element tuple for ' 
     1804                                '"attributeDescr" sub-elements; got %d ' 
     1805                                'elements instead' %  
     1806                                (SamlCredentialWallet.N_ATTR_DESCR_ELEM_ITEMS, 
     1807                                 len(i))) 
     1808                 
     1809        self.__attributeDescr = value 
     1810     
     1811    attributeDescr = property(_getAttributeDescr,  
     1812                              _setAttributeDescr,  
     1813                              doc="List of name, friendly name, format tuples " 
     1814                                  "determining attributes to query from the " 
     1815                                  "Attribute Authority") 
     1816 
     1817    def _getIssuerDN(self): 
     1818        return self.__issuerDN 
     1819 
     1820    def _setIssuerDN(self, value): 
     1821        if isinstance(value, basestring): 
     1822            self.__issuerDN = X500DN.fromString(value) 
     1823             
     1824        elif isinstance(value, X500DN): 
     1825            self.__issuerDN = value 
     1826        else: 
     1827            raise TypeError('Expecting string or X500DN type for "issuerDN"; ' 
     1828                            'got %r instead' % type(value)) 
     1829        self.__issuerDN = value 
     1830 
     1831    issuerDN = property(_getIssuerDN, _setIssuerDN,  
     1832                        doc="Distinguished Name of issuer of SAML Attribute " 
     1833                            "Query to Attribute Authority") 
     1834 
     1835    def _getClockSkew(self): 
     1836        return self.__clockSkew 
     1837 
     1838    def _setClockSkew(self, value): 
     1839        if isinstance(value, (float, int, long)): 
     1840            self.__clockSkew = timedelta(seconds=value) 
     1841             
     1842        elif isinstance(value, basestring): 
     1843            self.__clockSkew = timedelta(seconds=float(value)) 
     1844        else: 
     1845            raise TypeError('Expecting float, int, long or string type for ' 
     1846                            '"clockSkew"; got %r' % type(value)) 
     1847 
     1848    clockSkew = property(fget=_getClockSkew,  
     1849                         fset=_setClockSkew,  
     1850                         doc="Allow a clock skew in seconds for SAML Attribute" 
     1851                             " Query issueInstant parameter check") 
     1852         
     1853    def __getstate__(self): 
     1854        '''Specific implementation needed with __slots__''' 
     1855        return dict([(attrName, getattr(self, attrName))  
     1856                     for attrName in SamlCredentialWallet.__slots__]) 
     1857         
     1858    def __setstate__(self, attrDict): 
     1859        '''Specific implementation needed with __slots__''' 
     1860        for attr, val in attrDict.items(): 
     1861            setattr(self, attr, val) 
     1862     
     1863    @staticmethod 
     1864    def serialiseAssertion(assertion): 
     1865        """Convert SAML assertion object into a string""" 
     1866        samlAssertionElem = AssertionElementTree.toXML(assertion) 
     1867        return ElementTree.tostring(samlAssertionElem) 
     1868         
     1869    def attributeQuery(self): 
     1870        """Query an Attribute Authority to retrieve an assertion for the  
     1871        given user""" 
     1872                 
     1873        # Create a SAML attribute query 
     1874        attributeQuery = AttributeQuery() 
     1875        attributeQuery.version = SAMLVersion(SAMLVersion.VERSION_20) 
     1876        attributeQuery.id = str(uuid4()) 
     1877        attributeQuery.issueInstant = datetime.utcnow() 
     1878         
     1879        attributeQuery.issuer = Issuer() 
     1880        attributeQuery.issuer.format = Issuer.X509_SUBJECT 
     1881        attributeQuery.issuer.value = self.issuerDN 
     1882                         
     1883        attributeQuery.subject = Subject()   
     1884        attributeQuery.subject.nameID = NameID() 
     1885        attributeQuery.subject.nameID.format = \ 
     1886                                        SamlCredentialWallet.ESG_NAME_ID_FORMAT 
     1887        attributeQuery.subject.nameID.value = self.userId 
     1888                   
     1889        # Add list of attributes to query                       
     1890        for name, friendlyName, format in self.attributeDescr: 
     1891            attribute = Attribute() 
     1892            attribute.name = name 
     1893            attribute.nameFormat = format 
     1894            attribute.friendlyName = friendlyName 
     1895     
     1896            attributeQuery.attributes.append(attribute) 
     1897 
     1898        # Make query over SOAP interface to remote service 
     1899        binding = SamlSoapBinding() 
     1900        response = binding.attributeQuery(attributeQuery,  
     1901                                          self.attributeAuthorityURI) 
     1902         
     1903        if log.level <= logging.DEBUG:             
     1904            log.debug("Attribute Authority [%s] SAML Response:",  
     1905                      self.attributeAuthorityURI) 
     1906            log.debug("_"*80) 
     1907            responseElem = ResponseElementTree.toXML(response) 
     1908            log.debug(prettyPrint(responseElem)) 
     1909         
     1910        if response.status.statusCode.value != StatusCode.SUCCESS_URI: 
     1911            samlRespError = SamlCredentialWalletAttributeQueryResponseError() 
     1912            samlRespError.status = response.status 
     1913            raise samlRespError 
     1914         
     1915        # Check Query ID matches the query ID the service received 
     1916        if response.inResponseTo != attributeQuery.id: 
     1917            samlRespError = SamlCredentialWalletAttributeQueryResponseError() 
     1918            samlRespError.status = response.status 
     1919            raise samlRespError 
     1920         
     1921        utcNow = datetime.utcnow() + self.clockSkew 
     1922        if response.issueInstant > utcNow: 
     1923            samlRespError = SamlCredentialWalletAttributeQueryResponseError() 
     1924             
     1925            msg = ('SAML Attribute Response issueInstant [%s] is after ' 
     1926                   'the current clock time [%s]' %  
     1927                   (attributeQuery.issueInstant, SAMLDateTime.toString(utcNow))) 
     1928                       
     1929            samlRespError.status.statusCode.value = StatusCode.RESPONDER_URI 
     1930            samlRespError.status.statusMessage.value = msg 
     1931            raise samlRespError 
     1932         
     1933        if utcNow < response.assertions[-1].conditions.notBefore: 
     1934            samlRespError = SamlCredentialWalletAttributeQueryResponseError() 
     1935             
     1936            msg = ('The current clock time [%s] is before the SAML Attribute ' 
     1937                   'Response assertion conditions not before time [%s]' %  
     1938                   (SAMLDateTime.toString(utcNow), 
     1939                    response.assertions[-1].conditions.notBefore)) 
     1940                       
     1941            samlRespError.status.statusCode.value = StatusCode.RESPONDER_URI 
     1942            samlRespError.status.statusMessage.value = msg 
     1943            raise samlRespError 
     1944          
     1945        if utcNow >= response.assertions[-1].conditions.notOnOrAfter: 
     1946            samlRespError = SamlCredentialWalletAttributeQueryResponseError()         
     1947             
     1948            msg = ('The current clock time [%s] is on or after the SAML ' 
     1949                   'Attribute Response assertion conditions not on or after ' 
     1950                   'time [%s]' %  
     1951                   (SAMLDateTime.toString(utcNow), 
     1952                    response.assertions[-1].conditions.notOnOrAfter)) 
     1953                       
     1954            samlRespError.status.statusCode.value = StatusCode.RESPONDER_URI 
     1955            samlRespError.status.statusMessage.value = msg 
     1956            raise samlRespError 
     1957 
     1958 
     1959        # Add credential into wallet 
     1960        # 
     1961        # Nb. if the certificates signature is invalid, it will be rejected 
     1962        log.debug("Adding credentials into wallet...") 
     1963        for assertion in response.assertions: 
     1964            self.addCredential(assertion) 
     1965 
     1966    def addCredential(self,  
     1967                      credential,  
     1968                      attributeAuthorityURI=None, 
     1969                      bUpdateCredentialRepository=False): 
     1970        """Add a new assertion to the list of assertion credentials held. 
     1971 
     1972        @type credential: SAML assertion 
     1973        @param credential: new assertion to be added 
     1974        @type attributeAuthorityURI: basestring 
     1975        @param attributeAuthorityURI: input the Attribute Authority URI from 
     1976        which credential was retrieved.  This is added to a dict to enable  
     1977        access to a given Attribute Certificate keyed by Attribute Authority  
     1978        URI. See the getCredential method. 
     1979        @type bUpdateCredentialRepository: bool 
     1980        @param bUpdateCredentialRepository: if set to True, and a repository  
     1981        exists it will be updated with the new credentials also 
     1982         
     1983        @rtype: bool 
     1984        @return: True if certificate was added otherwise False.  - If an 
     1985        existing certificate from the same issuer has a later expiry it will 
     1986        take precedence and the new input certificate is ignored.""" 
     1987         
     1988        # Check input 
     1989        if not isinstance(credential, Assertion): 
     1990            raise CredentialWalletError("Input credential must be an " 
     1991                                        "%r type object" % Assertion)         
     1992 
     1993        # Check to see if there is an existing Attribute Certificate held 
     1994        # that was issued by the same host.  If so, compare the expiry time. 
     1995        # The one with the latest expiry will be retained and the other 
     1996        # ingored 
     1997        bUpdateCred = True 
     1998        issuerName = attCert['issuerName'] 
     1999         
     2000        if issuerName in self.credentials: 
     2001            # There is an existing certificate held with the same issuing 
     2002            # host name as the new certificate 
     2003            attCertOld = self.credentials[issuerName]['attCert'] 
     2004 
     2005            # Get expiry times in datetime format to allow comparison 
     2006            dtAttCertOldNotAfter = attCertOld.getValidityNotAfter(\ 
     2007                                                            asDatetime=True) 
     2008            dtAttCertNotAfter = attCert.getValidityNotAfter(asDatetime=True) 
     2009 
     2010            # If the new certificate has an earlier expiry time then ignore it 
     2011            bUpdateCred = dtAttCertNotAfter > dtAttCertOldNotAfter 
     2012 
     2013                 
     2014        if bUpdateCred: 
     2015            # Update: Nb. -1 ID value flags item as new.  Items read in 
     2016            # from the CredentialRepository during creation of the wallet will 
     2017            # have +ve IDs previously allocated by the database 
     2018            self.credentials[issuerName] = { 
     2019                'id': -1,  
     2020                'attCert': attCert, 
     2021                'issuerName': issuerName, 
     2022                'attributeAuthorityURI': attributeAuthorityURI 
     2023            } 
     2024 
     2025            if attributeAuthorityURI: 
     2026                self.credentialsKeyedByURI[attributeAuthorityURI] = \ 
     2027                    self.credentials[issuerName] 
     2028             
     2029            # Update the Credentials Repository - the permanent store of user 
     2030            # authorisation credentials.  This allows credentials for previous 
     2031            # sessions to be re-instated 
     2032            if bUpdateCredentialRepository: 
     2033                self.updateCredentialRepository() 
     2034 
     2035        # Flag to caller to indicate whether the input certificate was added 
     2036        # to the credentials or an exsiting certificate from the same issuer 
     2037        # took precedence 
     2038        return bUpdateCred 
     2039                         
     2040    def audit(self): 
     2041        """Check the credentials held in the wallet removing any that have 
     2042        expired or are otherwise invalid.""" 
     2043 
     2044        log.debug("CredentialWallet.audit ...") 
     2045         
     2046        for key, val in self.credentials.items(): 
     2047            if not self.isValidCredential(val['attCert']): 
     2048                del self.credentials[key] 
     2049 
     2050    def updateCredentialRepository(self, auditCred=True): 
     2051        msg = SamlCredentialWallet.CREDENTIAL_REPOSITORY_NOT_SUPPORTED_MSG 
     2052        log.warning(msg) 
     2053        warnings.warn(msg) 
     2054 
     2055    def isValidCredential(self, assertion): 
     2056        if utcNow < assertion.conditions.notBefore: 
     2057            msg = ('The current clock time [%s] is before the SAML Attribute ' 
     2058                   'Response assertion conditions not before time [%s]' %  
     2059                   (SAMLDateTime.toString(utcNow), 
     2060                    assertion.conditions.notBefore)) 
     2061            log.warning(msg) 
     2062            return False 
     2063             
     2064        if utcNow >= assertion.conditions.notOnOrAfter: 
     2065            msg = ('The current clock time [%s] is on or after the SAML ' 
     2066                   'Attribute Response assertion conditions not on or after ' 
     2067                   'time [%s]' %  
     2068                   (SAMLDateTime.toString(utcNow), 
     2069                    assertion.conditions.notOnOrAfter)) 
     2070            log.warning(msg) 
     2071            return False 
     2072             
     2073        return True 
     2074         
     2075         
    16052076class CredentialRepositoryError(_CredentialWalletException):    
    16062077    """Exception handling for NDG Credential Repository class.""" 
    16072078 
    16082079 
    1609 class CredentialRepository: 
     2080class CredentialRepository(object): 
    16102081    """CredentialWallet's abstract interface class to a Credential Repository.  
    16112082    The Credential Repository is abstract store of user currently valid user 
     
    16842155 
    16852156 
    1686  
    16872157class NullCredentialRepository(CredentialRepository): 
    16882158    """Implementation of Credential Repository interface with empty stubs.   
  • TI12-security/trunk/python/ndg_security_common/ndg/security/common/m2CryptoSSLUtility.py

    r5442 r6033  
    1 """Extend M2Crypto SSL functionality for cert verification and custom 
    2 timeout settings. 
     1"""Code moved to ndg.security.common.utils.m2crypto 
    32 
    43NERC DataGrid Project""" 
     
    98__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    109__revision__ = '$Id$' 
     10import warnings 
     11warnings.warn("Module moved use ndg.security.common.utils.m2crypto instead of " 
     12              "%s" % __file__, PendingDeprecationWarning) 
    1113 
    12 import httplib 
    13 import socket 
    14  
    15 from M2Crypto import SSL, X509 
    16 from M2Crypto.httpslib import HTTPSConnection as _HTTPSConnection 
    17  
    18 from ndg.security.common.X509 import X509Cert, X509Stack, X500DN 
    19  
    20 class InvalidCertSignature(SSL.Checker.SSLVerificationError): 
    21     """Raise if verification against CA cert public key fails""" 
    22  
    23 class InvalidCertDN(SSL.Checker.SSLVerificationError): 
    24     """Raise if verification against a list acceptable DNs fails""" 
    25     
    26  
    27 class HostCheck(SSL.Checker.Checker, object): 
    28     """Override SSL.Checker.Checker to enable alternate Common Name 
    29     setting match for peer cert""" 
    30  
    31     def __init__(self,  
    32                  peerCertDN=None,  
    33                  peerCertCN=None, 
    34                  acceptedDNs=[],  
    35                  caCertList=[], 
    36                  caCertFilePathList=[],  
    37                  **kw): 
    38         """Override parent class __init__ to enable setting of myProxyServerDN 
    39         setting 
    40          
    41         @type peerCertDN: string/list 
    42         @param peerCertDN: Set the expected Distinguished Name of the 
    43         server to avoid errors matching hostnames.  This is useful 
    44         where the hostname is not fully qualified.   
    45  
    46         *param acceptedDNs: a list of acceptable DNs.  This enables validation  
    47         where the expected DN is where against a limited list of certs. 
    48          
    49         @type peerCertCN: string 
    50         @param peerCertCN: enable alternate Common Name to peer 
    51         hostname 
    52          
    53         @type caCertList: list type of M2Crypto.X509.X509 types 
    54         @param caCertList: CA X.509 certificates - if set the peer cert's  
    55         CA signature is verified against one of these.  At least one must 
    56         verify 
    57          
    58         @type caCertFilePathList: list string types 
    59         @param caCertFilePathList: same as caCertList except input as list 
    60         of CA cert file paths""" 
    61          
    62         SSL.Checker.Checker.__init__(self, **kw) 
    63          
    64         self.peerCertDN = peerCertDN 
    65         self.peerCertCN = peerCertCN 
    66         self.acceptedDNs = acceptedDNs 
    67          
    68         if caCertList: 
    69             self.caCertList = caCertList 
    70         elif caCertFilePathList: 
    71             self.caCertFilePathList = caCertFilePathList 
    72         else: 
    73             # Set default to enable len() test in __call__ 
    74             self.__caCertStack = () 
    75              
    76     def __call__(self, peerCert, host=None): 
    77         """Carry out checks on server ID 
    78         @param peerCert: MyProxy server host certificate as M2Crypto.X509.X509 
    79         instance 
    80         @param host: name of host to check 
    81         """ 
    82         if peerCert is None: 
    83             raise SSL.Checker.NoCertificate('SSL Peer did not return ' 
    84                                             'certificate') 
    85  
    86         peerCertDN = '/'+peerCert.get_subject().as_text().replace(', ', '/') 
    87         try: 
    88             SSL.Checker.Checker.__call__(self, peerCert, host=self.peerCertCN) 
    89              
    90         except SSL.Checker.WrongHost, e: 
    91             # Try match against peerCertDN set    
    92             if peerCertDN != self.peerCertDN: 
    93                 raise e 
    94  
    95         # At least one match should be found in the list - first convert to 
    96         # NDG X500DN type to allow per field matching for DN comparison 
    97         peerCertX500DN = X500DN(dn=peerCertDN) 
    98          
    99         if self.acceptedDNs: 
    100            matchFound = False 
    101            for dn in self.acceptedDNs: 
    102                x500dn = X500DN(dn=dn) 
    103                if x500dn == peerCertX500DN: 
    104                    matchFound = True 
    105                    break 
    106                 
    107            if not matchFound: 
    108                raise InvalidCertDN('Peer cert DN "%s" doesn\'t match ' 
    109                                    'verification list' % peerCertDN) 
    110  
    111         if len(self.__caCertStack) > 0: 
    112             try: 
    113                 self.__caCertStack.verifyCertChain( 
    114                            x509Cert2Verify=X509Cert(m2CryptoX509=peerCert)) 
    115             except Exception, e: 
    116                 raise InvalidCertSignature("Peer certificate verification " 
    117                                            "against CA certificate failed: %s"  
    118                                            % e) 
    119                
    120         # They match - drop the exception and return all OK instead           
    121         return True 
    122        
    123     def __setCACertList(self, caCertList): 
    124         """Set list of CA certs - peer cert must validate against at least one 
    125         of these""" 
    126         self.__caCertStack = X509Stack() 
    127         for caCert in caCertList: 
    128             self.__caCertStack.push(caCert) 
    129  
    130     caCertList = property(fset=__setCACertList, 
    131                           doc="list of CA certificates - the peer certificate " 
    132                               "must validate against one") 
    133  
    134     def __setCACertsFromFileList(self, caCertFilePathList): 
    135         '''Read CA certificates from file and add them to the X.509 
    136         stack 
    137          
    138         @type caCertFilePathList: basestring, list or tuple 
    139         @param caCertFilePathList: list of file paths for CA certificates to 
    140         be used to verify certificate used to sign message.  If a single  
    141         string item is input then this is converted into a tuple 
    142         ''' 
    143         if isinstance(caCertFilePathList, basestring): 
    144             caCertFilePathList = (caCertFilePathList,) 
    145              
    146         elif not isinstance(caCertFilePathList, (list, tuple)): 
    147             raise TypeError('Expecting a basestring, list or tuple type for ' 
    148                             '"caCertFilePathList"') 
    149  
    150         self.__caCertStack = X509Stack() 
    151  
    152         for caCertFilePath in caCertFilePathList: 
    153             self.__caCertStack.push(X509.load_cert(caCertFilePath)) 
    154          
    155     caCertFilePathList = property(fset=__setCACertsFromFileList, 
    156                                   doc="list of CA certificate file paths - " 
    157                                       "peer certificate must validate against " 
    158                                       "one") 
    159  
    160  
    161 class HTTPSConnection(_HTTPSConnection): 
    162     """Modified version of M2Crypto equivalent to enable custom checks with 
    163     the peer and timeout settings 
    164      
    165     @type defReadTimeout: M2Crypto.SSL.timeout 
    166     @cvar defReadTimeout: default timeout for read operations 
    167     @type defWriteTimeout: M2Crypto.SSL.timeout 
    168     @cvar defWriteTimeout: default timeout for write operations"""     
    169     defReadTimeout = SSL.timeout(sec=20.) 
    170     defWriteTimeout = SSL.timeout(sec=20.) 
    171      
    172     def __init__(self, *args, **kw): 
    173         '''Overload to enable setting of post connection check 
    174         callback to SSL.Connection 
    175          
    176         type *args: tuple 
    177         param *args: args which apply to M2Crypto.httpslib.HTTPSConnection 
    178         type **kw: dict 
    179         param **kw: additional keywords 
    180         @type postConnectionCheck: SSL.Checker.Checker derivative 
    181         @keyword postConnectionCheck: set class for checking peer 
    182         @type readTimeout: M2Crypto.SSL.timeout 
    183         @keyword readTimeout: readTimeout - set timeout for read 
    184         @type writeTimeout: M2Crypto.SSL.timeout 
    185         @keyword writeTimeout: similar to read timeout''' 
    186          
    187         self._postConnectionCheck = kw.pop('postConnectionCheck', 
    188                                            SSL.Checker.Checker) 
    189          
    190         if 'readTimeout' in kw: 
    191             if not isinstance(kw['readTimeout'], SSL.timeout): 
    192                 raise AttributeError("readTimeout must be of type " 
    193                                      "M2Crypto.SSL.timeout") 
    194             self.readTimeout = kw.pop('readTimeout') 
    195         else: 
    196             self.readTimeout = HTTPSConnection.defReadTimeout 
    197                
    198         if 'writeTimeout' in kw: 
    199             if not isinstance(kw['writeTimeout'], SSL.timeout): 
    200                 raise AttributeError("writeTimeout must be of type " 
    201                                      "M2Crypto.SSL.timeout")  
    202             self.writeTimeout = kw.pop('writeTimeout') 
    203         else: 
    204             self.writeTimeout = HTTPSConnection.defWriteTimeout 
    205      
    206         self._clntCertFilePath = kw.pop('clntCertFilePath', None) 
    207         self._clntPriKeyFilePath = kw.pop('clntPriKeyFilePath', None) 
    208          
    209         _HTTPSConnection.__init__(self, *args, **kw) 
    210          
    211         # load up certificate stuff 
    212         if self._clntCertFilePath is not None and \ 
    213            self._clntPriKeyFilePath is not None: 
    214             self.ssl_ctx.load_cert(self._clntCertFilePath,  
    215                                    self._clntPriKeyFilePath) 
    216          
    217          
    218     def connect(self): 
    219         '''Overload M2Crypto.httpslib.HTTPSConnection to enable 
    220         custom post connection check of peer certificate and socket timeout''' 
    221  
    222         self.sock = SSL.Connection(self.ssl_ctx) 
    223         self.sock.set_post_connection_check_callback(self._postConnectionCheck) 
    224  
    225         self.sock.set_socket_read_timeout(self.readTimeout) 
    226         self.sock.set_socket_write_timeout(self.writeTimeout) 
    227  
    228         self.sock.connect((self.host, self.port)) 
    229  
    230     def putrequest(self, method, url, **kw): 
    231         '''Overload to work around bug with unicode type URL''' 
    232         url = str(url) 
    233         _HTTPSConnection.putrequest(self, method, url, **kw) 
     14from ndg.security.common.utils.m2crypto import * 
  • TI12-security/trunk/python/ndg_security_common/ndg/security/common/saml/bindings.py

    r5741 r6033  
    2020from ndg.security.common.soap import SOAPEnvelopeBase 
    2121from ndg.security.common.soap.etree import SOAPEnvelope 
    22 from ndg.security.common.soap.client import UrlLib2SOAPClient, \ 
    23     UrlLib2SOAPRequest 
     22from ndg.security.common.soap.client import (UrlLib2SOAPClient,  
     23    UrlLib2SOAPRequest) 
    2424 
    2525 
     
    3434_isIterable = lambda obj: getattr(obj, '__iter__', False)  
    3535    
    36     
    37 class SOAPBinding(object): 
     36 
     37class SOAPBinding(SSLContextProxy): 
    3838    '''Client SAML SOAP Binding for Attribute Query''' 
    3939     
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/myproxy/certificate_extapp/saml_attribute_assertion.py

    r6018 r6033  
    9696        else: 
    9797            return '' 
    98          
    99     def _getStatusMessage(self): 
    100         ''' 
    101         Gets the Message of this Status. 
    102          
    103         @return Status StatusMessage 
    104         ''' 
    105         return self.__statusMessage 
    106  
    107     def _setStatusMessage(self, value): 
    108         ''' 
    109         Sets the Message of this Status. 
    110          
    111         @param newStatusMessage the Message of this Status 
    112         ''' 
    113         if not isinstance(value, StatusMessage): 
    114             raise TypeError('"statusMessage" must be a %r derived type, ' 
    115                             "got %r" % (StatusMessage, type(value))) 
    116              
    117         self.__statusMessage = value 
    118          
    119     statusMessage = property(fget=_getStatusMessage, 
    120                              fset=_setStatusMessage, 
    121                              doc="SAML response status message") 
    12298     
    12399            
  • TI12-security/trunk/python/ndg_security_server/ndg/security/server/wsgi/authz.py

    r5786 r6033  
    351351        # Pre-process list items splitting as needed 
    352352        if isinstance(local_conf.get('caCertFilePathList'), basestring): 
    353             local_conf['caCertFilePathList'] = \ 
    354                 NDGSecurityMiddlewareBase.parseListItem( 
    355                                         local_conf['caCertFilePathList']) 
     353            local_conf[ 
     354                'caCertFilePathList'] = NDGSecurityMiddlewareBase.parseListItem( 
     355                                            local_conf['caCertFilePathList']) 
    356356             
    357357        if isinstance(local_conf.get('sslCACertFilePathList'), basestring): 
    358             local_conf['sslCACertFilePathList'] = \ 
    359                 NDGSecurityMiddlewareBase.parseListItem( 
     358            local_conf[ 
     359                'sslCACertFilePathList' 
     360                ] = NDGSecurityMiddlewareBase.parseListItem( 
    360361                                        local_conf['sslCACertFilePathList']) 
    361362             
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/__init__.py

    r6009 r6033  
    4141    sqlAlchemyInstalled = False 
    4242     
     43     
    4344class BaseTestCase(unittest.TestCase): 
    4445    '''Convenience base class from which other unit tests can extend.  Its 
    4546    sets the generic data directory path''' 
    4647    configDirEnvVarName = 'NDGSEC_TEST_CONFIG_DIR' 
     48     
    4749    SITEA_ATTRIBUTEAUTHORITY_PORTNUM = 5000 
    4850    SITEB_ATTRIBUTEAUTHORITY_PORTNUM = 5100 
     51     
     52    SITEA_ATTRIBUTEAUTHORITY_URI = 'http://localhost:%s/AttributeAuthority' % \ 
     53                                    SITEA_ATTRIBUTEAUTHORITY_PORTNUM 
     54                                     
     55    SITEB_ATTRIBUTEAUTHORITY_URI = 'http://localhost:%s/AttributeAuthority' % \ 
     56                                    SITEB_ATTRIBUTEAUTHORITY_PORTNUM 
     57                                     
     58    SITEA_ATTRIBUTEAUTHORITY_SAML_URI = \ 
     59        'http://localhost:%s/AttributeAuthority/saml' % \ 
     60                                    SITEA_ATTRIBUTEAUTHORITY_PORTNUM 
     61                                     
     62    SITEB_ATTRIBUTEAUTHORITY_SAML_URI = \ 
     63        'http://localhost:%s/AttributeAuthority/saml' % \ 
     64                                    SITEB_ATTRIBUTEAUTHORITY_PORTNUM 
     65     
    4966    SESSIONMANAGER_PORTNUM = 5500 
    5067     
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/authz/pdp/__init__.py

    r3793 r6033  
     1"""Authorisation PDP Package 
     2 
     3NERC DataGrid Project 
     4""" 
     5__author__ = "P J Kershaw" 
     6__date__ = "18/11/09" 
     7__copyright__ = "(C) 2009 Science and Technology Facilities Council" 
     8__license__ = "BSD - see LICENSE file in top-level directory" 
     9__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     10__revision__ = '$Id$' 
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/credentialwallet/test_credentialwallet.py

    r5774 r6033  
    1717from ndg.security.test.unit import BaseTestCase 
    1818 
    19 from ndg.security.common.utils.configfileparsers import \ 
    20                                                     CaseSensitiveConfigParser 
     19from ndg.security.common.utils.configfileparsers import ( 
     20                                                    CaseSensitiveConfigParser) 
    2121from ndg.security.common.X509 import X509CertParse 
    22 from ndg.security.common.credentialwallet import CredentialWallet, \ 
    23                                         CredentialWalletAttributeRequestDenied 
     22from ndg.security.common.credentialwallet import (CredentialWallet,  
     23                                        CredentialWalletAttributeRequestDenied) 
    2424from ndg.security.server.attributeauthority import AttributeAuthority 
    2525 
     
    128128        assert(attCert.userId == str(credWallet.userX509Cert.dn)) 
    129129        print("Attribute Certificate:\n%s" % attCert) 
    130           
    131  
    132130 
    133131    def test05GetAttCertRefusedWithUserX509Cert(self): 
     
    182180        assert(attCert.userId == credWallet.userId) 
    183181        print("Attribute Certificate:\n%s" % attCert)   
    184                                                           
     182  
     183  
     184from ndg.security.common.credentialwallet import SamlCredentialWallet 
     185 
     186 
     187class SamlCredentialWalletTestCase(BaseTestCase): 
     188    def __init__(self, *arg, **kw): 
     189        super(CredentialWalletTestCase, self).__init__(*arg, **kw) 
     190        self.startSiteAAttributeAuthority() 
     191         
     192    def test01(self): 
     193        wallet = SamlCredentialWallet() 
     194        wallet.attributeAuthorityURI = \ 
     195            SamlCredentialWalletTestCase.SITEA_ATTRIBUTEAUTHORITY_SAML_URI 
     196        wallet.attributeQuery() 
     197                                                                 
    185198if __name__ == "__main__": 
    186199    unittest.main()         
  • TI12-security/trunk/python/ndg_security_test/ndg/security/test/unit/myproxy/certificate_extapp/__init__.py

    r5907 r6033  
     1"""MyProxy Certificate Extension Application unit test package 
     2 
     3NERC DataGrid Project 
     4""" 
     5__author__ = "P J Kershaw" 
     6__date__ = "18/11/09" 
     7__copyright__ = "(C) 2009 Science and Technology Facilities Council" 
     8__license__ = "BSD - see LICENSE file in top-level directory" 
     9__contact__ = "Philip.Kershaw@stfc.ac.uk" 
     10__revision__ = '$Id$' 
Note: See TracChangeset for help on using the changeset viewer.