2
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3
# See LICENSE for details.
7
Tests for twisted.cred.
11
from twisted.trial import unittest
13
from twisted.internet import app
14
from twisted.cred import authorizer, identity, perspective, service, util
18
"A strange object which shouldn't rightly be accepted by anything."
20
def __init__(self, s=None):
22
self.__setattr__ = self.x__setattr__
24
def x__setattr__(self, key, value):
25
raise TypeError, "I am read-only."
28
s = "<ForeignObject at %s: %s>" % (id(self), self.desc)
33
'I do not have a meaningful string representation'\
34
'like "%s".' % (self.desc,)
37
raise TypeError, "unhashable type"
41
AppForServiceTest = app.Application
43
class OldCredTestCase(unittest.TestCase):
45
warnings.filterwarnings('ignore', 'cred|authorizers|identities', DeprecationWarning)
47
def tearDownClass(self):
48
warnings.filterwarnings('default', 'cred|authorizers|identities', DeprecationWarning)
50
class ServiceTestCase(OldCredTestCase):
51
App = AppForServiceTest
54
self.service = service.Service("test service", authorizer=authorizer.Authorizer())
56
def testConstruction(self):
57
appl = self.App("test app for service-test")
58
auth = authorizer.Authorizer()
59
parent = app.MultiService("test")
60
service.Service("test service")
61
service.Service("test service", authorizer=auth)
62
service.Service("test service", parent)
65
parent = app.MultiService("test")
66
auth = authorizer.Authorizer(parent)
67
s = service.Service("test service", parent, authorizer=auth)
68
self.assertEqual(s.authorizer.getServiceNamed(s.getServiceName()),
70
parent2 = app.MultiService("test")
71
s.disownServiceParent()
72
s.setServiceParent(parent2)
73
self.assertEqual(s.authorizer.getServiceNamed(s.getServiceName()),
77
def testConstruction_serviceName(self):
78
"""serviceName is frequently used as a key, thus it is expected
81
self.assertRaises(TypeError, service.Service,
82
ForeignObject("Not a Name"))
84
def testsetServiceParent(self):
85
parent = app.MultiService("test")
86
self.service.setServiceParent(parent)
87
self.assert_(self.service.serviceParent is parent)
89
## def testsetApplication_invalid(self):
90
## "setApplication should not accept bogus argument."
92
## self.assertRaises(TypeError, self.service.setApplication,
93
## ForeignObject("Not an Application"))
95
## def testsetApplication_again(self):
96
## "setApplication should bail if already set."
98
## app1 = self.App("test app for service-test")
99
## app2 = self.App("another app?")
100
## self.service.setApplication(app1)
101
## self.assertRaises(RuntimeError, self.service.setApplication,
104
def testgetPerspective(self):
105
self.pname = pname = "perspective for service-test"
106
self.p = p = perspective.Perspective(pname)
107
self.service.addPerspective(p)
108
d = self.service.getPerspectiveRequest(pname)
109
d.addCallback(self._checkPerspective)
111
def _checkPerspective(self, q):
112
self.assertEquals(self.p, q)
113
self.assertEquals(self.pname, q.getPerspectiveName())
117
def testGetSetPerspetiveSanity(self):
119
pname = "perspective for service-test"
120
p = perspective.Perspective(pname)
121
self.service.addPerspective(p)
122
q = self.service.getPerspectiveNamed(pname)
123
self.assertEqual(pname, q.getPerspectiveName())
124
self.assertEqual(p,q)
126
def testaddPerspective_invalid(self):
127
self.assertRaises(TypeError, self.service.addPerspective,
128
ForeignObject("Not a Perspective"))
130
def testgetPerspectiveNamed_invalid(self):
132
self.assertRaises(KeyError, self.service.getPerspectiveNamed,
133
"NoSuchPerspectiveNameAsThis")
135
def testgetServiceName(self):
136
self.assert_(self.service.getServiceName())
138
def testgetServiceName_hashable(self):
140
d[self.service.getServiceName()] = "value keyed to serviceName"
142
def testgetServiceType(self):
143
self.assert_(isinstance(self.service.getServiceType(),
145
"ServiceType claimed to be a string, but isn't now.")
150
AppForPerspectiveTest = app.Application
151
ServiceForPerspectiveTest = service.Service
152
IdentityForPerspectiveTest = identity.Identity
154
class PerspectiveTestCase(OldCredTestCase):
155
App = AppForPerspectiveTest
156
Service = ServiceForPerspectiveTest
157
def Identity(self, n):
158
return self.auth.createIdentity(n)
162
self.app = self.App("app for perspective-test")
163
self.auth = authorizer.DefaultAuthorizer()
164
self.service = self.Service("service for perspective-test",
165
authorizer=self.auth)
166
self.perspective = perspective.Perspective("test perspective")
167
self.perspective.setService(self.service)
169
def testConstruction(self):
170
perspective.Perspective("test perspective")
171
perspective.Perspective("test perspective", "testIdentityName")
173
def testConstruction_invalidPerspectiveName(self):
174
self.assertRaises(TypeError, perspective.Perspective,
175
ForeignObject("Not a perspectiveName"),
178
def testConstruction_invalidService(self):
179
self.assertRaises(TypeError, perspective.Perspective,
181
ForeignObject("Not a Service"))
183
def testConstruction_invalidIdentityName(self):
184
self.assertRaises(TypeError, perspective.Perspective,
185
"test perspective", self.service,
186
ForeignObject("Not an idenityName"))
188
def testsetIdentityName(self):
189
self.perspective.setIdentityName("saneIdentityName")
190
self.assertEqual(self.perspective.identityName,
193
def testsetIdentityName_invalid(self):
194
self.assertRaises(TypeError,
195
self.perspective.setIdentityName,
196
ForeignObject("unusable identityName"))
198
def testsetIdentity(self):
199
i = self.Identity("id test name")
200
self.perspective.setIdentity(i)
201
self.assertEqual(self.perspective.identityName, "id test name")
203
def test_identityWithNoPassword(self):
204
i = self.Identity("id test name")
206
pwrq = i.verifyPassword("foo", "bar")
207
pwrq.addErrback(self._identityWithNoPassword_fail)
209
def _identityWithNoPassword_fail(self, msg):
210
# "Identity with no password did not authenticate."
213
def test_identityWithNoPassword_plain(self):
214
i = self.Identity("id test name")
215
pwrq = i.verifyPlainPassword("foo")
216
pwrq.addErrback(self._identityWithNoPassword_plain_fail)
218
def _identityWithNoPassword_plain_fail(self, msg):
219
# "Identity with no password did not authenticate (plaintext): %s"
222
def testsetIdentity_invalid(self):
223
self.assertRaises(TypeError,
224
self.perspective.setIdentity,
225
ForeignObject("not an Identity"))
227
def testmakeIdentity(self):
228
self.ident = ident = self.perspective.makeIdentity("password")
229
# simple password verification
230
pwrq = ident.verifyPlainPassword("password")
231
pwrq.addCallbacks(self._testmakeIdentity_1, self._testmakeIdentity_1fail)
233
def _testmakeIdentity_1fail(self, msg):
235
self.fail("Identity did not verify with plain password: %s" % msg)
236
except self.failureException, e:
237
self.error = sys.exc_info()
240
def _testmakeIdentity_1(self, msg):
241
# complex password verification
243
challenge = ident.challenge()
244
hashedPassword = util.respond(challenge, "password")
245
pwrq = ident.verifyPassword(challenge, hashedPassword)
246
pwrq.addCallback(self._testmakeIdentity_2)
247
pwrq.addErrback(self._testmakeIdentity_2fail)
249
def _testmakeIdentity_2fail(self, msg):
251
self.fail("Identity did not verify with hashed password: %s" % msg)
252
except self.failureException, e:
253
self.error = sys.exc_info()
256
def _testmakeIdentity_2(self, msg):
257
d = self.perspective.getIdentityRequest()
258
d.addCallback(self._gotIdentity)
260
def _gotIdentity(self, ident):
261
self.assertEquals(self.ident, ident)
264
def testmakeIdentity_invalid(self):
265
self.assertRaises(TypeError, self.perspective.makeIdentity,
266
ForeignObject("Illegal Passkey"))
268
def testgetService(self):
269
s = self.perspective.getService()
270
self.assert_(s is self.service)
272
class FunctionsTestCase(OldCredTestCase):
273
def test_challenge(self):
274
self.assert_(identity.challenge())
276
AppForIdentityTest = AppForPerspectiveTest
278
ServiceForIdentityTest = ServiceForPerspectiveTest
280
class PerspectiveForIdentityTest(perspective.Perspective):
281
def __init__(self, n, service):
282
perspective.Perspective.__init__(self, n)
283
self.setService(service)
285
class IdentityTestCase(OldCredTestCase):
286
App = AppForIdentityTest
287
Service = ServiceForIdentityTest
288
Perspective = PerspectiveForIdentityTest
291
self.auth = authorizer.DefaultAuthorizer()
292
self.ident = identity.Identity("test identity", authorizer=self.auth)
294
def testConstruction(self):
295
identity.Identity("test name", authorizer=self.auth)
297
def test_addKeyByString(self):
298
self.ident.addKeyByString("one", "two")
299
self.assert_(("one", "two") in self.ident.getAllKeys())
301
def test_addKeyForPerspective(self):
302
service = self.Service("one", authorizer=self.auth)
303
perspective = self.Perspective("two", service)
305
self.ident.addKeyForPerspective(perspective)
306
self.assert_(("one", "two") in self.ident.getAllKeys())
308
def test_getAllKeys(self):
309
self.assert_(len(self.ident.getAllKeys()) == 0)
311
service = self.Service("one", authorizer=self.auth)
313
for n in ("p1","p2","p3"):
314
perspective = self.Perspective(n, service)
315
self.ident.addKeyForPerspective(perspective)
317
keys = self.ident.getAllKeys()
319
self.assertEqual(len(keys), 3)
321
for n in ("p1","p2","p3"):
322
self.assert_(("one", n) in keys)
324
def test_removeKey(self):
325
self.ident.addKeyByString("one", "two")
326
self.ident.removeKey("one", "two")
327
self.assert_(len(self.ident.getAllKeys()) == 0)
329
def test_removeKey_invalid(self):
330
self.assertRaises(KeyError, self.ident.removeKey,
333
def test_setPassword_invalid(self):
334
self.assertRaises(TypeError, self.ident.setPassword,
335
ForeignObject("not a valid passphrase"))
337
def test_verifyPassword(self):
338
self.ident.setPassword("passphrase")
340
self._test_verifyPassword_worked = 0
341
pwrq = self.ident.verifyPassword("wr", "ong")
342
pwrq.addCallback(self._test_verifyPassword_false_pos)
343
pwrq.addErrback(self._test_verifyPassword_correct_neg)
344
# the following test actually needs the identity in testing
345
# to have sync password checking..
346
self.assert_(self._test_verifyPassword_worked)
348
def _test_verifyPassword_false_pos(self, msg):
349
self.fail("Identity accepted invalid hashed password")
351
def _test_verifyPassword_correct_neg(self, msg):
352
self.assert_(self._test_verifyPassword_worked==0)
353
self._test_verifyPassword_worked = 1
355
def test_verifyPlainPassword(self):
356
self.ident.setPassword("passphrase")
358
self._test_verifyPlainPassword_worked = 0
360
pwrq1 = self.ident.verifyPlainPassword("passphrase")
361
pwrq1.addErrback(self._test_verifyPlainPassword_fail)
362
pwrq1.addCallback(self._test_verifyPlainPassword_ok)
363
self.assert_(self._test_verifyPlainPassword_worked==1)
365
pwrq2 = self.ident.verifyPlainPassword("wrongphrase")
366
pwrq2.addCallback(self._test_verifyPlainPassword_false_pos)
367
pwrq2.addErrback(self._test_verifyPlainPassword_correct_neg)
368
self.assert_(self._test_verifyPlainPassword_worked==2)
370
def _test_verifyPlainPassword_fail(self, msg):
371
self.fail("Identity did not verify with plain password")
373
def _test_verifyPlainPassword_ok(self, msg):
374
self.assert_(self._test_verifyPlainPassword_worked==0)
375
self._test_verifyPlainPassword_worked = 1
377
def _test_verifyPlainPassword_false_pos(self, msg):
378
self.fail("Identity accepted invalid plain password")
380
def _test_verifyPlainPassword_correct_neg(self, msg):
381
self.assert_(self._test_verifyPlainPassword_worked==1)
382
self._test_verifyPlainPassword_worked = 2
386
class AuthorizerTestCase(OldCredTestCase):
387
"""TestCase for authorizer.DefaultAuthorizer."""
390
self.auth = authorizer.DefaultAuthorizer()
393
raise RuntimeError, e
395
def _gotIdentity(self, i):
396
self.assertEquals(self.ident, i)
399
def test_addIdent(self):
400
i = identity.Identity("user", self.auth)
403
self.auth.addIdentity(i)
404
self.assertRaises(KeyError, self.auth.addIdentity, i)
405
self.assert_(self.auth.identities.has_key("user"))
407
# get request for identity
409
d = self.auth.getIdentityRequest("user")
410
d.addCallback(self._gotIdentity).addErrback(self._error)
413
self.auth.removeIdentity("user")
414
self.assert_(not self.auth.identities.has_key("user"))
415
self.assertRaises(KeyError, self.auth.removeIdentity, "user")
416
self.assertRaises(KeyError, self.auth.removeIdentity, "otheruser")
418
def _gotNoUser(self, err):
421
def test_nonExistentIdent(self):
422
d = self.auth.getIdentityRequest("nosuchuser")
423
d.addCallback(self._error).addErrback(self._gotNoUser)