source: TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/saml/test_samlinterface.py @ 7155

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/saml/test_samlinterface.py@7155
Revision 7155, 27.7 KB checked in by pjkersha, 9 years ago (diff)

Incomplete - task 2: XACML-Security Integration

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