1
# -*- test-case-name: twisted.test.test_sip -*-
2
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
3
# See LICENSE for details.
6
"""Session Initialization Protocol tests."""
8
from twisted.trial import unittest, util
9
from twisted.protocols import sip
10
from twisted.internet import defer, reactor, utils
11
from twisted.python.versions import Version
13
from twisted.test import proto_helpers
15
from twisted import cred
16
import twisted.cred.portal
17
import twisted.cred.checkers
19
from zope.interface import implements
22
# request, prefixed by random CRLFs
23
request1 = "\n\r\n\n\r" + """\
24
INVITE sip:foo SIP/2.0
29
abcd""".replace("\n", "\r\n")
31
# request, no content-length
32
request2 = """INVITE sip:foo SIP/2.0
36
1234""".replace("\n", "\r\n")
38
# request, with garbage after
39
request3 = """INVITE sip:foo SIP/2.0
46
lalalal""".replace("\n", "\r\n")
49
request4 = """INVITE sip:foo SIP/2.0
54
INVITE sip:loop SIP/2.0
59
abcdINVITE sip:loop SIP/2.0
64
1234""".replace("\n", "\r\n")
66
# response, no content
67
response1 = """SIP/2.0 200 OK
72
""".replace("\n", "\r\n")
74
# short header version
76
INVITE sip:foo SIP/2.0
81
abcd""".replace("\n", "\r\n")
84
INVITE sip:foo SIP/2.0
85
Via: SIP/2.0/UDP 10.0.0.1:5060;rport
87
""".replace("\n", "\r\n")
90
def requestAvatar(self, avatarId, mind, *interfaces):
91
return sip.IContact, None, lambda: None
93
class MessageParsingTestCase(unittest.TestCase):
96
self.parser = sip.MessagesParser(self.l.append)
98
def feedMessage(self, message):
99
self.parser.dataReceived(message)
100
self.parser.dataDone()
102
def validateMessage(self, m, method, uri, headers, body):
103
"""Validate Requests."""
104
self.assertEquals(m.method, method)
105
self.assertEquals(m.uri.toString(), uri)
106
self.assertEquals(m.headers, headers)
107
self.assertEquals(m.body, body)
108
self.assertEquals(m.finished, 1)
110
def testSimple(self):
112
self.feedMessage(request1)
113
self.assertEquals(len(l), 1)
114
self.validateMessage(
115
l[0], "INVITE", "sip:foo",
116
{"from": ["mo"], "to": ["joe"], "content-length": ["4"]},
119
def testTwoMessages(self):
121
self.feedMessage(request1)
122
self.feedMessage(request2)
123
self.assertEquals(len(l), 2)
124
self.validateMessage(
125
l[0], "INVITE", "sip:foo",
126
{"from": ["mo"], "to": ["joe"], "content-length": ["4"]},
128
self.validateMessage(l[1], "INVITE", "sip:foo",
129
{"from": ["mo"], "to": ["joe"]},
132
def testGarbage(self):
134
self.feedMessage(request3)
135
self.assertEquals(len(l), 1)
136
self.validateMessage(
137
l[0], "INVITE", "sip:foo",
138
{"from": ["mo"], "to": ["joe"], "content-length": ["4"]},
141
def testThreeInOne(self):
143
self.feedMessage(request4)
144
self.assertEquals(len(l), 3)
145
self.validateMessage(
146
l[0], "INVITE", "sip:foo",
147
{"from": ["mo"], "to": ["joe"], "content-length": ["0"]},
149
self.validateMessage(
150
l[1], "INVITE", "sip:loop",
151
{"from": ["foo"], "to": ["bar"], "content-length": ["4"]},
153
self.validateMessage(
154
l[2], "INVITE", "sip:loop",
155
{"from": ["foo"], "to": ["bar"], "content-length": ["4"]},
160
self.feedMessage(request_short)
161
self.assertEquals(len(l), 1)
162
self.validateMessage(
163
l[0], "INVITE", "sip:foo",
164
{"from": ["mo"], "to": ["joe"], "content-length": ["4"]},
167
def testSimpleResponse(self):
169
self.feedMessage(response1)
170
self.assertEquals(len(l), 1)
172
self.assertEquals(m.code, 200)
173
self.assertEquals(m.phrase, "OK")
176
{"from": ["foo"], "to": ["bar"], "content-length": ["0"]})
177
self.assertEquals(m.body, "")
178
self.assertEquals(m.finished, 1)
181
class MessageParsingTestCase2(MessageParsingTestCase):
182
"""Same as base class, but feed data char by char."""
184
def feedMessage(self, message):
186
self.parser.dataReceived(c)
187
self.parser.dataDone()
190
class MakeMessageTestCase(unittest.TestCase):
192
def testRequest(self):
193
r = sip.Request("INVITE", "sip:foo")
194
r.addHeader("foo", "bar")
197
"INVITE sip:foo SIP/2.0\r\nFoo: bar\r\n\r\n")
199
def testResponse(self):
200
r = sip.Response(200, "OK")
201
r.addHeader("foo", "bar")
202
r.addHeader("Content-Length", "4")
203
r.bodyDataReceived("1234")
206
"SIP/2.0 200 OK\r\nFoo: bar\r\nContent-Length: 4\r\n\r\n1234")
208
def testStatusCode(self):
209
r = sip.Response(200)
210
self.assertEquals(r.toString(), "SIP/2.0 200 OK\r\n\r\n")
213
class ViaTestCase(unittest.TestCase):
215
def checkRoundtrip(self, v):
217
self.assertEquals(s, sip.parseViaHeader(s).toString())
219
def testExtraWhitespace(self):
220
v1 = sip.parseViaHeader('SIP/2.0/UDP 192.168.1.1:5060')
221
v2 = sip.parseViaHeader('SIP/2.0/UDP 192.168.1.1:5060')
222
self.assertEquals(v1.transport, v2.transport)
223
self.assertEquals(v1.host, v2.host)
224
self.assertEquals(v1.port, v2.port)
226
def test_complex(self):
228
Test parsing a Via header with one of everything.
230
s = ("SIP/2.0/UDP first.example.com:4000;ttl=16;maddr=224.2.0.1"
231
" ;branch=a7c6a8dlze (Example)")
232
v = sip.parseViaHeader(s)
233
self.assertEquals(v.transport, "UDP")
234
self.assertEquals(v.host, "first.example.com")
235
self.assertEquals(v.port, 4000)
236
self.assertEquals(v.rport, None)
237
self.assertEquals(v.rportValue, None)
238
self.assertEquals(v.rportRequested, False)
239
self.assertEquals(v.ttl, 16)
240
self.assertEquals(v.maddr, "224.2.0.1")
241
self.assertEquals(v.branch, "a7c6a8dlze")
242
self.assertEquals(v.hidden, 0)
243
self.assertEquals(v.toString(),
244
"SIP/2.0/UDP first.example.com:4000"
245
";ttl=16;branch=a7c6a8dlze;maddr=224.2.0.1")
246
self.checkRoundtrip(v)
248
def test_simple(self):
250
Test parsing a simple Via header.
252
s = "SIP/2.0/UDP example.com;hidden"
253
v = sip.parseViaHeader(s)
254
self.assertEquals(v.transport, "UDP")
255
self.assertEquals(v.host, "example.com")
256
self.assertEquals(v.port, 5060)
257
self.assertEquals(v.rport, None)
258
self.assertEquals(v.rportValue, None)
259
self.assertEquals(v.rportRequested, False)
260
self.assertEquals(v.ttl, None)
261
self.assertEquals(v.maddr, None)
262
self.assertEquals(v.branch, None)
263
self.assertEquals(v.hidden, True)
264
self.assertEquals(v.toString(),
265
"SIP/2.0/UDP example.com:5060;hidden")
266
self.checkRoundtrip(v)
268
def testSimpler(self):
269
v = sip.Via("example.com")
270
self.checkRoundtrip(v)
273
def test_deprecatedRPort(self):
275
Setting rport to True is deprecated, but still produces a Via header
276
with the expected properties.
278
v = sip.Via("foo.bar", rport=True)
280
warnings = self.flushWarnings(
281
offendingFunctions=[self.test_deprecatedRPort])
282
self.assertEqual(len(warnings), 1)
284
warnings[0]['message'],
285
'rport=True is deprecated since Twisted 9.0.')
287
warnings[0]['category'],
290
self.assertEqual(v.toString(), "SIP/2.0/UDP foo.bar:5060;rport")
291
self.assertEqual(v.rport, True)
292
self.assertEqual(v.rportRequested, True)
293
self.assertEqual(v.rportValue, None)
296
def test_rport(self):
298
An rport setting of None should insert the parameter with no value.
300
v = sip.Via("foo.bar", rport=None)
301
self.assertEqual(v.toString(), "SIP/2.0/UDP foo.bar:5060;rport")
302
self.assertEqual(v.rportRequested, True)
303
self.assertEqual(v.rportValue, None)
306
def test_rportValue(self):
308
An rport numeric setting should insert the parameter with the number
311
v = sip.Via("foo.bar", rport=1)
312
self.assertEqual(v.toString(), "SIP/2.0/UDP foo.bar:5060;rport=1")
313
self.assertEqual(v.rportRequested, False)
314
self.assertEqual(v.rportValue, 1)
315
self.assertEqual(v.rport, 1)
319
s = "SIP/2.0/UDP 10.0.0.1:5060;received=22.13.1.5;rport=12345"
320
v = sip.parseViaHeader(s)
321
self.assertEquals(v.transport, "UDP")
322
self.assertEquals(v.host, "10.0.0.1")
323
self.assertEquals(v.port, 5060)
324
self.assertEquals(v.received, "22.13.1.5")
325
self.assertEquals(v.rport, 12345)
327
self.assertNotEquals(v.toString().find("rport=12345"), -1)
330
def test_unknownParams(self):
332
Parsing and serializing Via headers with unknown parameters should work.
334
s = "SIP/2.0/UDP example.com:5060;branch=a12345b;bogus;pie=delicious"
335
v = sip.parseViaHeader(s)
336
self.assertEqual(v.toString(), s)
340
class URLTestCase(unittest.TestCase):
342
def testRoundtrip(self):
345
"sip:j.doe:secret@big.com;transport=tcp",
346
"sip:j.doe@big.com?subject=project",
349
self.assertEquals(sip.parseURL(url).toString(), url)
351
def testComplex(self):
352
s = ("sip:user:pass@hosta:123;transport=udp;user=phone;method=foo;"
353
"ttl=12;maddr=1.2.3.4;blah;goo=bar?a=b&c=d")
354
url = sip.parseURL(s)
355
for k, v in [("username", "user"), ("password", "pass"),
356
("host", "hosta"), ("port", 123),
357
("transport", "udp"), ("usertype", "phone"),
358
("method", "foo"), ("ttl", 12),
359
("maddr", "1.2.3.4"), ("other", ["blah", "goo=bar"]),
360
("headers", {"a": "b", "c": "d"})]:
361
self.assertEquals(getattr(url, k), v)
364
class ParseTestCase(unittest.TestCase):
366
def testParseAddress(self):
367
for address, name, urls, params in [
368
('"A. G. Bell" <sip:foo@example.com>',
369
"A. G. Bell", "sip:foo@example.com", {}),
370
("Anon <sip:foo@example.com>", "Anon", "sip:foo@example.com", {}),
371
("sip:foo@example.com", "", "sip:foo@example.com", {}),
372
("<sip:foo@example.com>", "", "sip:foo@example.com", {}),
373
("foo <sip:foo@example.com>;tag=bar;foo=baz", "foo",
374
"sip:foo@example.com", {"tag": "bar", "foo": "baz"}),
376
gname, gurl, gparams = sip.parseAddress(address)
377
self.assertEquals(name, gname)
378
self.assertEquals(gurl.toString(), urls)
379
self.assertEquals(gparams, params)
383
implements(sip.ILocator)
384
def getAddress(self, logicalURL):
385
return defer.succeed(sip.URL("server.com", port=5060))
387
class FailingLocator:
388
implements(sip.ILocator)
389
def getAddress(self, logicalURL):
390
return defer.fail(LookupError())
393
class ProxyTestCase(unittest.TestCase):
396
self.proxy = sip.Proxy("127.0.0.1")
397
self.proxy.locator = DummyLocator()
399
self.proxy.sendMessage = lambda dest, msg: self.sent.append((dest, msg))
401
def testRequestForward(self):
402
r = sip.Request("INVITE", "sip:foo")
403
r.addHeader("via", sip.Via("1.2.3.4").toString())
404
r.addHeader("via", sip.Via("1.2.3.5").toString())
405
r.addHeader("foo", "bar")
406
r.addHeader("to", "<sip:joe@server.com>")
407
r.addHeader("contact", "<sip:joe@1.2.3.5>")
408
self.proxy.datagramReceived(r.toString(), ("1.2.3.4", 5060))
409
self.assertEquals(len(self.sent), 1)
410
dest, m = self.sent[0]
411
self.assertEquals(dest.port, 5060)
412
self.assertEquals(dest.host, "server.com")
413
self.assertEquals(m.uri.toString(), "sip:foo")
414
self.assertEquals(m.method, "INVITE")
415
self.assertEquals(m.headers["via"],
416
["SIP/2.0/UDP 127.0.0.1:5060",
417
"SIP/2.0/UDP 1.2.3.4:5060",
418
"SIP/2.0/UDP 1.2.3.5:5060"])
421
def testReceivedRequestForward(self):
422
r = sip.Request("INVITE", "sip:foo")
423
r.addHeader("via", sip.Via("1.2.3.4").toString())
424
r.addHeader("foo", "bar")
425
r.addHeader("to", "<sip:joe@server.com>")
426
r.addHeader("contact", "<sip:joe@1.2.3.4>")
427
self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060))
428
dest, m = self.sent[0]
429
self.assertEquals(m.headers["via"],
430
["SIP/2.0/UDP 127.0.0.1:5060",
431
"SIP/2.0/UDP 1.2.3.4:5060;received=1.1.1.1"])
434
def testResponseWrongVia(self):
435
# first via must match proxy's address
436
r = sip.Response(200)
437
r.addHeader("via", sip.Via("foo.com").toString())
438
self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060))
439
self.assertEquals(len(self.sent), 0)
441
def testResponseForward(self):
442
r = sip.Response(200)
443
r.addHeader("via", sip.Via("127.0.0.1").toString())
444
r.addHeader("via", sip.Via("client.com", port=1234).toString())
445
self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060))
446
self.assertEquals(len(self.sent), 1)
447
dest, m = self.sent[0]
448
self.assertEquals((dest.host, dest.port), ("client.com", 1234))
449
self.assertEquals(m.code, 200)
450
self.assertEquals(m.headers["via"], ["SIP/2.0/UDP client.com:1234"])
452
def testReceivedResponseForward(self):
453
r = sip.Response(200)
454
r.addHeader("via", sip.Via("127.0.0.1").toString())
457
sip.Via("10.0.0.1", received="client.com").toString())
458
self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060))
459
self.assertEquals(len(self.sent), 1)
460
dest, m = self.sent[0]
461
self.assertEquals((dest.host, dest.port), ("client.com", 5060))
463
def testResponseToUs(self):
464
r = sip.Response(200)
465
r.addHeader("via", sip.Via("127.0.0.1").toString())
467
self.proxy.gotResponse = lambda *a: l.append(a)
468
self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060))
469
self.assertEquals(len(l), 1)
471
self.assertEquals(len(m.headers.get("via", [])), 0)
472
self.assertEquals(m.code, 200)
475
r = sip.Request("INVITE", "sip:foo")
476
r.addHeader("via", sip.Via("1.2.3.4").toString())
477
r.addHeader("via", sip.Via("127.0.0.1").toString())
478
self.proxy.datagramReceived(r.toString(), ("client.com", 5060))
479
self.assertEquals(self.sent, [])
481
def testCantForwardRequest(self):
482
r = sip.Request("INVITE", "sip:foo")
483
r.addHeader("via", sip.Via("1.2.3.4").toString())
484
r.addHeader("to", "<sip:joe@server.com>")
485
self.proxy.locator = FailingLocator()
486
self.proxy.datagramReceived(r.toString(), ("1.2.3.4", 5060))
487
self.assertEquals(len(self.sent), 1)
488
dest, m = self.sent[0]
489
self.assertEquals((dest.host, dest.port), ("1.2.3.4", 5060))
490
self.assertEquals(m.code, 404)
491
self.assertEquals(m.headers["via"], ["SIP/2.0/UDP 1.2.3.4:5060"])
493
def testCantForwardResponse(self):
496
#testCantForwardResponse.skip = "not implemented yet"
499
class RegistrationTestCase(unittest.TestCase):
502
self.proxy = sip.RegisterProxy(host="127.0.0.1")
503
self.registry = sip.InMemoryRegistry("bell.example.com")
504
self.proxy.registry = self.proxy.locator = self.registry
506
self.proxy.sendMessage = lambda dest, msg: self.sent.append((dest, msg))
507
setUp = utils.suppressWarnings(setUp,
508
util.suppress(category=DeprecationWarning,
509
message=r'twisted.protocols.sip.DigestAuthorizer was deprecated'))
512
for d, uri in self.registry.users.values():
517
r = sip.Request("REGISTER", "sip:bell.example.com")
518
r.addHeader("to", "sip:joe@bell.example.com")
519
r.addHeader("contact", "sip:joe@client.com:1234")
520
r.addHeader("via", sip.Via("client.com").toString())
521
self.proxy.datagramReceived(r.toString(), ("client.com", 5060))
523
def unregister(self):
524
r = sip.Request("REGISTER", "sip:bell.example.com")
525
r.addHeader("to", "sip:joe@bell.example.com")
526
r.addHeader("contact", "*")
527
r.addHeader("via", sip.Via("client.com").toString())
528
r.addHeader("expires", "0")
529
self.proxy.datagramReceived(r.toString(), ("client.com", 5060))
531
def testRegister(self):
533
dest, m = self.sent[0]
534
self.assertEquals((dest.host, dest.port), ("client.com", 5060))
535
self.assertEquals(m.code, 200)
536
self.assertEquals(m.headers["via"], ["SIP/2.0/UDP client.com:5060"])
537
self.assertEquals(m.headers["to"], ["sip:joe@bell.example.com"])
538
self.assertEquals(m.headers["contact"], ["sip:joe@client.com:5060"])
540
int(m.headers["expires"][0]) in (3600, 3601, 3599, 3598))
541
self.assertEquals(len(self.registry.users), 1)
542
dc, uri = self.registry.users["joe"]
543
self.assertEquals(uri.toString(), "sip:joe@client.com:5060")
544
d = self.proxy.locator.getAddress(sip.URL(username="joe",
545
host="bell.example.com"))
546
d.addCallback(lambda desturl : (desturl.host, desturl.port))
547
d.addCallback(self.assertEquals, ('client.com', 5060))
550
def testUnregister(self):
553
dest, m = self.sent[1]
554
self.assertEquals((dest.host, dest.port), ("client.com", 5060))
555
self.assertEquals(m.code, 200)
556
self.assertEquals(m.headers["via"], ["SIP/2.0/UDP client.com:5060"])
557
self.assertEquals(m.headers["to"], ["sip:joe@bell.example.com"])
558
self.assertEquals(m.headers["contact"], ["sip:joe@client.com:5060"])
559
self.assertEquals(m.headers["expires"], ["0"])
560
self.assertEquals(self.registry.users, {})
565
p = cred.portal.Portal(r)
566
c = cred.checkers.InMemoryUsernamePasswordDatabaseDontUse()
567
c.addUser('userXname@127.0.0.1', 'passXword')
569
self.proxy.portal = p
571
def testFailedAuthentication(self):
575
self.assertEquals(len(self.registry.users), 0)
576
self.assertEquals(len(self.sent), 1)
577
dest, m = self.sent[0]
578
self.assertEquals(m.code, 401)
581
def test_basicAuthentication(self):
583
Test that registration with basic authentication suceeds.
586
self.proxy.authorizers = self.proxy.authorizers.copy()
587
self.proxy.authorizers['basic'] = sip.BasicAuthorizer()
588
warnings = self.flushWarnings(
589
offendingFunctions=[self.test_basicAuthentication])
590
self.assertEqual(len(warnings), 1)
592
warnings[0]['message'],
593
"twisted.protocols.sip.BasicAuthorizer was deprecated in "
596
warnings[0]['category'],
598
r = sip.Request("REGISTER", "sip:bell.example.com")
599
r.addHeader("to", "sip:joe@bell.example.com")
600
r.addHeader("contact", "sip:joe@client.com:1234")
601
r.addHeader("via", sip.Via("client.com").toString())
602
r.addHeader("authorization",
603
"Basic " + "userXname:passXword".encode('base64'))
604
self.proxy.datagramReceived(r.toString(), ("client.com", 5060))
606
self.assertEquals(len(self.registry.users), 1)
607
self.assertEquals(len(self.sent), 1)
608
dest, m = self.sent[0]
609
self.assertEquals(m.code, 200)
612
def test_failedBasicAuthentication(self):
614
Failed registration with basic authentication results in an
615
unauthorized error response.
618
self.proxy.authorizers = self.proxy.authorizers.copy()
619
self.proxy.authorizers['basic'] = sip.BasicAuthorizer()
620
warnings = self.flushWarnings(
621
offendingFunctions=[self.test_failedBasicAuthentication])
622
self.assertEqual(len(warnings), 1)
624
warnings[0]['message'],
625
"twisted.protocols.sip.BasicAuthorizer was deprecated in "
628
warnings[0]['category'],
630
r = sip.Request("REGISTER", "sip:bell.example.com")
631
r.addHeader("to", "sip:joe@bell.example.com")
632
r.addHeader("contact", "sip:joe@client.com:1234")
633
r.addHeader("via", sip.Via("client.com").toString())
635
"authorization", "Basic " + "userXname:password".encode('base64'))
636
self.proxy.datagramReceived(r.toString(), ("client.com", 5060))
638
self.assertEquals(len(self.registry.users), 0)
639
self.assertEquals(len(self.sent), 1)
640
dest, m = self.sent[0]
641
self.assertEquals(m.code, 401)
644
def testWrongDomainRegister(self):
645
r = sip.Request("REGISTER", "sip:wrong.com")
646
r.addHeader("to", "sip:joe@bell.example.com")
647
r.addHeader("contact", "sip:joe@client.com:1234")
648
r.addHeader("via", sip.Via("client.com").toString())
649
self.proxy.datagramReceived(r.toString(), ("client.com", 5060))
650
self.assertEquals(len(self.sent), 0)
652
def testWrongToDomainRegister(self):
653
r = sip.Request("REGISTER", "sip:bell.example.com")
654
r.addHeader("to", "sip:joe@foo.com")
655
r.addHeader("contact", "sip:joe@client.com:1234")
656
r.addHeader("via", sip.Via("client.com").toString())
657
self.proxy.datagramReceived(r.toString(), ("client.com", 5060))
658
self.assertEquals(len(self.sent), 0)
660
def testWrongDomainLookup(self):
662
url = sip.URL(username="joe", host="foo.com")
663
d = self.proxy.locator.getAddress(url)
664
self.assertFailure(d, LookupError)
667
def testNoContactLookup(self):
669
url = sip.URL(username="jane", host="bell.example.com")
670
d = self.proxy.locator.getAddress(url)
671
self.assertFailure(d, LookupError)
675
class Client(sip.Base):
678
sip.Base.__init__(self)
680
self.deferred = defer.Deferred()
682
def handle_response(self, response, addr):
683
self.received.append(response)
684
self.deferred.callback(self.received)
687
class LiveTest(unittest.TestCase):
690
self.proxy = sip.RegisterProxy(host="127.0.0.1")
691
self.registry = sip.InMemoryRegistry("bell.example.com")
692
self.proxy.registry = self.proxy.locator = self.registry
693
self.serverPort = reactor.listenUDP(
694
0, self.proxy, interface="127.0.0.1")
695
self.client = Client()
696
self.clientPort = reactor.listenUDP(
697
0, self.client, interface="127.0.0.1")
698
self.serverAddress = (self.serverPort.getHost().host,
699
self.serverPort.getHost().port)
700
setUp = utils.suppressWarnings(setUp,
701
util.suppress(category=DeprecationWarning,
702
message=r'twisted.protocols.sip.DigestAuthorizer was deprecated'))
705
for d, uri in self.registry.users.values():
707
d1 = defer.maybeDeferred(self.clientPort.stopListening)
708
d2 = defer.maybeDeferred(self.serverPort.stopListening)
709
return defer.gatherResults([d1, d2])
711
def testRegister(self):
712
p = self.clientPort.getHost().port
713
r = sip.Request("REGISTER", "sip:bell.example.com")
714
r.addHeader("to", "sip:joe@bell.example.com")
715
r.addHeader("contact", "sip:joe@127.0.0.1:%d" % p)
716
r.addHeader("via", sip.Via("127.0.0.1", port=p).toString())
717
self.client.sendMessage(
718
sip.URL(host="127.0.0.1", port=self.serverAddress[1]), r)
719
d = self.client.deferred
721
self.assertEquals(len(received), 1)
723
self.assertEquals(r.code, 200)
727
def test_amoralRPort(self):
729
rport is allowed without a value, apparently because server
730
implementors might be too stupid to check the received port
731
against 5060 and see if they're equal, and because client
732
implementors might be too stupid to bind to port 5060, or set a
733
value on the rport parameter they send if they bind to another
736
p = self.clientPort.getHost().port
737
r = sip.Request("REGISTER", "sip:bell.example.com")
738
r.addHeader("to", "sip:joe@bell.example.com")
739
r.addHeader("contact", "sip:joe@127.0.0.1:%d" % p)
740
r.addHeader("via", sip.Via("127.0.0.1", port=p, rport=True).toString())
741
warnings = self.flushWarnings(
742
offendingFunctions=[self.test_amoralRPort])
743
self.assertEqual(len(warnings), 1)
745
warnings[0]['message'],
746
'rport=True is deprecated since Twisted 9.0.')
748
warnings[0]['category'],
750
self.client.sendMessage(sip.URL(host="127.0.0.1",
751
port=self.serverAddress[1]),
753
d = self.client.deferred
755
self.assertEquals(len(received), 1)
757
self.assertEquals(r.code, 200)
763
registerRequest = """
764
REGISTER sip:intarweb.us SIP/2.0\r
765
Via: SIP/2.0/UDP 192.168.1.100:50609\r
766
From: <sip:exarkun@intarweb.us:50609>\r
767
To: <sip:exarkun@intarweb.us:50609>\r
768
Contact: "exarkun" <sip:exarkun@192.168.1.100:50609>\r
769
Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r
770
CSeq: 9898 REGISTER\r
772
User-Agent: X-Lite build 1061\r
777
challengeResponse = """\
778
SIP/2.0 401 Unauthorized\r
779
Via: SIP/2.0/UDP 192.168.1.100:50609;received=127.0.0.1;rport=5632\r
780
To: <sip:exarkun@intarweb.us:50609>\r
781
From: <sip:exarkun@intarweb.us:50609>\r
782
Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r
783
CSeq: 9898 REGISTER\r
784
WWW-Authenticate: Digest nonce="92956076410767313901322208775",opaque="1674186428",qop-options="auth",algorithm="MD5",realm="intarweb.us"\r
789
REGISTER sip:intarweb.us SIP/2.0\r
790
Via: SIP/2.0/UDP 192.168.1.100:50609\r
791
From: <sip:exarkun@intarweb.us:50609>\r
792
To: <sip:exarkun@intarweb.us:50609>\r
793
Contact: "exarkun" <sip:exarkun@192.168.1.100:50609>\r
794
Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r
795
CSeq: 9899 REGISTER\r
797
Authorization: Digest username="exarkun",realm="intarweb.us",nonce="92956076410767313901322208775",response="4a47980eea31694f997369214292374b",uri="sip:intarweb.us",algorithm=MD5,opaque="1674186428"\r
798
User-Agent: X-Lite build 1061\r
805
Via: SIP/2.0/UDP 192.168.1.100:50609;received=127.0.0.1;rport=5632\r
806
To: <sip:exarkun@intarweb.us:50609>\r
807
From: <sip:exarkun@intarweb.us:50609>\r
808
Call-ID: 94E7E5DAF39111D791C6000393764646@intarweb.us\r
809
CSeq: 9899 REGISTER\r
810
Contact: sip:exarkun@127.0.0.1:5632\r
816
class FakeDigestAuthorizer(sip.DigestAuthorizer):
817
def generateNonce(self):
818
return '92956076410767313901322208775'
819
def generateOpaque(self):
823
class FakeRegistry(sip.InMemoryRegistry):
824
"""Make sure expiration is always seen to be 3600.
826
Otherwise slow reactors fail tests incorrectly.
829
def _cbReg(self, reg):
830
if 3600 < reg.secondsToExpiry or reg.secondsToExpiry < 3598:
832
"bad seconds to expire: %s" % reg.secondsToExpiry)
833
reg.secondsToExpiry = 3600
836
def getRegistrationInfo(self, uri):
837
d = sip.InMemoryRegistry.getRegistrationInfo(self, uri)
838
return d.addCallback(self._cbReg)
840
def registerAddress(self, domainURL, logicalURL, physicalURL):
841
d = sip.InMemoryRegistry.registerAddress(
842
self, domainURL, logicalURL, physicalURL)
843
return d.addCallback(self._cbReg)
845
class AuthorizationTestCase(unittest.TestCase):
847
self.proxy = sip.RegisterProxy(host="intarweb.us")
848
self.proxy.authorizers = self.proxy.authorizers.copy()
849
self.proxy.authorizers['digest'] = FakeDigestAuthorizer()
851
self.registry = FakeRegistry("intarweb.us")
852
self.proxy.registry = self.proxy.locator = self.registry
853
self.transport = proto_helpers.FakeDatagramTransport()
854
self.proxy.transport = self.transport
857
p = cred.portal.Portal(r)
858
c = cred.checkers.InMemoryUsernamePasswordDatabaseDontUse()
859
c.addUser('exarkun@intarweb.us', 'password')
861
self.proxy.portal = p
862
setUp = utils.suppressWarnings(setUp,
863
util.suppress(category=DeprecationWarning,
864
message=r'twisted.protocols.sip.DigestAuthorizer was deprecated'))
867
for d, uri in self.registry.users.values():
871
def testChallenge(self):
872
self.proxy.datagramReceived(registerRequest, ("127.0.0.1", 5632))
875
self.transport.written[-1],
876
((challengeResponse, ("127.0.0.1", 5632)))
878
self.transport.written = []
880
self.proxy.datagramReceived(authRequest, ("127.0.0.1", 5632))
883
self.transport.written[-1],
884
((okResponse, ("127.0.0.1", 5632)))
886
testChallenge.suppress = [
888
category=DeprecationWarning,
889
message=r'twisted.protocols.sip.DigestAuthorizer was deprecated'),
891
category=DeprecationWarning,
892
message=r'twisted.protocols.sip.DigestedCredentials was deprecated'),
894
category=DeprecationWarning,
895
message=r'twisted.protocols.sip.DigestCalcHA1 was deprecated'),
897
category=DeprecationWarning,
898
message=r'twisted.protocols.sip.DigestCalcResponse was deprecated')]
902
class DeprecationTests(unittest.TestCase):
904
Tests for deprecation of obsolete components of L{twisted.protocols.sip}.
907
def test_deprecatedDigestCalcHA1(self):
909
L{sip.DigestCalcHA1} is deprecated.
911
self.callDeprecated(Version("Twisted", 9, 0, 0),
912
sip.DigestCalcHA1, '', '', '', '', '', '')
915
def test_deprecatedDigestCalcResponse(self):
917
L{sip.DigestCalcResponse} is deprecated.
919
self.callDeprecated(Version("Twisted", 9, 0, 0),
920
sip.DigestCalcResponse, '', '', '', '', '', '', '',
923
def test_deprecatedBasicAuthorizer(self):
925
L{sip.BasicAuthorizer} is deprecated.
927
self.callDeprecated(Version("Twisted", 9, 0, 0), sip.BasicAuthorizer)
930
def test_deprecatedDigestAuthorizer(self):
932
L{sip.DigestAuthorizer} is deprecated.
934
self.callDeprecated(Version("Twisted", 9, 0, 0), sip.DigestAuthorizer)
937
def test_deprecatedDigestedCredentials(self):
939
L{sip.DigestedCredentials} is deprecated.
941
self.callDeprecated(Version("Twisted", 9, 0, 0),
942
sip.DigestedCredentials, '', {}, {})