Ignore:
Timestamp:
24/08/10 15:34:07 (9 years ago)
Author:
pjkersha
Message:

Incomplete - task 2: XACML-Security Integration

  • added caching capability to Policy Information Point. This enables the PIP to retrieve previously cached assertions from an Attribute Authority optimising performance. Caching is done with beaker.session but instead of indexing based on a cookie, it's based on the subject Id i.e. for ESG, a user's OpenID.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/xacml/pip/saml_pip.py

    r7357 r7358  
    1414from os import path 
    1515from ConfigParser import SafeConfigParser, ConfigParser 
     16import base64 
     17 
     18import beaker.session 
    1619 
    1720from ndg.xacml.core.attributedesignator import SubjectAttributeDesignator 
     
    2831                                            AttributeQuerySslSOAPBinding 
    2932                                             
    30 from ndg.security.common.utils import VettedDict 
    31  
     33from ndg.security.common.utils import VettedDict, str2Bool 
     34from ndg.security.common.credentialwallet import SAMLAssertionWallet 
     35 
     36 
     37class SessionCache(object):   
     38    """Class to cache previous attribute query results retrieved from  
     39    Attribute Authority callouts.  This is to optimise performance.  Session 
     40    caching is based on beaker.session 
     41     
     42    @ivar __session: wrapped beaker session instance 
     43    @type __session: beaker.session.Session 
     44    """ 
     45    __slots__ = ('__session', ) 
     46     
     47    def __init__(self, _id, data_dir=None): 
     48        """ 
     49        @param _id: unique identifier for session to be created, or one to reload 
     50        from store 
     51        @type _id: basestring 
     52        @param data_dir: directory for permanent storage of sessions. 
     53        Sessions are used as a means of optimisation caching Attribute Query  
     54        results to reduce the number of Attribute Authority web service calls. 
     55        If set to None, sessions are cached in memory only. 
     56        @type data_dir: None type / basestring 
     57        """                 
     58        # Expecting URIs for Ids, make them safe for storage by encoding first 
     59        encodedId = base64.b64encode(_id) 
     60         
     61        # The first argument is the request object, a dictionary-like object 
     62        # from which and to which cookie settings are made.  This can be ignored 
     63        # here as the cookie functionality is not being used. 
     64        self.__session = beaker.session.Session({}, id=encodedId,  
     65                                                data_dir=data_dir, 
     66                                                use_cookies=False) 
     67        if 'wallet' not in self.__session: 
     68            self.__session['wallet'] = SAMLAssertionWallet() 
     69     
     70    def add(self, assertions, issuerEndpoint): 
     71        """Add a SAML assertion containing attribute statement(s) from an 
     72        Attribute Authority 
     73         
     74        @type assertions: ndg.security.common.utils.TypedList 
     75        @param assertions: new SAML assertions to be added corresponding to the 
     76        issuerEndpoint 
     77        @type issuerEndpoint: basestring 
     78        @param issuerEndpoint: input the issuing service URI from 
     79        which assertions were retrieved.  This is added to a dict to enable  
     80        access to given Assertions keyed by issuing service URI. See the  
     81        retrieveAssertions method. 
     82        @raise KeyError: error with session object - no wallet key set 
     83        """ 
     84        self.__session['wallet'].addCredentials(issuerEndpoint, assertions) 
     85         
     86    def retrieve(self, issuerEndpoint): 
     87        '''Get the cached assertions for the given Attribute Authority issuer 
     88         
     89        @type issuerEndpoint: basestring 
     90        @param issuerEndpoint: input the issuing service URI from 
     91        which assertion was retrieved. 
     92        @return: SAML assertion response cached from a previous call to the  
     93        Attribute Authority with the given endpoint 
     94        @raise KeyError: error with session object - no wallet key set 
     95        ''' 
     96        wallet = self.__session['wallet'] 
     97        return wallet.retrieveCredentials(issuerEndpoint) 
     98             
     99    def __del__(self): 
     100        """Ensure session is saved when this object goes out of scope""" 
     101        if isinstance(self.__session, beaker.session.Session): 
     102            self.__session.save() 
     103         
    32104 
    33105class PIPException(Exception): 
     
    56128        AttributeQuerySslSOAPBinding.QUERY_ATTRIBUTES_ATTRNAME 
    57129    ) 
     130     
     131    # Special attribute setting for SAML Attribute Query attributes - see 
     132    # __setattr__ 
    58133    ATTRIBUTE_QUERY_ATTRNAME = 'attributeQuery' 
    59134    LEN_ATTRIBUTE_QUERY_ATTRNAME = len(ATTRIBUTE_QUERY_ATTRNAME) 
     
    72147        '__mappingFilePath',  
    73148        '__attributeId2AttributeAuthorityMap', 
    74         '__attributeQueryBinding' 
     149        '__attributeQueryBinding', 
     150        '__cacheSessions', 
     151        '__sessionCacheDataDir', 
     152        '__sessionCache' 
    75153    ) 
    76154     
    77     def __init__(self): 
    78         '''Initialise settings for connection to an Attribute Authority''' 
     155    def __init__(self, sessionCacheDataDir=None): 
     156        '''Initialise settings for connection to an Attribute Authority 
     157         
     158        @param sessionCacheDataDir: directory for permanent storage of sessions. 
     159        Sessions are used as a means of optimisation caching Attribute Query  
     160        results to reduce the number of Attribute Authority web service calls. 
     161        If set to None, sessions are cached in memory only. 
     162        @type sessionCacheDataDir: None type / basestring 
     163        ''' 
    79164        self.__subjectAttributeId = None 
    80165        self.__mappingFilePath = None 
     
    86171        self.__attributeQueryBinding = AttributeQuerySslSOAPBinding() 
    87172         
     173        self.__cacheSessions = True 
     174        self.__sessionCacheDataDir = sessionCacheDataDir 
     175        self.__sessionCache = None 
     176 
     177    def _getCacheSessions(self): 
     178        return self.__cacheSessions 
     179 
     180    def _setCacheSessions(self, value): 
     181        if isinstance(value, basestring): 
     182            self.__cacheSessions = str2Bool(value) 
     183        elif isinstance(value, bool): 
     184            self.__cacheSessions = value 
     185        else: 
     186            raise TypeError('Expecting string/bool type for "cacheSessions" ' 
     187                            'attribute; got %r' % type(value)) 
     188         
     189        self.__cacheSessions = value 
     190 
     191    cacheSessions = property(_getCacheSessions, _setCacheSessions,  
     192                             doc="Cache attribute query results to optimise " 
     193                                 "performance") 
     194 
     195    def _getSessionCacheDataDir(self): 
     196        return self.__sessionCacheDataDir 
     197 
     198    def _setSessionCacheDataDir(self, value): 
     199        if not isinstance(value, (basestring, type(None))): 
     200            raise TypeError('Expecting string/None type for ' 
     201                            '"sessionCacheDataDir"; got %r' % type(value)) 
     202             
     203        self.__sessionCacheDataDir = value 
     204 
     205    sessionCacheDataDir = property(_getSessionCacheDataDir,  
     206                                   _setSessionCacheDataDir,  
     207                                   doc="Data Directory for Session Cache.  " 
     208                                       "This setting will be ignored if " 
     209                                       '"cacheSessions" is set to False') 
     210     
    88211    def _get_subjectAttributeId(self): 
    89212        return self.__subjectAttributeId 
     
    207330                super(PIP, self).__setattr__(name, value) 
    208331                 
    209             setattr(self.__attributeQueryBinding, queryAttrName, value) 
     332            setattr(self.__attributeQueryBinding, queryAttrName, value)             
    210333        else: 
    211334            super(PIP, self).__setattr__(name, value) 
     
    249372                            (XacmlRequestCtx, type(context))) 
    250373         
    251         # TODO: Check for cached attributes for this subject (i.e. user)         
    252         # If none found send a query to the attribute authority 
    253  
    254374        # Look up mapping from request attribute ID to Attribute Authority to 
    255375        # query  
     
    270390         
    271391        # Get subject from the request context 
     392        subject = None 
    272393        subjectId = None 
    273394        for subject in context.subjects: 
     
    292413            xacmlCtxSubject = subject 
    293414             
    294         # Get the id of the attribute to be queried for and add it to the SAML 
    295         # query 
    296415        attributeFormat = attributeDesignator.dataType 
    297416        attributeId = attributeDesignator.attributeId 
    298          
    299         samlAttribute = SamlAttribute() 
    300         samlAttribute.name = attributeDesignator.attributeId 
    301         samlAttribute.nameFormat = attributeFormat 
    302         self.attributeQueryBinding.query.attributes.append(samlAttribute) 
    303          
    304         # Dispatch query 
    305         try: 
    306             self.attributeQueryBinding.subjectID = subjectId 
    307             self.attributeQueryBinding.subjectIdFormat = self.subjectAttributeId 
    308             response = self.attributeQueryBinding.send( 
     417             
     418        # Check for cached attributes for this subject (i.e. user)         
     419        # If none found send a query to the attribute authority 
     420        if self.cacheSessions: 
     421            sessionCache = SessionCache(subjectId, 
     422                                        data_dir=self.__sessionCacheDataDir) 
     423            assertions = sessionCache.retrieve(attributeAuthorityURI) 
     424        else: 
     425            assertions = None 
     426             
     427        if assertions is None: 
     428            # No cached assertions are available for this Attribute Authority, 
     429            # make a fresh call  
     430             
     431            # Get the id of the attribute to be queried for and add it to the  
     432            # SAML query 
     433             
     434            samlAttribute = SamlAttribute() 
     435            samlAttribute.name = attributeDesignator.attributeId 
     436            samlAttribute.nameFormat = attributeFormat 
     437            self.attributeQueryBinding.query.attributes.append(samlAttribute) 
     438             
     439            # Dispatch query 
     440            try: 
     441                self.attributeQueryBinding.subjectID = subjectId 
     442                self.attributeQueryBinding.subjectIdFormat = \ 
     443                                                    self.subjectAttributeId 
     444                response = self.attributeQueryBinding.send( 
    309445                                                    uri=attributeAuthorityURI) 
    310         except Exception: 
    311             log.exception('Error querying Attribute service %r with subject %r', 
    312                           attributeAuthorityURI, 
    313                           subjectId) 
    314             raise 
    315         finally: 
    316             # !Ensure relevant query attributes are reset ready for any  
    317             # subsequent query! 
    318             self.attributeQueryBinding.subjectID = '' 
    319             self.attributeQueryBinding.subjectIdFormat = '' 
    320             self.attributeQueryBinding.query.attributes = SamlTypedList( 
     446            except Exception: 
     447                log.exception('Error querying Attribute service %r with ' 
     448                              'subject %r', attributeAuthorityURI, subjectId) 
     449                raise 
     450            finally: 
     451                # !Ensure relevant query attributes are reset ready for any  
     452                # subsequent query! 
     453                self.attributeQueryBinding.subjectID = '' 
     454                self.attributeQueryBinding.subjectIdFormat = '' 
     455                self.attributeQueryBinding.query.attributes = SamlTypedList( 
    321456                                                                SamlAttribute) 
    322457         
     458            assertions = response.assertions 
     459            if self.cacheSessions: 
     460                sessionCache.add(assertions, attributeAuthorityURI) 
     461             
    323462        # Unpack SAML assertion attribute corresponding to the name  
    324463        # format specified and copy into XACML attributes       
     
    331470        xacmlAttrValClass = factory(attributeFormat) 
    332471         
    333         for assertion in response.assertions: 
     472        for assertion in assertions: 
    334473            for statement in assertion.attributeStatements: 
    335474                for attribute in statement.attributes: 
     
    349488            matchFound = attr.attributeId == attributeId 
    350489            if matchFound: 
     490                # Weed out duplicates 
    351491                newAttrVals = [attrVal  
    352492                               for attrVal in xacmlAttribute.attributeValues  
     
    360500        # Return the attributes to the caller to comply with the interface 
    361501        return xacmlAttribute.attributeValues 
    362         
Note: See TracChangeset for help on using the changeset viewer.