예제 #1
0
    def __init__(self,
                 sessionCacheDataDir=None,
                 sessionCacheTimeout=None,
                 sessionCacheAssertionClockSkewTol=1.0):
        '''Initialise settings for connection to an Attribute Authority

        @param sessionCacheDataDir: directory for permanent storage of sessions.
        Sessions are used as a means of optimisation caching Attribute Query
        results to reduce the number of Attribute Authority web service calls.
        If set to None, sessions are cached in memory only.
        @type sessionCacheDataDir: None type / basestring
        @param sessionCacheTimeout: time in seconds for individual caches'
        lifetimes.  Set to None to set no expiry.
        @type sessionCacheTimeout: float/int/long/string or None type
        '''
        self.sessionCacheDataDir = sessionCacheDataDir
        self.sessionCacheTimeout = sessionCacheTimeout
        self.__sessionCacheAssertionClockSkewTol = \
            sessionCacheAssertionClockSkewTol

        self.__subjectAttributeId = None
        self.__mappingFilePath = None

        # Force mapping dict to have string type keys and items
        _typeCheckers = (lambda val: isinstance(val, basestring), ) * 2
        self.__attributeId2AttributeAuthorityMap = VettedDict(*_typeCheckers)

        self.__attribute_query = AttributeQueryFactory.create()
        self.__attribute_query_binding = AttributeQuerySslSOAPBinding()

        self.__cacheSessions = True
    def test02SendQuery(self):
        query_binding = AttributeQuerySslSOAPBinding()
        
        attribute_query = AttributeQueryFactory.create()
        attribute_query.subject.nameID.format = self.__class__.SUBJECT_FORMAT
        attribute_query.subject.nameID.value = self.__class__.SUBJECT
        attribute_query.issuerName = '/O=Site A/CN=Authorisation Service'


        attribute = Attribute()
        attribute.name = 'urn:ndg:saml:emailaddress'
        attribute.friendlyName = 'emailAddress'
        attribute.nameFormat = 'http://www.w3.org/2001/XMLSchema'
        
        attribute_query.attributes.append(attribute)
        
        query_binding.clockSkewTolerance = 2.
        query_binding.sslCACertDir = self.__class__.CLIENT_CACERT_DIR
        query_binding.sslCertFilePath = self.__class__.CLIENT_CERT_FILEPATH
        query_binding.sslPriKeyFilePath = self.__class__.CLIENT_PRIKEY_FILEPATH
        query_binding.sslValidDNs = self.__class__.VALID_DNS
        
        response = query_binding.send(attribute_query, 
                                      uri=self.__class__.SERVICE_URI)
        
        # Convert back to ElementTree instance read for string output
        samlResponseElem = ResponseElementTree.toXML(response)
        
        print("SAML Response ...")
        print(ElementTree.tostring(samlResponseElem))
        print("Pretty print SAML Response ...")
        print(prettyPrint(samlResponseElem))
        
        self.assert_(response.status.statusCode.value==StatusCode.SUCCESS_URI)
예제 #3
0
    def __init__(self, sessionCacheDataDir=None, sessionCacheTimeout=None,
                 sessionCacheAssertionClockSkewTol=1.0):
        '''Initialise settings for connection to an Attribute Authority

        @param sessionCacheDataDir: directory for permanent storage of sessions.
        Sessions are used as a means of optimisation caching Attribute Query
        results to reduce the number of Attribute Authority web service calls.
        If set to None, sessions are cached in memory only.
        @type sessionCacheDataDir: None type / basestring
        @param sessionCacheTimeout: time in seconds for individual caches'
        lifetimes.  Set to None to set no expiry.
        @type sessionCacheTimeout: float/int/long/string or None type
        '''
        self.sessionCacheDataDir = sessionCacheDataDir
        self.sessionCacheTimeout = sessionCacheTimeout
        self.__sessionCacheAssertionClockSkewTol = \
            sessionCacheAssertionClockSkewTol

        self.__subjectAttributeId = None
        self.__mappingFilePath = None

        # Force mapping dict to have string type keys and items
        _typeCheckers = (lambda val: isinstance(val, basestring),)*2
        self.__attributeId2AttributeAuthorityMap = VettedDict(*_typeCheckers)

        self.__attribute_query = AttributeQueryFactory.create()
        self.__attribute_query_binding = AttributeQuerySslSOAPBinding()

        self.__cacheSessions = True
예제 #4
0
    def test02_from_kw(self):
        attribute_query = AttributeQueryFactory.from_kw(
                                                    prefix='attributeQuery.',
                                                    **self.config)
        
        self.assertEqual(attribute_query.subject.nameID.format, 
                         self.config['attributeQuery.subject.nameID.format'], 
                         'Parameter is %r, expected %r' % (
                          attribute_query.subject.nameID.format, 
                          self.config['attributeQuery.subject.nameID.format']))
        
        self.assertEqual(attribute_query.issuer.value, 
                         self.config['attributeQuery.issuer.value'], 
                         'Parameter is %r, expected %r' % (
                         attribute_query.issuer.value, 
                         self.config['attributeQuery.issuer.value']))
        
        self.assertEqual(len(attribute_query.attributes), 2, 
                        'expecting 2 SAML attributes parsed')
        
        attr = None
        for attr in attribute_query.attributes:
            if attr.friendlyName == 'FirstName':
                break
            
        self.assertNotEqual(attr, None, 
                            'Missing expected friendlyName attribute')
                           
        self.assertIn(attr.nameFormat, 
                      self.config['attributeQuery.attributes.0'], 
                      'Parameter is %r, not found in %r' % (
                          attr.nameFormat, 
                          self.config['attributeQuery.attributes.0']))

        self.assertIn(attr.name, 
                      self.config['attributeQuery.attributes.0'], 
                      'Parameter is %r, not found in %r' % (
                          attr.name, 
                          self.config['attributeQuery.attributes.0']))
예제 #5
0
    def attributeQuery(self, context, attributeDesignator):
        """Query this PIP for the given request context attribute specified by
        the attribute designator.  Nb. this implementation is only intended to
        accept queries for a given *subject* in the request

        @param context: the request context
        @type context: ndg.xacml.core.context.request.Request
        @param designator:
        @type designator: ndg.xacml.core.attributedesignator.SubjectAttributeDesignator
        @rtype: ndg.xacml.utils.TypedList(<attributeDesignator.dataType>) / None
        @return: attribute values found for query subject or None if none
        could be found
        @raise PIPConfigException: if attribute ID -> Attribute Authority
        mapping is empty
        """

        # Check the attribute designator type - this implementation takes
        # queries for request context subjects only
        if not isinstance(attributeDesignator, SubjectAttributeDesignator):
            log.debug('This PIP query interface can only accept subject '
                      'attribute designator related queries')
            return None

        attributeFormat = attributeDesignator.dataType
        attributeId = attributeDesignator.attributeId
        exptd_attribute_id = self.attribute_query.subject.nameID.format

        if not isinstance(context, XacmlRequestCtx):
            raise TypeError('Expecting %r type for context input; got %r' %
                            (XacmlRequestCtx, type(context)))

        # Look up mapping from request attribute ID to Attribute Authority to
        # query
        if len(self.__attributeId2AttributeAuthorityMap) == 0:
            raise PIPConfigException('No entries found in attribute ID to '
                                     'Attribute Authority mapping')

        attributeAuthorityURI = self.__attributeId2AttributeAuthorityMap.get(
            attributeId, None)
        if attributeAuthorityURI is None:
            log.debug(
                "No matching attribute authority endpoint found in "
                "mapping file %r for input attribute ID %r",
                self.mappingFilePath, attributeId)
            return None

        # Get subject from the request context
        subject = None
        subjectId = None
        for subject in context.subjects:
            for attribute in subject.attributes:
                if attribute.attributeId == exptd_attribute_id:
                    if len(attribute.attributeValues) != 1:
                        raise PIPRequestCtxException("Expecting a single "
                                                     "attribute value "
                                                     "for query subject ID")
                    subjectId = attribute.attributeValues[0].value
                    break

        if subjectId is None:
            raise PIPRequestCtxException('No subject found of type %r in '
                                         'request context' %
                                         exptd_attribute_id)
        elif not subjectId:
            # Empty string
            return None
        else:
            # Keep a reference to the matching Subject instance
            xacmlCtxSubject = subject

        # Check for cached attributes for this subject (i.e. user)
        # If none found send a query to the attribute authority
        assertions = None
        attributeIdFoundInCache = False
        if self.cacheSessions:
            attributeIdFoundInCache = False
            sessionCache = SessionCache(subjectId,
                                    data_dir=self.sessionCacheDataDir,
                                    timeout=self.sessionCacheTimeout,
                                    assertionClockSkewTolerance=\
                                        self.sessionCacheAssertionClockSkewTol)

            assertions = sessionCache.retrieve(attributeAuthorityURI)
            if assertions is not None:
                # Check for attributes matching the requested ID
                for assertion in assertions:
                    for statement in assertion.attributeStatements:
                        for attribute in statement.attributes:
                            if attribute.name == attributeId:
                                attributeIdFoundInCache = True
                                break

        if not attributeIdFoundInCache:
            # No cached assertions are available for this Attribute Authority,
            # for the required attribute ID - make a fresh call to the
            # Attribute Authority

            # Initialise the attribute to be queried for and add it to the
            # SAML query
            samlAttribute = SamlAttribute()
            samlAttribute.name = attributeId
            samlAttribute.nameFormat = attributeFormat

            # Copy attributes for this query from constants set at
            # initialisation
            query = AttributeQueryFactory.create()
            query.subject.nameID.value = subjectId
            query.subject.nameID.format = exptd_attribute_id
            query.issuer.value = self.attribute_query.issuer.value
            query.issuer.format = self.attribute_query.issuer.format
            query.attributes.append(samlAttribute)

            # Dispatch query
            try:
                response = self.attribute_query_binding.send(
                    query, uri=attributeAuthorityURI)

                log.debug('Retrieved response from attribute service %r',
                          attributeAuthorityURI)
            except Exception:
                log.exception(
                    'Error querying Attribute service %r with '
                    'subject %r', attributeAuthorityURI, subjectId)
                raise

            if assertions is None:
                assertions = SamlTypedList(SamlAssertion)

            assertions.extend(response.assertions)

            if self.cacheSessions:
                sessionCache.add(assertions, attributeAuthorityURI)

        # Unpack SAML assertion attribute corresponding to the name
        # format specified and copy into XACML attributes
        xacmlAttribute = XacmlAttribute()
        xacmlAttribute.attributeId = attributeId
        xacmlAttribute.dataType = attributeFormat

        # Create XACML class from SAML type identifier
        factory = self.__class__.XACML_ATTR_VAL_CLASS_FACTORY
        xacmlAttrValClass = factory(attributeFormat)

        for assertion in assertions:
            for statement in assertion.attributeStatements:
                for attribute in statement.attributes:
                    if attribute.nameFormat == attributeFormat:
                        # Convert SAML Attribute values to XACML equivalent
                        # types
                        for samlAttrVal in attribute.attributeValues:
                            # Instantiate and initial new XACML value
                            xacmlAttrVal = xacmlAttrValClass(
                                value=samlAttrVal.value)

                            xacmlAttribute.attributeValues.append(xacmlAttrVal)

        # Update the XACML request context subject with the new attributes
        matchFound = False
        for attr in xacmlCtxSubject.attributes:
            matchFound = attr.attributeId == attributeId
            if matchFound:
                # Weed out duplicates
                newAttrVals = [
                    attrVal for attrVal in xacmlAttribute.attributeValues
                    if attrVal not in attr.attributeValues
                ]
                attr.attributeValues.extend(newAttrVals)
                break

        if not matchFound:
            xacmlCtxSubject.attributes.append(xacmlAttribute)

        # Return the attributes to the caller to comply with the interface
        return xacmlAttribute.attributeValues
예제 #6
0
    def attributeQuery(self, context, attributeDesignator):
        """Query this PIP for the given request context attribute specified by
        the attribute designator.  Nb. this implementation is only intended to
        accept queries for a given *subject* in the request

        @param context: the request context
        @type context: ndg.xacml.core.context.request.Request
        @param designator:
        @type designator: ndg.xacml.core.attributedesignator.SubjectAttributeDesignator
        @rtype: ndg.xacml.utils.TypedList(<attributeDesignator.dataType>) / None
        @return: attribute values found for query subject or None if none
        could be found
        @raise PIPConfigException: if attribute ID -> Attribute Authority
        mapping is empty
        """

        # Check the attribute designator type - this implementation takes
        # queries for request context subjects only
        if not isinstance(attributeDesignator, SubjectAttributeDesignator):
            log.debug('This PIP query interface can only accept subject '
                      'attribute designator related queries')
            return None

        attributeFormat = attributeDesignator.dataType
        attributeId = attributeDesignator.attributeId
        exptd_attribute_id = self.attribute_query.subject.nameID.format

        if not isinstance(context, XacmlRequestCtx):
            raise TypeError('Expecting %r type for context input; got %r' %
                            (XacmlRequestCtx, type(context)))

        # Look up mapping from request attribute ID to Attribute Authority to
        # query
        if len(self.__attributeId2AttributeAuthorityMap) == 0:
            raise PIPConfigException('No entries found in attribute ID to '
                                     'Attribute Authority mapping')

        attributeAuthorityURI = self.__attributeId2AttributeAuthorityMap.get(
                                            attributeId, None)
        if attributeAuthorityURI is None:
            log.debug("No matching attribute authority endpoint found in "
                      "mapping file %r for input attribute ID %r",
                      self.mappingFilePath, attributeId)
            return None

        # Get subject from the request context
        subject = None
        subjectId = None
        for subject in context.subjects:
            for attribute in subject.attributes:
                if attribute.attributeId == exptd_attribute_id:
                    if len(attribute.attributeValues) != 1:
                        raise PIPRequestCtxException("Expecting a single "
                                                     "attribute value "
                                                     "for query subject ID")
                    subjectId = attribute.attributeValues[0].value
                    break

        if subjectId is None:
            raise PIPRequestCtxException('No subject found of type %r in '
                                         'request context' % exptd_attribute_id)
        elif not subjectId:
            # Empty string
            return None
        else:
            # Keep a reference to the matching Subject instance
            xacmlCtxSubject = subject

        # Check for cached attributes for this subject (i.e. user)
        # If none found send a query to the attribute authority
        assertions = None
        attributeIdFoundInCache = False
        if self.cacheSessions:
            attributeIdFoundInCache = False
            sessionCache = SessionCache(subjectId,
                                    data_dir=self.sessionCacheDataDir,
                                    timeout=self.sessionCacheTimeout,
                                    assertionClockSkewTolerance=\
                                        self.sessionCacheAssertionClockSkewTol)

            assertions = sessionCache.retrieve(attributeAuthorityURI)
            if assertions is not None:
                # Check for attributes matching the requested ID
                for assertion in assertions:
                    for statement in assertion.attributeStatements:
                        for attribute in statement.attributes:
                            if attribute.name == attributeId:
                                attributeIdFoundInCache = True
                                break

        if not attributeIdFoundInCache:
            # No cached assertions are available for this Attribute Authority,
            # for the required attribute ID - make a fresh call to the
            # Attribute Authority

            # Initialise the attribute to be queried for and add it to the
            # SAML query
            samlAttribute = SamlAttribute()
            samlAttribute.name = attributeId
            samlAttribute.nameFormat = attributeFormat

            # Copy attributes for this query from constants set at
            # initialisation
            query = AttributeQueryFactory.create()
            query.subject.nameID.value = subjectId
            query.subject.nameID.format = exptd_attribute_id
            query.issuer.value = self.attribute_query.issuer.value
            query.issuer.format = self.attribute_query.issuer.format
            query.attributes.append(samlAttribute)

            # Dispatch query
            try:
                response = self.attribute_query_binding.send(query,
                                                    uri=attributeAuthorityURI)

                log.debug('Retrieved response from attribute service %r',
                          attributeAuthorityURI)
            except Exception:
                log.exception('Error querying Attribute service %r with '
                              'subject %r', attributeAuthorityURI, subjectId)
                raise

            if assertions is None:
                assertions = SamlTypedList(SamlAssertion)

            assertions.extend(response.assertions)

            if self.cacheSessions:
                sessionCache.add(assertions, attributeAuthorityURI)

        # Unpack SAML assertion attribute corresponding to the name
        # format specified and copy into XACML attributes
        xacmlAttribute = XacmlAttribute()
        xacmlAttribute.attributeId = attributeId
        xacmlAttribute.dataType = attributeFormat

        # Create XACML class from SAML type identifier
        factory = self.__class__.XACML_ATTR_VAL_CLASS_FACTORY
        xacmlAttrValClass = factory(attributeFormat)

        for assertion in assertions:
            for statement in assertion.attributeStatements:
                for attribute in statement.attributes:
                    if attribute.nameFormat == attributeFormat:
                        # Convert SAML Attribute values to XACML equivalent
                        # types
                        for samlAttrVal in attribute.attributeValues:
                            # Instantiate and initial new XACML value
                            xacmlAttrVal = xacmlAttrValClass(
                                                        value=samlAttrVal.value)

                            xacmlAttribute.attributeValues.append(xacmlAttrVal)

        # Update the XACML request context subject with the new attributes
        matchFound = False
        for attr in xacmlCtxSubject.attributes:
            matchFound = attr.attributeId == attributeId
            if matchFound:
                # Weed out duplicates
                newAttrVals = [attrVal
                               for attrVal in xacmlAttribute.attributeValues
                               if attrVal not in attr.attributeValues]
                attr.attributeValues.extend(newAttrVals)
                break

        if not matchFound:
            xacmlCtxSubject.attributes.append(xacmlAttribute)

        # Return the attributes to the caller to comply with the interface
        return xacmlAttribute.attributeValues
예제 #7
0
 def test01_create(self):
     attribute_query = AttributeQueryFactory.create()
     self.assertIsNotNone(attribute_query.subject, 'query subject is none')
     self.assertIsNotNone(attribute_query.issuer, 'query issuer is none')