source: TI12-security/trunk/ndg_saml/ndg/saml/test/binding/soap/test_samlinterface.py @ 7138

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/ndg_saml/ndg/saml/test/binding/soap/test_samlinterface.py@7138
Revision 7138, 27.6 KB checked in by pjkersha, 10 years ago (diff)

Incomplete - task 2: XACML-Security Integration

  • ported SAML WSGI middleware unit tests from ndg.security.
Line 
1"""Attribute Authority SAML Interface unit test package
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "21/07/09"
7__copyright__ = "(C) 2009 Science and Technology Facilities Council"
8__license__ = "http://www.apache.org/licenses/LICENSE-2.0"
9__contact__ = "Philip.Kershaw@stfc.ac.uk"
10__revision__ = '$Id: test_samlinterface.py 7077 2010-06-24 15:38:19Z pjkersha $'
11import logging
12logging.basicConfig(level=logging.DEBUG)
13import unittest
14
15from datetime import datetime, timedelta
16import os
17from uuid import uuid4
18import paste.fixture
19from cStringIO import StringIO
20from xml.etree import ElementTree
21
22from ndg.saml.utils import SAMLDateTime
23from ndg.saml.saml2.core import (Response, Assertion, Attribute, 
24                             AttributeStatement, SAMLVersion, Subject, NameID,
25                             Issuer, AttributeQuery, XSStringAttributeValue, 
26                             Conditions, Status, StatusCode)
27from ndg.saml.xml import XMLConstants
28from ndg.saml.xml.etree import AttributeQueryElementTree, ResponseElementTree
29from ndg.saml.saml2.binding.soap.subjectquery import (
30    SubjectQuerySOAPBinding, ResponseIssueInstantInvalid, 
31    AssertionIssueInstantInvalid, AssertionConditionNotBeforeInvalid, 
32    AssertionConditionNotOnOrAfterInvalid)
33
34from ndg.soap.client import (UrlLib2SOAPClient, UrlLib2SOAPRequest)
35from ndg.soap.etree import SOAPEnvelope
36from ndg.soap.utils.etree import QName, prettyPrint
37   
38from ndg.security.common.saml_utils.esg import (EsgSamlNamespaces, 
39                                          XSGroupRoleAttributeValue)
40from ndg.security.common.saml_utils.esg.xml.etree import (
41                                        XSGroupRoleAttributeValueElementTree)
42
43
44class SamlSoapBindingApp(object):
45    def __init__(self):
46        self.firstName = "Philip"
47        self.lastName = "Kershaw"
48        self.emailAddress = "pkershaw@somewhere.ac.uk"
49                 
50    def __call__(self, environ, start_response):
51        soapRequestStream = environ['wsgi.input']
52        soapRequest = SOAPEnvelope()
53        soapRequest.parse(soapRequestStream)
54        attributeQueryElem = soapRequest.body.elem[0]
55        attributeQuery = AttributeQueryElementTree.fromXML(attributeQueryElem)
56       
57        print("Received request from client:\n")
58        print soapRequest.prettyPrint()
59       
60        samlResponse = Response()
61       
62        samlResponse.issueInstant = datetime.utcnow()
63        samlResponse.id = str(uuid4())
64        samlResponse.issuer = Issuer()
65       
66        # SAML 2.0 spec says format must be omitted
67        #samlResponse.issuer.format = Issuer.X509_SUBJECT
68        samlResponse.issuer.value = \
69                        "/O=NDG/OU=BADC/CN=attributeauthority.badc.rl.ac.uk"
70       
71        samlResponse.inResponseTo = attributeQuery.id
72       
73        assertion = Assertion()
74       
75        assertion.version = SAMLVersion(SAMLVersion.VERSION_20)
76        assertion.id = str(uuid4())
77        assertion.issueInstant = samlResponse.issueInstant
78       
79        assertion.conditions = Conditions()
80        assertion.conditions.notBefore = assertion.issueInstant
81        assertion.conditions.notOnOrAfter = assertion.conditions.notBefore + \
82            timedelta(seconds=60*60*8)
83       
84        assertion.subject = Subject() 
85        assertion.subject.nameID = NameID()
86        assertion.subject.nameID.format = attributeQuery.subject.nameID.format
87        assertion.subject.nameID.value = attributeQuery.subject.nameID.value
88
89        assertion.attributeStatements.append(AttributeStatement())
90       
91        for attribute in attributeQuery.attributes:
92            if attribute.name == EsgSamlNamespaces.FIRSTNAME_ATTRNAME:
93                # special case handling for 'FirstName' attribute
94                fnAttribute = Attribute()
95                fnAttribute.name = attribute.name
96                fnAttribute.nameFormat = attribute.nameFormat
97                fnAttribute.friendlyName = attribute.friendlyName
98   
99                firstName = XSStringAttributeValue()
100                firstName.value = self.firstName
101                fnAttribute.attributeValues.append(firstName)
102   
103                assertion.attributeStatements[0].attributes.append(fnAttribute)
104           
105            elif attribute.name == EsgSamlNamespaces.LASTNAME_ATTRNAME:
106                lnAttribute = Attribute()
107                lnAttribute.name = attribute.name
108                lnAttribute.nameFormat = attribute.nameFormat
109                lnAttribute.friendlyName = attribute.friendlyName
110   
111                lastName = XSStringAttributeValue()
112                lastName.value = self.lastName
113                lnAttribute.attributeValues.append(lastName)
114   
115                assertion.attributeStatements[0].attributes.append(lnAttribute)
116               
117            elif attribute.name == EsgSamlNamespaces.EMAILADDRESS_ATTRNAME:
118                emailAddressAttribute = Attribute()
119                emailAddressAttribute.name = attribute.name
120                emailAddressAttribute.nameFormat = attribute.nameFormat
121                emailAddressAttribute.friendlyName = attribute.friendlyName
122   
123                emailAddress = XSStringAttributeValue()
124                emailAddress.value = self.emailAddress
125                emailAddressAttribute.attributeValues.append(emailAddress)
126   
127                assertion.attributeStatements[0].attributes.append(
128                                                        emailAddressAttribute)
129       
130        samlResponse.assertions.append(assertion)
131       
132        # Add mapping for ESG Group/Role Attribute Value to enable ElementTree
133        # Attribute Value factory to render the XML output
134        toXMLTypeMap = {
135            XSGroupRoleAttributeValue: XSGroupRoleAttributeValueElementTree
136        }
137
138       
139        samlResponse.status = Status()
140        samlResponse.status.statusCode = StatusCode()
141        samlResponse.status.statusCode.value = StatusCode.SUCCESS_URI       
142
143       
144        # Convert to ElementTree representation to enable attachment to SOAP
145        # response body
146        samlResponseElem = ResponseElementTree.toXML(samlResponse,
147                                            customToXMLTypeMap=toXMLTypeMap)
148        xml = ElementTree.tostring(samlResponseElem)
149       
150        # Create SOAP response and attach the SAML Response payload
151        soapResponse = SOAPEnvelope()
152        soapResponse.create()
153        soapResponse.body.elem.append(samlResponseElem)
154       
155        response = soapResponse.serialize()
156       
157        start_response("200 OK",
158                       [('Content-length', str(len(response))),
159                        ('Content-type', 'text/xml')])
160        return [response]
161
162       
163class SamlAttributeAuthorityInterfaceTestCase(BaseTestCase):
164    """TODO: test SAML Attribute Authority interface"""
165    thisDir = os.path.dirname(os.path.abspath(__file__))
166    RESPONSE = '''\
167<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
168   <SOAP-ENV:Body>
169      <samlp:Response ID="05680cb2-4973-443d-9d31-7bc99bea87c1" InResponseTo="e3183380-ae82-4285-8827-8c40613842de" IssueInstant="%(issueInstant)s" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
170         <saml:Issuer Format="urn:esg:issuer" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">ESG-NCAR</saml:Issuer>
171         <samlp:Status>
172            <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
173         </samlp:Status>
174         <saml:Assertion ID="192c67d9-f9cd-457a-9242-999e7b943166" IssueInstant="%(assertionIssueInstant)s" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
175            <saml:Issuer Format="urn:esg:issuer">ESG-NCAR</saml:Issuer>
176            <saml:Subject>
177               <saml:NameID Format="urn:esg:openid">https://esg.prototype.ucar.edu/myopenid/testUser</saml:NameID>
178            </saml:Subject>
179            <saml:Conditions NotBefore="%(notBefore)s" NotOnOrAfter="%(notOnOrAfter)s" />
180            <saml:AttributeStatement>
181               <saml:Attribute FriendlyName="FirstName" Name="urn:esg:first:name" NameFormat="http://www.w3.org/2001/XMLSchema#string">
182                  <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Test</saml:AttributeValue>
183               </saml:Attribute>
184               <saml:Attribute FriendlyName="LastName" Name="urn:esg:last:name" NameFormat="http://www.w3.org/2001/XMLSchema#string">
185                  <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">User</saml:AttributeValue>
186               </saml:Attribute>
187               <saml:Attribute FriendlyName="EmailAddress" Name="urn:esg:first:email:address" NameFormat="http://www.w3.org/2001/XMLSchema#string">
188                  <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">ejn@ucar.edu</saml:AttributeValue>
189               </saml:Attribute>
190               <saml:Attribute FriendlyName="GroupRole" Name="urn:esg:group:role" NameFormat="groupRole">
191                  <saml:AttributeValue>
192                     <esg:groupRole group="CCSM" role="default" xmlns:esg="http://www.esg.org" />
193                  </saml:AttributeValue>
194                  <saml:AttributeValue>
195                     <esg:groupRole group="Dynamical Core" role="default" xmlns:esg="http://www.esg.org" />
196                  </saml:AttributeValue>
197                  <saml:AttributeValue>
198                     <esg:groupRole group="NARCCAP" role="default" xmlns:esg="http://www.esg.org" />
199                  </saml:AttributeValue>
200               </saml:Attribute>
201            </saml:AttributeStatement>
202         </saml:Assertion>
203      </samlp:Response>
204   </SOAP-ENV:Body>
205</SOAP-ENV:Envelope>
206'''
207
208    def __init__(self, *args, **kwargs):
209        wsgiApp = SamlSoapBindingApp()
210        self.app = paste.fixture.TestApp(wsgiApp)
211         
212        BaseTestCase.__init__(self, *args, **kwargs)
213       
214    def test01AttributeQuery(self):
215        attributeQuery = AttributeQuery()
216        attributeQuery.version = SAMLVersion(SAMLVersion.VERSION_20)
217        attributeQuery.id = str(uuid4())
218        attributeQuery.issueInstant = datetime.utcnow()
219       
220        attributeQuery.issuer = Issuer()
221        attributeQuery.issuer.format = Issuer.X509_SUBJECT
222        attributeQuery.issuer.value = \
223                        "/O=NDG/OU=BADC/CN=attributeauthority.badc.rl.ac.uk"
224                       
225                       
226        attributeQuery.subject = Subject() 
227        attributeQuery.subject.nameID = NameID()
228        attributeQuery.subject.nameID.format = EsgSamlNamespaces.NAMEID_FORMAT
229        attributeQuery.subject.nameID.value = \
230                                    "https://openid.localhost/philip.kershaw"
231       
232        # special case handling for 'FirstName' attribute
233        fnAttribute = Attribute()
234        fnAttribute.name = EsgSamlNamespaces.FIRSTNAME_ATTRNAME
235        fnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string"
236        fnAttribute.friendlyName = "FirstName"
237
238        attributeQuery.attributes.append(fnAttribute)
239   
240        # special case handling for 'LastName' attribute
241        lnAttribute = Attribute()
242        lnAttribute.name = EsgSamlNamespaces.LASTNAME_ATTRNAME
243        lnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string"
244        lnAttribute.friendlyName = "LastName"
245
246        attributeQuery.attributes.append(lnAttribute)
247   
248        # special case handling for 'LastName' attribute
249        emailAddressAttribute = Attribute()
250        emailAddressAttribute.name = EsgSamlNamespaces.EMAILADDRESS_ATTRNAME
251        emailAddressAttribute.nameFormat = XMLConstants.XSD_NS+"#"+\
252                                    XSStringAttributeValue.TYPE_LOCAL_NAME
253        emailAddressAttribute.friendlyName = "emailAddress"
254
255        attributeQuery.attributes.append(emailAddressAttribute)                                   
256       
257        elem = AttributeQueryElementTree.toXML(attributeQuery)
258        soapRequest = SOAPEnvelope()
259        soapRequest.create()
260        soapRequest.body.elem.append(elem)
261       
262        request = soapRequest.serialize()
263       
264        header = {
265            'soapAction': "http://www.oasis-open.org/committees/security",
266            'Content-length': str(len(request)),
267            'Content-type': 'text/xml'
268        }
269        response = self.app.post('/attributeauthority', 
270                                 params=request, 
271                                 headers=header, 
272                                 status=200)
273        print("Response status=%d" % response.status)
274
275        soapResponse = SOAPEnvelope()
276       
277        responseStream = StringIO()
278        responseStream.write(response.body)
279        responseStream.seek(0)
280       
281        soapResponse.parse(responseStream)
282       
283        print("Parsed response ...")
284        print(soapResponse.serialize())
285#        print(prettyPrint(soapResponse.elem))
286       
287        response = ResponseElementTree.fromXML(soapResponse.body.elem[0])
288        self.assert_(response.status.statusCode.value==StatusCode.SUCCESS_URI)
289        self.assert_(response.inResponseTo == attributeQuery.id)
290        self.assert_(response.assertions[0].subject.nameID.value == \
291                     attributeQuery.subject.nameID.value)
292     
293    def test02AttributeQueryWithSOAPClient(self):
294           
295        # Thread a separate attribute authority instance
296        self.startSiteAAttributeAuthority()
297         
298        client = UrlLib2SOAPClient()
299       
300        # ElementTree based envelope class
301        client.responseEnvelopeClass = SOAPEnvelope
302       
303        request = UrlLib2SOAPRequest()
304        request.url = 'http://localhost:5000/AttributeAuthority'
305        request.envelope = SOAPEnvelope()
306        request.envelope.create()
307       
308        # Make an attribute query
309        attributeQuery = AttributeQuery()
310        attributeQuery.version = SAMLVersion(SAMLVersion.VERSION_20)
311        attributeQuery.id = str(uuid4())
312        attributeQuery.issueInstant = datetime.utcnow()
313       
314        attributeQuery.issuer = Issuer()
315        attributeQuery.issuer.format = Issuer.X509_SUBJECT
316        attributeQuery.issuer.value = \
317                        "/O=NDG/OU=BADC/CN=attributeauthority.badc.rl.ac.uk"
318
319        attributeQuery.subject = Subject() 
320        attributeQuery.subject.nameID = NameID()
321        attributeQuery.subject.nameID.format = EsgSamlNamespaces.NAMEID_FORMAT
322        attributeQuery.subject.nameID.value = \
323                            "https://esg.prototype.ucar.edu/myopenid/testUser"
324       
325        # special case handling for 'FirstName' attribute
326        fnAttribute = Attribute()
327        fnAttribute.name = EsgSamlNamespaces.FIRSTNAME_ATTRNAME
328        fnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string"
329        fnAttribute.friendlyName = "FirstName"
330
331        attributeQuery.attributes.append(fnAttribute)
332   
333        # special case handling for 'LastName' attribute
334        lnAttribute = Attribute()
335        lnAttribute.name = EsgSamlNamespaces.LASTNAME_ATTRNAME
336        lnAttribute.nameFormat = "http://www.w3.org/2001/XMLSchema#string"
337        lnAttribute.friendlyName = "LastName"
338
339        attributeQuery.attributes.append(lnAttribute)
340   
341        # special case handling for 'LastName' attribute
342        emailAddressAttribute = Attribute()
343        emailAddressAttribute.name = EsgSamlNamespaces.EMAILADDRESS_ATTRNAME
344        emailAddressAttribute.nameFormat = XMLConstants.XSD_NS+"#"+\
345                                    XSStringAttributeValue.TYPE_LOCAL_NAME
346        emailAddressAttribute.friendlyName = "emailAddress"
347
348        attributeQuery.attributes.append(emailAddressAttribute)                                   
349       
350        attributeQueryElem = AttributeQueryElementTree.toXML(attributeQuery)
351
352        # Attach query to SOAP body
353        request.envelope.body.elem.append(attributeQueryElem)
354       
355        from M2Crypto.m2urllib2 import HTTPSHandler
356        from urllib2 import URLError
357
358        client.openerDirector.add_handler(HTTPSHandler())
359        try:
360            response = client.send(request)
361        except URLError, e:
362            self.fail("Error calling Attribute Service")
363       
364        print("Response from server:\n\n%s" % response.envelope.serialize())
365       
366        if len(response.envelope.body.elem) != 1:
367            self.fail("Expecting single child element is SOAP body")
368           
369        if QName.getLocalPart(response.envelope.body.elem[0].tag)!='Response':
370            self.fail('Expecting "Response" element in SOAP body')
371           
372        toSAMLTypeMap = [XSGroupRoleAttributeValueElementTree.factoryMatchFunc]
373        response = ResponseElementTree.fromXML(response.envelope.body.elem[0],
374                                            customToSAMLTypeMap=toSAMLTypeMap)
375        self.assert_(response)
376       
377    def test03ParseResponse(self):
378        response = \
379'''<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
380   <SOAP-ENV:Body>
381      <samlp:Response ID="05680cb2-4973-443d-9d31-7bc99bea87c1" InResponseTo="e3183380-ae82-4285-8827-8c40613842de" IssueInstant="2009-08-17T12:28:37.325Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
382         <saml:Issuer Format="urn:esg:issuer" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">ESG-NCAR</saml:Issuer>
383         <samlp:Status>
384            <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
385         </samlp:Status>
386         <saml:Assertion ID="192c67d9-f9cd-457a-9242-999e7b943166" IssueInstant="2009-08-17T12:28:37.347Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
387            <saml:Issuer Format="urn:esg:issuer">ESG-NCAR</saml:Issuer>
388            <saml:Subject>
389               <saml:NameID Format="urn:esg:openid">https://esg.prototype.ucar.edu/myopenid/testUser</saml:NameID>
390            </saml:Subject>
391            <saml:Conditions NotBefore="2009-08-17T12:28:37.347Z" NotOnOrAfter="2009-08-18T12:28:37.347Z" />
392            <saml:AttributeStatement>
393               <saml:Attribute FriendlyName="FirstName" Name="urn:esg:first:name" NameFormat="http://www.w3.org/2001/XMLSchema#string">
394                  <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Test</saml:AttributeValue>
395               </saml:Attribute>
396               <saml:Attribute FriendlyName="LastName" Name="urn:esg:last:name" NameFormat="http://www.w3.org/2001/XMLSchema#string">
397                  <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">User</saml:AttributeValue>
398               </saml:Attribute>
399               <saml:Attribute FriendlyName="EmailAddress" Name="urn:esg:first:email:address" NameFormat="http://www.w3.org/2001/XMLSchema#string">
400                  <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">ejn@ucar.edu</saml:AttributeValue>
401               </saml:Attribute>
402               <saml:Attribute FriendlyName="GroupRole" Name="urn:esg:group:role" NameFormat="groupRole">
403                  <saml:AttributeValue>
404                     <esg:groupRole group="CCSM" role="default" xmlns:esg="http://www.esg.org" />
405                  </saml:AttributeValue>
406                  <saml:AttributeValue>
407                     <esg:groupRole group="Dynamical Core" role="default" xmlns:esg="http://www.esg.org" />
408                  </saml:AttributeValue>
409                  <saml:AttributeValue>
410                     <esg:groupRole group="NARCCAP" role="default" xmlns:esg="http://www.esg.org" />
411                  </saml:AttributeValue>
412               </saml:Attribute>
413            </saml:AttributeStatement>
414         </saml:Assertion>
415      </samlp:Response>
416   </SOAP-ENV:Body>
417</SOAP-ENV:Envelope>'''
418       
419        soapResponse = SOAPEnvelope()
420       
421        responseStream = StringIO()
422        responseStream.write(response)
423        responseStream.seek(0)
424       
425        soapResponse.parse(responseStream)
426       
427        print("Parsed response ...")
428        print(soapResponse.serialize())
429       
430        toSAMLTypeMap = [XSGroupRoleAttributeValueElementTree.factoryMatchFunc]
431        response = ResponseElementTree.fromXML(soapResponse.body.elem[0],
432                                            customToSAMLTypeMap=toSAMLTypeMap)
433        self.assert_(response)
434
435    def _parseResponse(self, responseStr):
436        """Helper to parse a response from a string"""
437        soapResponse = SOAPEnvelope()
438       
439        responseStream = StringIO()
440        responseStream.write(responseStr)
441        responseStream.seek(0)
442       
443        soapResponse.parse(responseStream)
444       
445        print("Parsed response ...")
446        print(soapResponse.serialize())
447       
448        toSAMLTypeMap = [XSGroupRoleAttributeValueElementTree.factoryMatchFunc]
449        response = ResponseElementTree.fromXML(soapResponse.body.elem[0],
450                                            customToSAMLTypeMap=toSAMLTypeMap)
451        return response
452       
453    def test03ParseResponse(self):
454        utcNow = datetime.utcnow()
455        respDict = {
456            'issueInstant': SAMLDateTime.toString(utcNow),
457            'assertionIssueInstant': SAMLDateTime.toString(utcNow),
458            'notBefore': SAMLDateTime.toString(utcNow),
459            'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta(
460                                                            seconds=60*60*8))
461        }
462        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \
463                                                                        respDict
464        response = self._parseResponse(responseStr)
465        self.assert_(response)
466
467    def test04AssertionConditionExpired(self):
468        # issued 9 hours ago
469        issueInstant = datetime.utcnow() - timedelta(seconds=60*60*9)
470        respDict = {
471            'issueInstant': SAMLDateTime.toString(issueInstant),
472            'assertionIssueInstant': SAMLDateTime.toString(issueInstant),
473            'notBefore': SAMLDateTime.toString(issueInstant),
474            # It lasts for 8 hours so it's expired by one hour
475            'notOnOrAfter': SAMLDateTime.toString(issueInstant + timedelta(
476                                                            seconds=60*60*8))
477        }
478        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \
479                                                                    respDict
480        response = self._parseResponse(responseStr)
481        binding = SubjectQuerySOAPBinding()
482        try:
483            binding._verifyTimeConditions(response)
484            self.fail("Expecting not on or after timestamp error")
485        except AssertionConditionNotOnOrAfterInvalid, e:
486            print("PASSED: %s" % e)
487
488    def test05ResponseIssueInstantInvalid(self):
489        utcNow = datetime.utcnow()
490        respDict = {
491            'issueInstant': SAMLDateTime.toString(utcNow + timedelta(
492                                                                    seconds=1)),
493            'assertionIssueInstant': SAMLDateTime.toString(utcNow),
494            'notBefore': SAMLDateTime.toString(utcNow),
495            'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta(
496                                                            seconds=60*60*8))
497        }
498        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \
499                                                                    respDict
500        response = self._parseResponse(responseStr)
501        binding = SubjectQuerySOAPBinding()
502        try:
503            binding._verifyTimeConditions(response)
504            self.fail("Expecting issue instant timestamp error")
505        except ResponseIssueInstantInvalid, e:
506            print("PASSED: %s" % e)
507
508    def test06NotBeforeConditionInvalid(self):
509        utcNow = datetime.utcnow()
510        respDict = {
511            'issueInstant': SAMLDateTime.toString(utcNow),
512            'assertionIssueInstant': SAMLDateTime.toString(utcNow),
513            'notBefore': SAMLDateTime.toString(utcNow + timedelta(seconds=1)),
514            'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta(
515                                                            seconds=60*60*8))
516        }
517        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \
518                                                                    respDict
519        response = self._parseResponse(responseStr)
520        binding = SubjectQuerySOAPBinding()
521        try:
522            binding._verifyTimeConditions(response)
523            self.fail("Expecting issue instant timestamp error")
524        except AssertionConditionNotBeforeInvalid, e:
525            print("PASSED: %s" % e)
526
527    def test07AssertionIssueInstantInvalid(self):
528        utcNow = datetime.utcnow()
529        respDict = {
530            'issueInstant': SAMLDateTime.toString(utcNow),
531            'assertionIssueInstant': SAMLDateTime.toString(utcNow + timedelta(
532                                                                    seconds=1)),
533            'notBefore': SAMLDateTime.toString(utcNow),
534            'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta(
535                                                            seconds=60*60*8))
536        }
537        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \
538                                                                    respDict
539        response = self._parseResponse(responseStr)
540        binding = SubjectQuerySOAPBinding()
541        try:
542            binding._verifyTimeConditions(response)
543            self.fail("Expecting issue instant timestamp error")
544        except AssertionIssueInstantInvalid, e:
545            print("PASSED: %s" % e)
546
547    def test07ClockSkewCorrectedAssertionIssueInstantInvalid(self):
548        utcNow = datetime.utcnow()
549        respDict = {
550            'issueInstant': SAMLDateTime.toString(utcNow),
551            'assertionIssueInstant': SAMLDateTime.toString(utcNow + timedelta(
552                                                                    seconds=1)),
553            'notBefore': SAMLDateTime.toString(utcNow),
554            'notOnOrAfter': SAMLDateTime.toString(utcNow + timedelta(
555                                                            seconds=60*60*8))
556        }
557        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \
558                                                                    respDict
559        response = self._parseResponse(responseStr)
560        binding = SubjectQuerySOAPBinding()
561       
562        # Set a skew to correct the error
563        binding.clockSkewTolerance = 1
564       
565        try:
566            binding._verifyTimeConditions(response)
567        except AssertionIssueInstantInvalid, e:
568            self.fail("issue instant timestamp error should be corrected for")
569
570    def test08ClockSkewCorrectedAssertionConditionExpired(self):
571        # Issued 9 hours ago
572        issueInstant = datetime.utcnow() - timedelta(seconds=60*60*9)
573        respDict = {
574            'issueInstant': SAMLDateTime.toString(issueInstant),
575            'assertionIssueInstant': SAMLDateTime.toString(issueInstant),
576            'notBefore': SAMLDateTime.toString(issueInstant),
577            # Assertion lasts 8 hours so it has expired by one hour
578            'notOnOrAfter': SAMLDateTime.toString(issueInstant + timedelta(
579                                                            seconds=60*60*8))
580        }
581        responseStr = SamlAttributeAuthorityInterfaceTestCase.RESPONSE % \
582                                                                    respDict
583        response = self._parseResponse(responseStr)
584        binding = SubjectQuerySOAPBinding()
585       
586        # Set a skew of over one hour to correct for the assertion expiry
587        binding.clockSkewTolerance = 60*60 + 3
588       
589        try:
590            binding._verifyTimeConditions(response)
591           
592        except AssertionConditionNotOnOrAfterInvalid, e:
593            self.fail("Not on or after timestamp error should be corrected for")
594           
595           
596if __name__ == "__main__":
597    unittest.main()       
598
Note: See TracBrowser for help on using the repository browser.