source: TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/credentialwallet/test_credentialwallet.py @ 7077

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/python/ndg_security_test/ndg/security/test/unit/credentialwallet/test_credentialwallet.py@7077
Revision 7077, 7.9 KB checked in by pjkersha, 11 years ago (diff)
  • Property svn:keywords set to Id
Line 
1#!/usr/bin/env python
2"""Unit tests for Credential Wallet class
3
4NERC DataGrid Project
5"""
6__author__ = "P J Kershaw"
7__date__ = "03/10/08"
8__copyright__ = "(C) 2009 Science and Technology Facilities Council"
9__license__ = "BSD - see LICENSE file in top-level directory"
10__contact__ = "Philip.Kershaw@stfc.ac.uk"
11__revision__ = '$Id$'
12import logging
13logging.basicConfig(level=logging.DEBUG)
14
15import unittest
16import os
17
18from string import Template
19from cStringIO import StringIO
20import cPickle as pickle
21
22from elementtree import ElementTree
23
24from time import sleep
25from datetime import datetime, timedelta
26
27from ndg.saml.utils import SAMLDateTime
28from ndg.saml.xml.etree import AssertionElementTree
29
30from ndg.security.test.unit import BaseTestCase
31from ndg.security.common.utils.etree import prettyPrint
32from ndg.security.common.credentialwallet import SAMLCredentialWallet
33
34
35class SAMLCredentialWalletTestCase(BaseTestCase):
36    THIS_DIR = os.path.dirname(__file__)
37    CONFIG_FILENAME = 'test_samlcredentialwallet.cfg'
38    CONFIG_FILEPATH = os.path.join(THIS_DIR, CONFIG_FILENAME)
39    PICKLE_FILENAME = 'SAMLCredentialWalletPickle.dat'
40    PICKLE_FILEPATH = os.path.join(THIS_DIR, PICKLE_FILENAME)
41   
42    ASSERTION_STR = (
43"""<saml:Assertion ID="192c67d9-f9cd-457a-9242-999e7b943166" IssueInstant="$timeNow" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
44   <saml:Issuer Format="urn:esg:issuer">$issuerName</saml:Issuer>
45   <saml:Subject>
46      <saml:NameID Format="urn:esg:openid">https://esg.prototype.ucar.edu/myopenid/testUser</saml:NameID>
47   </saml:Subject>
48   <saml:Conditions NotBefore="$timeNow" NotOnOrAfter="$timeExpires" />
49   <saml:AttributeStatement>
50      <saml:Attribute FriendlyName="FirstName" Name="urn:esg:first:name" NameFormat="http://www.w3.org/2001/XMLSchema#string">
51         <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Test</saml:AttributeValue>
52      </saml:Attribute>
53      <saml:Attribute FriendlyName="LastName" Name="urn:esg:last:name" NameFormat="http://www.w3.org/2001/XMLSchema#string">
54         <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">User</saml:AttributeValue>
55      </saml:Attribute>
56      <saml:Attribute FriendlyName="EmailAddress" Name="urn:esg:first:email:address" NameFormat="http://www.w3.org/2001/XMLSchema#string">
57         <saml:AttributeValue xsi:type="xs:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">test@sitea.ac.uk</saml:AttributeValue>
58      </saml:Attribute>
59   </saml:AttributeStatement>
60</saml:Assertion>
61"""
62    )
63   
64    def __init__(self, *arg, **kw):
65        super(SAMLCredentialWalletTestCase, self).__init__(*arg, **kw)
66       
67    def setUp(self):
68        self.assertion = self._createAssertion()
69       
70    def _createAssertion(self, timeNow=None, validityDuration=60*60*8,
71                         issuerName=BaseTestCase.SITEA_SAML_ISSUER_NAME):
72        if timeNow is None:
73            timeNow = datetime.utcnow()
74           
75        timeExpires = timeNow + timedelta(seconds=validityDuration)
76        assertionStr = Template(
77            SAMLCredentialWalletTestCase.ASSERTION_STR).substitute(
78                dict(
79                 issuerName=issuerName,
80                 timeNow=SAMLDateTime.toString(timeNow), 
81                 timeExpires=SAMLDateTime.toString(timeExpires)
82                )
83            )
84
85        assertionStream = StringIO()
86        assertionStream.write(assertionStr)
87        assertionStream.seek(0)
88        assertionElem = ElementTree.parse(assertionStream).getroot()
89        return AssertionElementTree.fromXML(assertionElem)
90
91    def _addCredential(self):
92        wallet = SAMLCredentialWallet()   
93        wallet.addCredential(
94            self.assertion, 
95            attributeAuthorityURI=\
96                SAMLCredentialWalletTestCase.SITEA_ATTRIBUTEAUTHORITY_SAML_URI)
97        return wallet
98   
99    def test01AddCredential(self):
100        wallet = self._addCredential()
101       
102        self.assert_(len(wallet.credentials) == 1)
103        self.assert_(
104            SAMLCredentialWalletTestCase.SITEA_ATTRIBUTEAUTHORITY_SAML_URI in \
105            wallet.credentialsKeyedByURI)
106        self.assert_(SAMLCredentialWalletTestCase.SITEA_SAML_ISSUER_NAME in \
107                     wallet.credentials)
108       
109        assertion = wallet.credentials[
110            SAMLCredentialWalletTestCase.SITEA_SAML_ISSUER_NAME
111        ].credential
112       
113        print("SAML Assertion:\n%s" % 
114              prettyPrint(AssertionElementTree.toXML(assertion)))
115   
116    def test02VerifyCredential(self):
117        wallet = SAMLCredentialWallet()
118        self.assert_(wallet.isValidCredential(self.assertion))
119       
120        expiredAssertion = self._createAssertion(
121                                timeNow=datetime.utcnow() - timedelta(hours=24))
122                               
123        self.assert_(not wallet.isValidCredential(expiredAssertion))
124       
125        futureAssertion = self._createAssertion(
126                                timeNow=datetime.utcnow() + timedelta(hours=24))
127
128        self.assert_(not wallet.isValidCredential(futureAssertion))
129       
130    def test03AuditCredential(self):
131        # Add a short lived credential and ensure it's removed when an audit
132        # is carried to prune expired credentials
133        shortExpiryAssertion = self._createAssertion(validityDuration=1)
134        wallet = SAMLCredentialWallet()
135        wallet.addCredential(shortExpiryAssertion)
136       
137        self.assert_(len(wallet.credentials) == 1)
138        sleep(2)
139        wallet.audit()
140        self.assert_(len(wallet.credentials) == 0)
141
142    def test04ClockSkewTolerance(self):
143        # Add a short lived credential but with the wallet set to allow for
144        # a clock skew of
145        shortExpiryAssertion = self._createAssertion(validityDuration=1)
146        wallet = SAMLCredentialWallet()
147       
148        # Set a tolerance of five seconds
149        wallet.clockSkewTolerance = 5.*60*60
150        wallet.addCredential(shortExpiryAssertion)
151       
152        self.assert_(len(wallet.credentials) == 1)
153        sleep(2)
154        wallet.audit()
155        self.assert_(len(wallet.credentials) == 1)
156       
157    def test05ReplaceCredential(self):
158        # Replace an existing credential from a given institution with a more
159        # up to date one
160        wallet = self._addCredential()
161        self.assert_(len(wallet.credentials) == 1)
162       
163        newAssertion = self._createAssertion() 
164
165        wallet.addCredential(newAssertion)
166        self.assert_(len(wallet.credentials) == 1)
167        self.assert_(newAssertion.conditions.notOnOrAfter == \
168                     wallet.credentials[
169                        SAMLCredentialWalletTestCase.SITEA_SAML_ISSUER_NAME
170                    ].credential.conditions.notOnOrAfter)
171       
172    def test06CredentialsFromSeparateSites(self):
173        wallet = self._addCredential()
174        wallet.addCredential(self._createAssertion(issuerName="MySite"))
175        self.assert_(len(wallet.credentials) == 2)
176
177    def test07Pickle(self):
178        wallet = self._addCredential()
179        outFile = open(SAMLCredentialWalletTestCase.PICKLE_FILEPATH, 'w')
180        pickle.dump(wallet, outFile)
181        outFile.close()
182       
183        inFile = open(SAMLCredentialWalletTestCase.PICKLE_FILEPATH)
184        unpickledWallet = pickle.load(inFile)
185        self.assert_(unpickledWallet.credentialsKeyedByURI.get(
186            SAMLCredentialWalletTestCase.SITEA_ATTRIBUTEAUTHORITY_SAML_URI))
187       
188        self.assert_(unpickledWallet.credentials.items()[0][1].issuerName == \
189                     BaseTestCase.SITEA_SAML_ISSUER_NAME)
190
191    def test08CreateFromConfig(self):
192        wallet = SAMLCredentialWallet.fromConfig(
193                                SAMLCredentialWalletTestCase.CONFIG_FILEPATH)
194        self.assert_(wallet.clockSkewTolerance == timedelta(seconds=0.01))
195        self.assert_(wallet.userId == 'https://openid.localhost/philip.kershaw')
196       
197if __name__ == "__main__":
198    unittest.main()       
Note: See TracBrowser for help on using the repository browser.