Changeset 6578 for TI12-security


Ignore:
Timestamp:
16/02/10 16:11:08 (10 years ago)
Author:
pjkersha
Message:
  • Important fix for SOAP client used with SAML SOAP binding: set text/xml content type.
  • Refactored SAML SOAP binding query clients.
Location:
TI12-security/trunk/NDGSecurity/python
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/__init__.py

    r6572 r6578  
    188188         
    189189        samlElem = self.serialise(samlObj) 
    190  
     190             
    191191        # Attach query to SOAP body 
    192192        request.envelope.body.elem.append(samlElem) 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/attributequery.py

    r6572 r6578  
    4848    SERIALISE_KW = 'serialise' 
    4949    DESERIALISE_KW = 'deserialise' 
     50    QUERY_TYPE = AttributeQuery 
    5051     
    5152    def __init__(self, **kw): 
    5253        '''Create SOAP Client for SAML Attribute Query''' 
    53         self.__queryAttributes = TypedList(Attribute) 
    5454         
    5555        # Default to ElementTree based serialisation/deserialisation 
     
    6565         
    6666        super(AttributeQuerySOAPBinding, self).__init__(**kw) 
     67        self.__queryAttributes = TypedList(Attribute) 
    6768             
    6869    def __setattr__(self, name, value): 
     
    107108                               doc="List of attributes to query from the " 
    108109                                   "Attribute Authority") 
    109  
    110     def _createQuery(self): 
    111         """ Create a SAML attribute query""" 
    112         attributeQuery = super(AttributeQuerySOAPBinding, self)._createQuery( 
    113                                                                 AttributeQuery) 
    114         # Add list of attributes to query                       
    115         for attribute in self.queryAttributes: 
    116             attributeQuery.attributes.append(attribute) 
    117              
    118         return attributeQuery  
     110# 
     111#    def _createQuery(self): 
     112#        """ Create a SAML attribute query""" 
     113#        attributeQuery = super(AttributeQuerySOAPBinding, self)._createQuery( 
     114#                                                                AttributeQuery) 
     115#        # Add list of attributes to query                       
     116#        for attribute in self.queryAttributes: 
     117#            attributeQuery.attributes.append(attribute) 
     118#             
     119#        return attributeQuery  
    119120 
    120121     
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/authzdecisionquery.py

    r6572 r6578  
    1717from saml.saml2.core import AuthzDecisionQuery 
    1818 
    19 from ndg.security.common.sam_utils.binding.soap.subjectquery import ( 
     19from ndg.security.common.saml_utils.binding.soap.subjectquery import ( 
    2020                                                    SubjectQuerySOAPBinding, 
    2121                                                    SubjectQueryResponseError) 
     
    4040    Nb. Assumes X.509 subject type for query issuer 
    4141    """ 
    42     __slots__ = () 
     42    SERIALISE_KW = 'serialise' 
     43    DESERIALISE_KW = 'deserialise' 
     44    QUERY_TYPE = AuthzDecisionQuery 
     45    __slots__ = ('__resourceURI', '__action', '__actionNs') 
    4346     
    4447    def __init__(self, **kw): 
    4548        '''Create SOAP Client for SAML Authorization Decision Query''' 
     49        cls = AuthzDecisionQuerySOAPBinding 
     50         
     51        # Default to ElementTree based serialisation/deserialisation 
     52        if cls.SERIALISE_KW not in kw: 
     53            from saml.xml.etree import AuthzDecisionQueryElementTree 
     54            kw[cls.SERIALISE_KW] = AuthzDecisionQueryElementTree.toXML 
     55                
     56        if cls.DESERIALISE_KW not in kw: 
     57            from saml.xml.etree import ResponseElementTree 
     58            kw[cls.DESERIALISE_KW] = ResponseElementTree.fromXML 
     59 
    4660        super(AuthzDecisionQuerySOAPBinding, self).__init__(**kw) 
    4761 
     62    def _getResourceURI(self): 
     63        return self.query.resource 
     64 
     65    def _setResourceURI(self, value): 
     66        self.query.resource = value 
     67         
     68    resourceURI = property(_getResourceURI, _setResourceURI,  
     69                           doc="Resource URI to query for access") 
    4870     
    49     def _createQuery(self): 
    50         """Specialisation to force creation of AuthzDecisionQuery type instead 
    51         of SubjectQuery 
    52         """ 
    53         return super(AuthzDecisionQuerySOAPBinding, self)._createQuery( 
    54                                                             AuthzDecisionQuery)  
     71    @property 
     72    def actions(self): 
     73        return self.query.actions 
    5574 
    5675     
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/binding/soap/subjectquery.py

    r6572 r6578  
    5656    """ 
    5757    SUBJECT_ID_OPTNAME = 'subjectID' 
     58    SUBJECT_ID_FORMAT_OPTNAME = 'subjectIdFormat' 
    5859    ISSUER_NAME_OPTNAME = 'issuerName' 
    5960    ISSUER_FORMAT_OPTNAME = 'issuerFormat' 
    60     SUBJECT_ID_FORMAT_OPTNAME = 'subjectIdFormat' 
    6161    CLOCK_SKEW_OPTNAME = 'clockSkewTolerance' 
    6262    VERIFY_TIME_CONDITIONS_OPTNAME = 'verifyTimeConditions' 
     
    7272     
    7373    __PRIVATE_ATTR_PREFIX = "__" 
    74     __slots__ = tuple([__PRIVATE_ATTR_PREFIX + i for i in CONFIG_FILE_OPTNAMES]) 
     74    __slots__ = tuple([__PRIVATE_ATTR_PREFIX + i  
     75                       for i in CONFIG_FILE_OPTNAMES + ('query', )]) 
    7576    del i 
    7677     
     78    QUERY_TYPE = SubjectQuery 
     79     
    7780    def __init__(self, **kw): 
    78         '''Create SOAP Client for SAML Attribute Query''' 
    79         self.__issuerName = None 
    80         self.__issuerFormat = Issuer.X509_SUBJECT 
    81         self.__subjectID = None 
    82         self.__subjectIdFormat = NameID.UNSPECIFIED 
     81        '''Create SOAP Client for SAML Subject Query'''        
    8382        self.__clockSkewTolerance = timedelta(seconds=0.) 
    8483        self.__verifyTimeConditions = True 
    8584         
     85        self._initQuery() 
     86         
    8687        super(SubjectQuerySOAPBinding, self).__init__(**kw) 
    8788 
    88     def _getNameIdFormat(self): 
    89         return self.__subjectIdFormat 
    90  
    91     def _setNameIdFormat(self, value): 
    92         self.__subjectIdFormat = value 
    93  
    94     subjectIdFormat = property(_getNameIdFormat, _setNameIdFormat,  
    95                             doc="Subject Name ID format") 
     89    def _initQuery(self): 
     90        """Initialise query settings""" 
     91        self.__query = self.__class__.QUERY_TYPE() 
     92        self.__query.version = SAMLVersion(SAMLVersion.VERSION_20) 
     93        self.__query.id = str(uuid4()) 
     94         
     95        # These properties access the __query instance 
     96        self.issuerFormat = Issuer.X509_SUBJECT 
     97        self.subjectIdFormat = NameID.UNSPECIFIED 
     98 
     99    def _getQuery(self): 
     100        return self.__query 
     101 
     102    def _setQuery(self, value): 
     103        if not isinstance(value, self.__class__.QUERY_TYPE): 
     104            raise TypeError('Expecting %r query type got %r instead' % 
     105                            (self.__class__, type(value))) 
     106        self.__query = value 
     107 
     108    query = property(_getQuery, _setQuery,  
     109                     doc="SAML Subject Query or derived query type") 
     110 
     111    def _getSubjectID(self): 
     112        if self.__query.subject is None or self.__query.subject.nameID is None: 
     113            return None 
     114        else: 
     115            return self.__query.subject.nameID.value 
     116 
     117    def _setSubjectID(self, value): 
     118        if self.__query.subject is None: 
     119            self.__query.subject = Subject() 
     120             
     121        if self.__query.subject.nameID is None: 
     122            self.__query.subject.nameID = NameID() 
     123             
     124        self.__query.subject.nameID.value = value 
     125 
     126    subjectID = property(_getSubjectID, _setSubjectID,  
     127                         doc="ID to be sent as query subject") 
     128     
     129    def _getSubjectIdFormat(self): 
     130        if self.__query.subject is None or self.__query.subject.nameID is None: 
     131            return None 
     132        else: 
     133            return self.__query.subject.nameID.format 
     134 
     135    def _setSubjectIdFormat(self, value): 
     136        if self.__query.subject is None: 
     137            self.__query.subject = Subject() 
     138             
     139        if self.__query.subject.nameID is None: 
     140            self.__query.subject.nameID = NameID() 
     141             
     142        self.__query.subject.nameID.format = value 
     143 
     144    subjectIdFormat = property(_getSubjectIdFormat, _setSubjectIdFormat,  
     145                               doc="Subject Name ID format") 
    96146 
    97147    def _getIssuerFormat(self): 
    98         return self.__issuerFormat 
     148        if self.__query.issuer is None: 
     149            return None 
     150        else: 
     151            return self.__query.issuer.value 
    99152 
    100153    def _setIssuerFormat(self, value): 
    101         if not isinstance(value, basestring): 
    102             raise TypeError('Expecting string type for "issuerFormat"; got %r ' 
    103                             'instead' % type(value)) 
    104         self.__issuerFormat = value 
     154        if self.__query.issuer is None: 
     155            self.__query.issuer = Issuer() 
     156             
     157        self.__query.issuer.format = value 
    105158 
    106159    issuerFormat = property(_getIssuerFormat, _setIssuerFormat,  
    107160                            doc="Issuer format") 
     161 
     162    def _getIssuerName(self): 
     163        if self.__query.issuer is None: 
     164            return None 
     165        else: 
     166            return self.__query.issuer.value 
     167 
     168    def _setIssuerName(self, value): 
     169        if self.__query.issuer is None: 
     170            self.__query.issuer = Issuer() 
     171             
     172        self.__query.issuer.value = value 
     173 
     174    issuerName = property(_getIssuerName, _setIssuerName,  
     175                        doc="Distinguished Name of issuer of SAML Attribute " 
     176                            "Query to Attribute Authority") 
    108177 
    109178    def _getVerifyTimeConditions(self): 
     
    125194                                    doc='Set to True to verify any time ' 
    126195                                        'Conditions set in the returned ' 
    127                                         'response assertions') 
    128          
    129     def _getSubjectID(self): 
    130         return self.__subjectID 
    131  
    132     def _setSubjectID(self, value): 
    133         if not isinstance(value, basestring): 
    134             raise TypeError('Expecting string type for "subjectID"; got %r ' 
    135                             'instead' % type(value)) 
    136         self.__subjectID = value 
    137  
    138     subjectID = property(_getSubjectID, _setSubjectID,  
    139                          doc="ID to be sent as query subject")   
    140  
    141     def _getIssuerName(self): 
    142         return self.__issuerName 
    143  
    144     def _setIssuerName(self, value): 
    145         if not isinstance(value, basestring): 
    146             raise TypeError('Expecting string type for "issuerName"; ' 
    147                             'got %r instead' % type(value)) 
    148              
    149         self.__issuerName = value 
    150  
    151     issuerName = property(_getIssuerName, _setIssuerName,  
    152                         doc="Distinguished Name of issuer of SAML Attribute " 
    153                             "Query to Attribute Authority") 
     196                                        'response assertions')   
    154197 
    155198    def _getClockSkewTolerance(self): 
     
    172215                                      "assertion condition notBefore and " 
    173216                                      "notOnOrAfter times to allow for clock " 
    174                                       "skew")   
    175  
    176     def _createQuery(self, queryClass=SubjectQuery): 
    177         """ Create a SAML SubjectQuery derived type instance 
    178         @param queryClass: query type to create - must be  
    179         saml.saml2.core.SubjectQuery type 
    180         @type queryClass: type 
    181         @return: query instance 
    182         @rtype: saml.saml2.core.SubjectQuery 
    183         """ 
    184         if not issubclass(queryClass, SubjectQuery): 
    185             raise TypeError('Query class %r is not a SubjectQuery derived type' 
    186                             % queryClass) 
    187              
    188         query = queryClass() 
    189         query.version = SAMLVersion(SAMLVersion.VERSION_20) 
    190         query.id = str(uuid4()) 
    191         query.issueInstant = datetime.utcnow() 
    192          
     217                                      "skew") 
     218     
     219    def _validateQueryParameters(self): 
     220        """Perform sanity check immediately before creating the query and  
     221        sending it""" 
    193222        if self.issuerName is None: 
    194             raise AttributeError('No issuer DN has been set for SAML Query') 
    195          
    196         query.issuer = Issuer() 
    197         query.issuer.format = self.issuerFormat 
    198         query.issuer.value = self.issuerName 
    199                          
    200         query.subject = Subject()   
    201         query.subject.nameID = NameID() 
    202         query.subject.nameID.format = self.subjectIdFormat 
    203         query.subject.nameID.value = self.subjectID 
    204              
    205         return query 
     223            raise AttributeError('No issuer name has been set for SAML Query') 
     224 
     225        if self.issuerFormat is None: 
     226            raise AttributeError('No issuer format has been set for SAML Query') 
     227         
     228        if self.subjectID is None: 
     229            raise AttributeError('No subject has been set for SAML Query') 
     230         
     231        if self.subjectIdFormat is None: 
     232            raise AttributeError('No subject format has been set for SAML ' 
     233                                 'Query') 
     234 
     235    def _initSend(self): 
     236        """Perform any final initialisation prior to sending the query - derived 
     237        classes may overload to specify as required""" 
     238        self.__query.issueInstant = datetime.utcnow() 
    206239 
    207240    def send(self, **kw): 
     
    214247        defaults to ndg.security.common.soap.client.UrlLib2SOAPRequest 
    215248        ''' 
    216         query = self._createQuery() 
    217              
    218         response = super(SubjectQuerySOAPBinding, self).send(query, **kw) 
     249        self._validateQueryParameters()  
     250        self._initSend() 
     251            
     252        response = super(SubjectQuerySOAPBinding, self).send(self.query, **kw) 
    219253 
    220254        # Perform validation 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/saml_utils/esg/xml/etree.py

    r6069 r6578  
    1616 
    1717from saml.xml import XMLTypeParseError, UnknownAttrProfile 
    18 from saml.xml.etree import AttributeValueElementTreeBase, QName 
     18from saml.xml.etree import (AttributeValueElementTreeBase, ResponseElementTree, 
     19                            QName) 
    1920 
    2021from ndg.security.common.saml_utils.esg import XSGroupRoleAttributeValue 
     
    138139        return None 
    139140 
     141 
     142class EsgResponseElementTree(ResponseElementTree): 
     143    """Extend ResponseElementTree type for Attribute Query Response to include  
     144    ESG custom Group/Role Attribute support""" 
     145     
     146    @classmethod 
     147    def toXML(cls, response, **kw): 
     148        # Add mapping for ESG Group/Role Attribute Value to enable ElementTree 
     149        # Attribute Value factory to render the XML output 
     150        toXMLTypeMap = kw.get('customToXMLTypeMap', {}) 
     151        toXMLTypeMap[XSGroupRoleAttributeValue 
     152                     ] = XSGroupRoleAttributeValueElementTree 
     153         
     154        kw['customToXMLTypeMap'] = toXMLTypeMap 
     155         
     156        # Convert to ElementTree representation to enable attachment to SOAP 
     157        # response body 
     158        return ResponseElementTree.toXML(response, **kw) 
     159     
     160    @classmethod 
     161    def fromXML(cls, elem, **kw): 
     162        toSAMLTypeMap = kw.get('customToSAMLTypeMap', []) 
     163        toSAMLTypeMap.append( 
     164                        XSGroupRoleAttributeValueElementTree.factoryMatchFunc) 
     165        kw['customToSAMLTypeMap'] = toSAMLTypeMap 
     166         
     167        return ResponseElementTree.fromXML(elem, **kw) 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/soap/client.py

    r6063 r6578  
    137137    def __init__(self): 
    138138        self.__fileobject = None 
    139  
    140     def _getFileobject(self): 
     139         
     140    @property 
     141    def fileobject(self): 
     142        "urllib2 file object returned from request" 
    141143        return self.__fileobject 
    142  
    143     fileobject = property(fget=_getFileobject, 
    144                           doc="urllib2 file object returned from request") 
    145144 
    146145     
    147146class UrlLib2SOAPClient(SOAPClientBase): 
    148147    """urllib2 based SOAP Client""" 
     148    DEFAULT_HTTP_HEADER = {'Content-type': 'text/xml'} 
    149149     
    150150    def __init__(self): 
     
    154154        self.__openerDirector.add_handler(urllib2.HTTPHandler()) 
    155155        self.__timeout = None 
     156        self.__httpHeader = UrlLib2SOAPClient.DEFAULT_HTTP_HEADER.copy() 
     157 
     158    def _getHttpHeader(self): 
     159        return self.__httpHeader 
     160 
     161    def _setHttpHeader(self, value): 
     162        if not isinstance(value, dict): 
     163            raise TypeError('Expecting dict type for "httpHeader" attribute; ' 
     164                            'got %r instead' % type(value)) 
     165        self.__httpHeader = value 
     166 
     167    httpHeader = property(_getHttpHeader, _setHttpHeader,  
     168                          doc="Set HTTP header fields in this dict object") 
    156169 
    157170    def _getTimeout(self): 
     
    203216             
    204217        soapRequestStr = soapRequest.envelope.serialize() 
    205          
    206         if log.level <= logging.DEBUG: 
     218 
     219        if log.getEffectiveLevel() <= logging.DEBUG: 
    207220            from ndg.security.common.utils.etree import prettyPrint 
    208221            log.debug("SOAP Request:") 
     
    211224 
    212225        soapResponse = UrlLib2SOAPResponse() 
    213         response = self.openerDirector.open(soapRequest.url,  
     226        urllib2Request = urllib2.Request(soapRequest.url)  
     227        for i in self.httpHeader.items(): 
     228            urllib2Request.add_header(*i) 
     229             
     230        response = self.openerDirector.open(urllib2Request,  
    214231                                            soapRequestStr,  
    215232                                            *arg) 
    216233        if response.code != httplib.OK: 
    217             output = response.read() 
    218234            excep = HTTPException("Response for request to [%s] is: %d %s" %  
    219235                                  (soapRequest.url,  
  • TI12-security/trunk/NDGSecurity/python/ndg_security_common/ndg/security/common/soap/etree.py

    r5601 r6578  
    148148         
    149149        self.qname = QName(SOAPEnvelopeBase.DEFAULT_ELEMENT_NS,  
    150                              tag=SOAPEnvelopeBase.DEFAULT_ELEMENT_LOCAL_NAME,  
    151                              prefix=SOAPEnvelopeBase.DEFAULT_ELEMENT_NS_PREFIX) 
     150                           tag=SOAPEnvelopeBase.DEFAULT_ELEMENT_LOCAL_NAME,  
     151                           prefix=SOAPEnvelopeBase.DEFAULT_ELEMENT_NS_PREFIX) 
    152152        self.__header = SOAPHeader() 
    153153        self.__body = SOAPBody() 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/saml/__init__.py

    r6573 r6578  
    99__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1010__revision__ = "$Id: $" 
    11 __license__ = "BSD - see LICENSE file in top-levle directory" 
     11__license__ = "BSD - see LICENSE file in top-level directory" 
     12import logging 
     13log = logging.getLogger(__name__) 
     14import traceback 
     15from cStringIO import StringIO 
     16from uuid import uuid4 
     17from datetime import datetime 
     18from xml.etree import ElementTree 
     19 
     20from saml.saml2.core import Response, AttributeQuery, Status, StatusCode  
     21from saml.xml import UnknownAttrProfile 
     22from saml.xml.etree import AttributeQueryElementTree, ResponseElementTree 
     23 
     24from ndg.security.common.saml_utils.esg import XSGroupRoleAttributeValue 
     25from ndg.security.common.saml_utils.esg.xml.etree import ( 
     26                                        XSGroupRoleAttributeValueElementTree) 
     27from ndg.security.common.soap.etree import SOAPEnvelope 
     28from ndg.security.common.utils.factory import importModuleObject 
     29from ndg.security.server.wsgi import NDGSecurityPathFilter 
     30from ndg.security.server.wsgi.soap import SOAPMiddleware 
     31 
     32 
     33class SOAPQueryInterfaceMiddlewareError(Exception): 
     34    """Base class for WSGI SAML 2.0 SOAP Query Interface Errors""" 
     35 
     36 
     37class SOAPQueryInterfaceMiddlewareConfigError(Exception): 
     38    """WSGI SAML 2.0 SOAP Query Interface Configuration problem""" 
     39 
     40   
     41class SOAPQueryInterfaceMiddleware(SOAPMiddleware, NDGSecurityPathFilter): 
     42    """Implementation of SAML 2.0 SOAP Binding for Query/Request Binding 
     43     
     44    @type PATH_OPTNAME: basestring 
     45    @cvar PATH_OPTNAME: name of app_conf option for specifying a path or paths 
     46    that this middleware will intercept and process 
     47    @type QUERY_INTERFACE_KEYNAME_OPTNAME: basestring 
     48    @cvar QUERY_INTERFACE_KEYNAME_OPTNAME: app_conf option name for key name 
     49    used to reference the SAML query interface in environ 
     50    @type DEFAULT_QUERY_INTERFACE_KEYNAME: basestring 
     51    @param DEFAULT_QUERY_INTERFACE_KEYNAME: default key name for referencing 
     52    SAML query interface in environ 
     53    """ 
     54    log = logging.getLogger('SOAPQueryInterfaceMiddleware') 
     55    PATH_OPTNAME = "pathMatchList" 
     56    QUERY_INTERFACE_KEYNAME_OPTNAME = "queryInterfaceKeyName" 
     57    DEFAULT_QUERY_INTERFACE_KEYNAME = ("ndg.security.server.wsgi.saml." 
     58                            "SOAPQueryInterfaceMiddleware.queryInterface") 
     59     
     60    REQUEST_ENVELOPE_CLASS_OPTNAME = 'requestEnvelopeClass' 
     61    RESPONSE_ENVELOPE_CLASS_OPTNAME = 'responseEnvelopeClass' 
     62    SERIALISE_OPTNAME = 'serialise' 
     63    DESERIALISE_OPTNAME = 'deserialise'  
     64      
     65    CONFIG_FILE_OPTNAMES = ( 
     66        PATH_OPTNAME, 
     67        QUERY_INTERFACE_KEYNAME_OPTNAME, 
     68        DEFAULT_QUERY_INTERFACE_KEYNAME, 
     69        REQUEST_ENVELOPE_CLASS_OPTNAME, 
     70        RESPONSE_ENVELOPE_CLASS_OPTNAME, 
     71        SERIALISE_OPTNAME, 
     72        DESERIALISE_OPTNAME 
     73    ) 
     74     
     75    def __init__(self, app): 
     76        '''@type app: callable following WSGI interface 
     77        @param app: next middleware application in the chain  
     78        '''      
     79        NDGSecurityPathFilter.__init__(self, app, None) 
     80         
     81        self._app = app 
     82         
     83        # Set defaults 
     84        cls = SOAPQueryInterfaceMiddleware 
     85        self.__queryInterfaceKeyName = cls.DEFAULT_QUERY_INTERFACE_KEYNAME 
     86        self.pathMatchList = ['/'] 
     87        self.__requestEnvelopeClass = None 
     88        self.__responseEnvelopeClass = None 
     89        self.__serialise = None 
     90        self.__deserialise = None 
     91                  
     92    def initialise(self, global_conf, prefix='', **app_conf): 
     93        ''' 
     94        @type global_conf: dict         
     95        @param global_conf: PasteDeploy global configuration dictionary 
     96        @type prefix: basestring 
     97        @param prefix: prefix for configuration items 
     98        @type app_conf: dict         
     99        @param app_conf: PasteDeploy application specific configuration  
     100        dictionary 
     101        ''' 
     102        cls = SOAPQueryInterfaceMiddleware 
     103         
     104        # Override where set in config 
     105        for name in SOAPQueryInterfaceMiddleware.CONFIG_FILE_OPTNAMES: 
     106            val = app_conf.get(prefix + name) 
     107            if val is not None: 
     108                setattr(self, name, val) 
     109 
     110        if self.serialise is None: 
     111            raise AttributeError('No "serialise" method set to serialise the ' 
     112                                 'SAML response from this middleware.') 
     113 
     114        if self.deserialise is None: 
     115            raise AttributeError('No "deserialise" method set to parse the ' 
     116                                 'SAML request to this middleware.') 
     117             
     118    def _getSerialise(self): 
     119        return self.__serialise 
     120 
     121    def _setSerialise(self, value): 
     122        if isinstance(value, basestring): 
     123            self.__serialise = importModuleObject(value) 
     124             
     125        elif callable(value): 
     126            self.__serialise = value 
     127        else: 
     128            raise TypeError('Expecting callable for "serialise"; got %r' %  
     129                            value) 
     130 
     131    serialise = property(_getSerialise, _setSerialise,  
     132                         doc="callable to serialise request into XML type") 
     133 
     134    def _getDeserialise(self): 
     135        return self.__deserialise 
     136 
     137    def _setDeserialise(self, value): 
     138        if isinstance(value, basestring): 
     139            self.__deserialise = importModuleObject(value) 
     140             
     141        elif callable(value): 
     142            self.__deserialise = value 
     143        else: 
     144            raise TypeError('Expecting callable for "deserialise"; got %r' %  
     145                            value) 
     146         
     147 
     148    deserialise = property(_getDeserialise,  
     149                           _setDeserialise,  
     150                           doc="callable to de-serialise response from XML " 
     151                               "type")         
     152    @classmethod 
     153    def filter_app_factory(cls, app, global_conf, **app_conf): 
     154        """Set-up using a Paste app factory pattern.  Set this method to avoid 
     155        possible conflicts from multiple inheritance 
     156         
     157        @type app: callable following WSGI interface 
     158        @param app: next middleware application in the chain       
     159        @type global_conf: dict         
     160        @param global_conf: PasteDeploy global configuration dictionary 
     161        @type prefix: basestring 
     162        @param prefix: prefix for configuration items 
     163        @type app_conf: dict         
     164        @param app_conf: PasteDeploy application specific configuration  
     165        dictionary 
     166        """ 
     167        app = cls(app) 
     168        app.initialise(global_conf, **app_conf) 
     169         
     170        return app 
     171     
     172    def _getQueryInterfaceKeyName(self): 
     173        return self.__queryInterfaceKeyName 
     174 
     175    def _setQueryInterfaceKeyName(self, value): 
     176        if not isinstance(value, basestring): 
     177            raise TypeError('Expecting string type for "queryInterfaceKeyName"' 
     178                            ' got %r' % value) 
     179             
     180        self.__queryInterfaceKeyName = value 
     181 
     182    queryInterfaceKeyName = property(fget=_getQueryInterfaceKeyName,  
     183                                     fset=_setQueryInterfaceKeyName,  
     184                                     doc="environ keyname for Attribute Query " 
     185                                         "interface") 
     186     
     187    @NDGSecurityPathFilter.initCall 
     188    def __call__(self, environ, start_response): 
     189        """Check for and parse a SOAP SAML Attribute Query and return a 
     190        SAML Response 
     191         
     192        @type environ: dict 
     193        @param environ: WSGI environment variables dictionary 
     194        @type start_response: function 
     195        @param start_response: standard WSGI start response function 
     196        """ 
     197     
     198        # Ignore non-matching path 
     199        if not self.pathMatch: 
     200            return self._app(environ, start_response) 
     201           
     202        # Ignore non-POST requests 
     203        if environ.get('REQUEST_METHOD') != 'POST': 
     204            return self._app(environ, start_response) 
     205         
     206        soapRequestStream = environ.get('wsgi.input') 
     207        if soapRequestStream is None: 
     208            raise SOAPQueryInterfaceMiddlewareError('No "wsgi.input" in ' 
     209                                                    'environ') 
     210         
     211        # TODO: allow for chunked data 
     212        contentLength = environ.get('CONTENT_LENGTH') 
     213        if contentLength is None: 
     214            raise SOAPQueryInterfaceMiddlewareError('No "CONTENT_LENGTH" in ' 
     215                                                    'environ') 
     216 
     217        contentLength = int(contentLength)         
     218        soapRequestTxt = soapRequestStream.read(contentLength) 
     219         
     220        # Parse into a SOAP envelope object 
     221        soapRequest = SOAPEnvelope() 
     222        soapRequest.parse(StringIO(soapRequestTxt)) 
     223         
     224        log.debug("SOAPQueryInterfaceMiddleware.__call__: received SAML " 
     225                  "SOAP AttributeQuery ...") 
     226        
     227        queryElem = soapRequest.body.elem[0] 
     228         
     229        try: 
     230            query = self.deserialise(queryElem) 
     231        except UnknownAttrProfile: 
     232            log.exception("%r raised parsing incoming query: " %  
     233                          (type(e), traceback.format_exc())) 
     234            samlResponse = self._makeErrorResponse( 
     235                                        StatusCode.UNKNOWN_ATTR_PROFILE_URI) 
     236        else:    
     237            # Check for Query Interface in environ 
     238            queryInterface = environ.get(self.queryInterfaceKeyName) 
     239            if queryInterface is None: 
     240                raise SOAPQueryInterfaceMiddlewareConfigError( 
     241                                'No query interface "%s" key found in environ' % 
     242                                self.queryInterfaceKeyName) 
     243             
     244            # Call query interface         
     245            samlResponse = queryInterface(query) 
     246         
     247        # Convert to ElementTree representation to enable attachment to SOAP 
     248        # response body 
     249        samlResponseElem = self.serialise(samlResponse) 
     250         
     251        # Create SOAP response and attach the SAML Response payload 
     252        soapResponse = SOAPEnvelope() 
     253        soapResponse.create() 
     254        soapResponse.body.elem.append(samlResponseElem) 
     255         
     256        response = soapResponse.serialize() 
     257         
     258        log.debug("SOAPQueryInterfaceMiddleware.__call__: sending response " 
     259                  "...\n\n%s", 
     260                  response) 
     261        start_response("200 OK", 
     262                       [('Content-length', str(len(response))), 
     263                        ('Content-type', 'text/xml')]) 
     264        return [response] 
     265 
     266    def _makeErrorResponse(self, code): 
     267        """Convenience method for making a basic response following an error 
     268        """ 
     269        samlResponse = Response() 
     270         
     271        samlResponse.issueInstant = datetime.utcnow()             
     272        samlResponse.id = str(uuid4()) 
     273         
     274        # Initialise to success status but reset on error 
     275        samlResponse.status = Status() 
     276        samlResponse.status.statusCode = StatusCode() 
     277        samlResponse.status.statusCode.value = code 
     278         
     279        return samlResponse 
     280 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/wsgi/saml/attributeinterface.py

    r6575 r6578  
    192192            if queryInterface is None: 
    193193                raise SOAPAttributeInterfaceMiddlewareConfigError( 
    194                                 'No query interface "%s" key found in environ'% 
     194                                'No query interface "%s" key found in environ' % 
    195195                                self.queryInterfaceKeyName) 
    196196             
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/config/attributeauthority/sitea/siteAUserRoles.py

    r6067 r6578  
    7979    ISSUER_NAME = "/O=Site A/CN=Attribute Authority" 
    8080     
    81     INSUFFICIENT_PRIVILEGES_REQUESTOR_ID = str( 
    82                     X500DN.fromString("/O=Site B/CN=Authorisation Service")) 
     81    INSUFFICIENT_PRIVILEGES_REQUESTOR_ID = X500DN.fromString( 
     82                                        "/O=Site B/CN=Authorisation Service") 
    8383     
    8484    def __init__(self, propertiesFilePath=None): 
     
    9494        requestedAttributeNames = [attribute.name  
    9595                                   for attribute in attributeQuery.attributes] 
     96        if attributeQuery.issuer.format != Issuer.X509_SUBJECT: 
     97            raise InvalidRequestorId('Requestor issuer format "%s" is invalid' % 
     98                                     attributeQuery.issuerFormat.value) 
     99             
    96100        requestorId = X500DN.fromString(attributeQuery.issuer.value) 
    97101         
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/wsgi/saml/__init__.py

    r6575 r6578  
    1515from ndg.security.test.unit import BaseTestCase 
    1616 
     17 
    1718class TestApp(object): 
     19    """Dummy application to terminate middleware stack containing SAML service 
     20    """ 
    1821    def __init__(self, global_conf, **app_conf): 
    1922        pass 
     
    3841        self.app = paste.fixture.TestApp(wsgiapp) 
    3942          
    40         unittest.TestCase.__init__(self, *args, **kwargs) 
     43        BaseTestCase.__init__(self, *args, **kwargs) 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/wsgi/saml/attribute-interface.ini

    r6575 r6578  
    2121 
    2222[filter:SAMLSoapAttributeInterfaceFilter] 
    23 paste.filter_app_factory = ndg.security.server.wsgi.saml.attributeinterface:SOAPAttributeInterfaceMiddleware.filter_app_factory 
     23paste.filter_app_factory = ndg.security.server.wsgi.saml:SOAPQueryInterfaceMiddleware.filter_app_factory 
    2424prefix = saml. 
    2525saml.pathMatchList = /attributeauthority/saml 
    2626saml.queryInterfaceKeyName = attributeQueryInterface 
     27saml.deserialise = saml.xml.etree:AttributeQueryElementTree.fromXML 
     28 
     29# Specialisation to incorporate ESG Group/Role type 
     30saml.serialise = ndg.security.common.saml_utils.esg.xml.etree:EsgResponseElementTree.toXML 
    2731 
    2832#______________________________________________________________________________ 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/wsgi/saml/authz-decision-interface.ini

    r6575 r6578  
    1515 
    1616[pipeline:main] 
    17 pipeline = AttributeAuthorityFilter SAMLSoapAttributeInterfaceFilter TestApp 
     17pipeline = TestAuthorisationServiceFilter SAMLSoapAuthzDecisionInterfaceFilter TestApp 
    1818 
    1919[app:TestApp] 
    2020paste.app_factory = ndg.security.test.unit.wsgi.saml:TestApp 
    2121 
    22 [filter:SAMLSoapAttributeInterfaceFilter] 
    23 paste.filter_app_factory = ndg.security.server.wsgi.saml.attributeinterface:SOAPAttributeInterfaceMiddleware.filter_app_factory 
     22[filter:SAMLSoapAuthzDecisionInterfaceFilter] 
     23paste.filter_app_factory = ndg.security.server.wsgi.saml:SOAPQueryInterfaceMiddleware.filter_app_factory 
    2424prefix = saml. 
    25 saml.pathMatchList = /attributeauthority/saml 
    26 saml.queryInterfaceKeyName = attributeQueryInterface 
     25saml.pathMatchList = /authorisationservice 
     26saml.queryInterfaceKeyName = AUTHZ_DECISION_QUERY_FUNC 
     27saml.deserialise = saml.xml.etree:AuthzDecisionQueryElementTree.fromXML 
     28saml.serialise = saml.xml.etree:ResponseElementTree.toXML 
    2729 
    2830#______________________________________________________________________________ 
    29 # Attribute Authority WSGI settings 
     31# Authorisation Service WSGI settings 
    3032# 
    31 [filter:AttributeAuthorityFilter] 
     33[filter:TestAuthorisationServiceFilter] 
    3234# This filter is a container for a binding to a SOAP based interface to the 
    3335# Attribute Authority 
    34 paste.filter_app_factory = ndg.security.server.wsgi.attributeauthority:AttributeAuthorityMiddleware.filter_app_factory 
    35  
    36 prefix = attributeAuthority. 
    37  
    38 attributeAuthority.environKeyName: attributeauthority 
    39 attributeAuthority.environKeyNameAttributeQueryInterface: attributeQueryInterface 
    40  
    41 # Attribute Authority settings 
    42 # 'name' setting MUST agree with map config file 'thisHost' name attribute 
    43 attributeAuthority.name: Site A 
    44  
    45 # Lifetime is measured in seconds 
    46 attributeAuthority.attCertLifetime: 28800  
    47  
    48 # Allow an offset for clock skew between servers running  
    49 # security services. NB, measured in seconds - use a minus sign for time in the 
    50 # past 
    51 attributeAuthority.attCertNotBeforeOff: 0 
    52  
    53 # All Attribute Certificates issued are recorded in this dir 
    54 attributeAuthority.attCertDir: %(testConfigDir)s/attributeauthority/sitea/attributeCertificateLog 
    55  
    56 # Files in attCertDir are stored using a rotating file handler 
    57 # attCertFileLogCnt sets the max number of files created before the first is  
    58 # overwritten 
    59 attributeAuthority.attCertFileName: ac.xml 
    60 attributeAuthority.attCertFileLogCnt: 16 
    61 attributeAuthority.dnSeparator:/ 
    62  
    63 # Location of role mapping file 
    64 attributeAuthority.mapConfigFilePath: %(testConfigDir)s/attributeauthority/sitea/siteAMapConfig.xml 
    65  
    66 # Settings for custom AttributeInterface derived class to get user roles for given  
    67 # user ID 
    68 attributeAuthority.attributeInterface.modFilePath: %(testConfigDir)s/attributeauthority/sitea 
    69 attributeAuthority.attributeInterface.modName: ndg.security.test.config.attributeauthority.sitea.siteAUserRoles 
    70 attributeAuthority.attributeInterface.className: TestUserRoles 
    71  
    72 # Config for XML signature of Attribute Certificate 
    73 attributeAuthority.signingPriKeyFilePath: %(testConfigDir)s/attributeauthority/sitea/siteA-aa.key 
    74 attributeAuthority.signingCertFilePath: %(testConfigDir)s/attributeauthority/sitea/siteA-aa.crt 
    75 attributeAuthority.caCertFilePathList: %(testConfigDir)s/ca/ndg-test-ca.crt 
     36paste.filter_app_factory = ndg.security.test.unit.wsgi.saml.test_soapauthzdecisioninterface:TestAuthorisationServiceMiddleware 
     37queryInterfaceKeyName = AUTHZ_DECISION_QUERY_FUNC 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/wsgi/saml/test_soapattributeinterface.py

    r6574 r6578  
    1010__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1111__revision__ = '$Id: $' 
     12import unittest 
    1213from uuid import uuid4 
    1314from datetime import datetime 
     
    2223from ndg.security.common.soap.etree import SOAPEnvelope 
    2324from ndg.security.common.saml_utils.esg import EsgSamlNamespaces 
    24  
    25  
    26 class SOAPAttributeInterfaceMiddlewareTestCase(unittest.TestCase): 
     25from ndg.security.test.unit.wsgi.saml import SoapSamlInterfaceMiddlewareTestCase 
     26 
     27 
     28class SOAPAttributeInterfaceMiddlewareTestCase( 
     29                                        SoapSamlInterfaceMiddlewareTestCase): 
    2730    CONFIG_FILENAME = 'attribute-interface.ini' 
    2831     
     
    179182                     StatusCode.INVALID_ATTR_NAME_VALUE_URI) 
    180183         
    181     def test04InvalidIssuer(self): 
    182         request = self._makeRequest(issuer="My Attribute Query Issuer") 
     184    def test04InvalidQueryIssuer(self): 
     185        request = self._makeRequest(issuer="/CN=My Attribute Query Issuer") 
    183186         
    184187        header = { 
  • TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/wsgi/saml/test_soapauthzdecisioninterface.py

    r6575 r6578  
    11#!/usr/bin/env python 
    2 """Unit tests for WSGI SAML 2.0 SOAP Attribute Query Interface 
     2"""Unit tests for WSGI SAML 2.0 SOAP Authorisation Decision Query Interface 
    33 
    44NERC DataGrid Project 
    55""" 
    66__author__ = "P J Kershaw" 
    7 __date__ = "21/08/09" 
    8 __copyright__ = "(C) 2009 Science and Technology Facilities Council" 
     7__date__ = "15/02/2010" 
     8__copyright__ = "(C) 2010 Science and Technology Facilities Council" 
    99__license__ = "BSD - see LICENSE file in top-level directory" 
    1010__contact__ = "Philip.Kershaw@stfc.ac.uk" 
    1111__revision__ = '$Id: $' 
     12import unittest 
    1213from uuid import uuid4 
    13 from datetime import datetime 
     14from datetime import datetime, timedelta 
    1415from cStringIO import StringIO 
    1516 
    16 from saml.saml2.core import (Attribute, SAMLVersion, Subject, NameID, Issuer,  
    17                              AttributeQuery, XSStringAttributeValue,  
    18                              StatusCode) 
    19 from saml.xml import XMLConstants 
    20 from saml.xml.etree import AttributeQueryElementTree, ResponseElementTree 
     17from saml.saml2.core import (SAMLVersion, Subject, NameID, Issuer, Response, 
     18                             AuthzDecisionQuery, AuthzDecisionStatement, Status, 
     19                             StatusCode, StatusMessage, DecisionType, Action,  
     20                             Conditions, Assertion) 
     21from saml.xml.etree import AuthzDecisionQueryElementTree, ResponseElementTree 
    2122 
    2223from ndg.security.common.soap.etree import SOAPEnvelope 
     
    2526 
    2627 
    27 class SOAPAuthzDecisionInterfaceMiddlewareTestCase(unittest.TestCase): 
     28class TestAuthorisationServiceMiddleware(object): 
     29    """Test Authorisation Service interface stub""" 
     30    QUERY_INTERFACE_KEYNAME_OPTNAME = 'queryInterfaceKeyName' 
     31    RESOURCE_URI = 'http://localhost/dap/data/' 
     32    ISSUER_DN = '/O=Site A/CN=PDP' 
     33     
     34    def __init__(self, app, global_conf, **app_conf): 
     35        self.queryInterfaceKeyName = app_conf[ 
     36            TestAuthorisationServiceMiddleware.QUERY_INTERFACE_KEYNAME_OPTNAME] 
     37        self._app = app 
     38     
     39    def __call__(self, environ, start_response): 
     40        environ[self.queryInterfaceKeyName] = self.authzDecisionQueryFactory() 
     41        return self._app(environ, start_response) 
     42     
     43    def authzDecisionQueryFactory(self): 
     44        def authzDecisionQuery(query): 
     45            response = Response() 
     46            now = datetime.utcnow() 
     47            response.issueInstant = now 
     48             
     49            # Make up a request ID that this response is responding to 
     50            response.inResponseTo = query.id 
     51            response.id = str(uuid4()) 
     52            response.version = SAMLVersion(SAMLVersion.VERSION_20) 
     53                 
     54            response.issuer = Issuer() 
     55            response.issuer.format = Issuer.X509_SUBJECT 
     56            response.issuer.value = TestAuthorisationServiceMiddleware.ISSUER_DN 
     57             
     58            response.status = Status() 
     59            response.status.statusCode = StatusCode() 
     60            response.status.statusCode.value = StatusCode.SUCCESS_URI 
     61            response.status.statusMessage = StatusMessage()         
     62            response.status.statusMessage.value = \ 
     63                                                "Response created successfully" 
     64                
     65            assertion = Assertion() 
     66            assertion.version = SAMLVersion(SAMLVersion.VERSION_20) 
     67            assertion.id = str(uuid4()) 
     68            assertion.issueInstant = now 
     69             
     70            authzDecisionStatement = AuthzDecisionStatement() 
     71            authzDecisionStatement.decision = DecisionType.PERMIT 
     72            authzDecisionStatement.resource = \ 
     73                TestAuthorisationServiceMiddleware.RESOURCE_URI 
     74            authzDecisionStatement.actions.append(Action()) 
     75            authzDecisionStatement.actions[-1].namespace = Action.GHPP_NS_URI 
     76            authzDecisionStatement.actions[-1].value = Action.HTTP_GET_ACTION 
     77            assertion.authzDecisionStatements.append(authzDecisionStatement) 
     78             
     79            # Add a conditions statement for a validity of 8 hours 
     80            assertion.conditions = Conditions() 
     81            assertion.conditions.notBefore = now 
     82            assertion.conditions.notOnOrAfter = now + timedelta(seconds=60*60*8) 
     83                    
     84            assertion.subject = Subject()   
     85            assertion.subject.nameID = NameID() 
     86            assertion.subject.nameID.format = query.subject.nameID.format 
     87            assertion.subject.nameID.value = query.subject.nameID.value 
     88                 
     89            assertion.issuer = Issuer() 
     90            assertion.issuer.format = Issuer.X509_SUBJECT 
     91            assertion.issuer.value = \ 
     92                                    TestAuthorisationServiceMiddleware.ISSUER_DN 
     93     
     94            response.assertions.append(assertion) 
     95            return response 
     96         
     97        return authzDecisionQuery 
     98     
     99     
     100class SOAPAuthzDecisionInterfaceMiddlewareTestCase( 
     101                                        SoapSamlInterfaceMiddlewareTestCase): 
    28102    CONFIG_FILENAME = 'authz-decision-interface.ini' 
    29103 
    30104    def _createAuthzDecisionQuery(self,  
    31                         issuer="/O=Site A/CN=Authorisation Service", 
    32                         subject="https://openid.localhost/philip.kershaw"): 
    33         query = AttributeQuery() 
     105                    issuer="/O=Site A/CN=PEP", 
     106                    subject="https://openid.localhost/philip.kershaw", 
     107                    resource=TestAuthorisationServiceMiddleware.RESOURCE_URI, 
     108                    action=Action.HTTP_GET_ACTION, 
     109                    actionNs=Action.GHPP_NS_URI): 
     110        query = AuthzDecisionQuery() 
    34111        query.version = SAMLVersion(SAMLVersion.VERSION_20) 
    35112        query.id = str(uuid4()) 
     
    45122        query.subject.nameID.value = subject 
    46123                                     
    47          
    48         # special case handling for 'FirstName' attribute 
    49         fnAttribute = Attribute() 
    50         fnAttribute.name = EsgSamlNamespaces.FIRSTNAME_ATTRNAME 
    51         fnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string" 
    52         fnAttribute.friendlyName = "FirstName" 
    53  
    54         query.attributes.append(fnAttribute) 
    55      
    56         # special case handling for 'LastName' attribute 
    57         lnAttribute = Attribute() 
    58         lnAttribute.name = EsgSamlNamespaces.LASTNAME_ATTRNAME 
    59         lnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string" 
    60         lnAttribute.friendlyName = "LastName" 
    61  
    62         query.attributes.append(lnAttribute) 
    63      
    64         # special case handling for 'LastName' attribute 
    65         emailAddressAttribute = Attribute() 
    66         emailAddressAttribute.name = EsgSamlNamespaces.EMAILADDRESS_ATTRNAME 
    67         emailAddressAttribute.nameFormat = XMLConstants.XSD_NS+"#"+\ 
    68                                     XSStringAttributeValue.TYPE_LOCAL_NAME 
    69         emailAddressAttribute.friendlyName = "emailAddress" 
    70  
    71         query.attributes.append(emailAddressAttribute)   
     124        query.resource = resource          
     125        query.actions.append(Action()) 
     126        query.actions[0].namespace = actionNs 
     127        query.actions[0].value = action     
    72128 
    73129        return query 
     
    79135            query = self._createAuthzDecisionQuery(**kw) 
    80136             
    81         elem = AuthzDecusionQueryElementTree.toXML(query) 
     137        elem = AuthzDecisionQueryElementTree.toXML(query) 
    82138        soapRequest = SOAPEnvelope() 
    83139        soapRequest.create() 
     
    115171            'Content-type': 'text/xml' 
    116172        } 
    117         response = self.app.post('/attributeauthority/saml',  
     173        response = self.app.post('/authorisationservice/',  
    118174                                 params=request,  
    119175                                 headers=header,  
     
    127183        self.assert_(samlResponse.assertions[0].subject.nameID.value == \ 
    128184                     query.subject.nameID.value) 
    129  
    130     def test02AttributeReleaseDenied(self): 
    131         request = self._makeRequest(issuer="/O=Site B/CN=Authorisation Service") 
     185        self.assert_(samlResponse.assertions[0]) 
     186        self.assert_(samlResponse.assertions[0].authzDecisionStatements[0]) 
     187        self.assert_(samlResponse.assertions[0].authzDecisionStatements[0 
     188                                            ].decision == DecisionType.PERMIT) 
    132189         
    133         header = { 
    134             'soapAction': "http://www.oasis-open.org/committees/security", 
    135             'Content-length': str(len(request)), 
    136             'Content-type': 'text/xml' 
    137         } 
    138          
    139         response = self.app.post('/attributeauthority/saml',  
    140                                  params=request,  
    141                                  headers=header,  
    142                                  status=200) 
    143          
    144         print("Response status=%d" % response.status) 
    145          
    146         samlResponse = self._getSAMLResponse(response.body) 
    147  
    148         self.assert_(samlResponse.status.statusCode.value == \ 
    149                      StatusCode.INVALID_ATTR_NAME_VALUE_URI) 
    150  
    151     def test03InvalidAttributesRequested(self): 
    152         query = self._createAuthzDecisionQuery() 
    153          
    154         # Add an unsupported Attribute name 
    155         attribute = Attribute() 
    156         attribute.name = "urn:my:attribute" 
    157         attribute.nameFormat = XMLConstants.XSD_NS+"#"+\ 
    158                                     XSStringAttributeValue.TYPE_LOCAL_NAME 
    159         attribute.friendlyName = "myAttribute" 
    160         query.attributes.append(attribute)      
    161          
    162         request = self._makeRequest(query=query) 
    163             
    164         header = { 
    165             'soapAction': "http://www.oasis-open.org/committees/security", 
    166             'Content-length': str(len(request)), 
    167             'Content-type': 'text/xml' 
    168         } 
    169         
    170         response = self.app.post('/attributeauthority/saml',  
    171                                  params=request,  
    172                                  headers=header,  
    173                                  status=200) 
    174          
    175         print("Response status=%d" % response.status) 
    176          
    177         samlResponse = self._getSAMLResponse(response.body) 
    178  
    179         self.assert_(samlResponse.status.statusCode.value == \ 
    180                      StatusCode.INVALID_ATTR_NAME_VALUE_URI) 
    181          
    182     def test04InvalidIssuer(self): 
    183         request = self._makeRequest(issuer="My Attribute Query Issuer") 
    184          
    185         header = { 
    186             'soapAction': "http://www.oasis-open.org/committees/security", 
    187             'Content-length': str(len(request)), 
    188             'Content-type': 'text/xml' 
    189         } 
    190         
    191         response = self.app.post('/attributeauthority/saml',  
    192                                  params=request,  
    193                                  headers=header,  
    194                                  status=200) 
    195          
    196         print("Response status=%d" % response.status) 
    197          
    198         samlResponse = self._getSAMLResponse(response.body) 
    199  
    200         self.assert_(samlResponse.status.statusCode.value == \ 
    201                      StatusCode.REQUEST_DENIED_URI) 
    202  
    203     def test05UnknownPrincipal(self): 
    204         request = self._makeRequest(subject="Joe.Bloggs") 
    205          
    206         header = { 
    207             'soapAction': "http://www.oasis-open.org/committees/security", 
    208             'Content-length': str(len(request)), 
    209             'Content-type': 'text/xml' 
    210         } 
    211          
    212         response = self.app.post('/attributeauthority/saml',  
    213                                  params=request,  
    214                                  headers=header,  
    215                                  status=200) 
    216          
    217         print("Response status=%d" % response.status) 
    218          
    219         samlResponse = self._getSAMLResponse(response.body) 
    220  
    221         self.assert_(samlResponse.status.statusCode.value == \ 
    222                      StatusCode.UNKNOWN_PRINCIPAL_URI) 
    223  
     190    def test02(self): 
     191        pass 
    224192  
    225193if __name__ == "__main__": 
Note: See TracChangeset for help on using the changeset viewer.