Ignore:
Timestamp:
16/02/10 16:11:08 (11 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/ndg_security_test/ndg/security/test
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • 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.