Changeset 7:0fbac5c2e97d in ralphm-patches for s2s.patch


Ignore:
Timestamp:
Apr 7, 2009, 11:53:45 AM (13 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
default
Message:

Save current state.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • s2s.patch

    r6 r7  
    1 diff -r c52801c0d6c2 wokkel/server.py
     1diff -r 842c0a2f8fa1 wokkel/server.py
    22--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
    3 +++ b/wokkel/server.py  Wed Apr 01 17:23:43 2009 +0200
    4 @@ -0,0 +1,566 @@
     3+++ b/wokkel/server.py  Tue Apr 07 09:17:35 2009 +0200
     4@@ -0,0 +1,684 @@
    55+# -*- test-case-name: wokkel.test.test_server -*-
    66+#
     
    225225+
    226226+class XMPPServerConnectAuthenticator(xmlstream.ConnectAuthenticator):
     227+    """
     228+    Authenticator for an outgoing XMPP server-to-server connection.
     229+
     230+    This authenticator connects to C{otherHost} (the Receiving Server) and then
     231+    initiates dialback as C{thisHost} (the Originating Server) using
     232+    L{OriginatingDialbackInitializer}.
     233+
     234+    @ivar thisHost: The domain this server connects from (the Originating
     235+                    Server) .
     236+    @ivar otherHost: The domain of the server this server connects to (the
     237+                     Receiving Server).
     238+    @ivar secret: The shared secret that is used for verifying the validity
     239+                  of this new connection.
     240+    """
    227241+    namespace = 'jabber:server'
    228242+
     
    250264+
    251265+class XMPPServerVerifyAuthenticator(xmlstream.ConnectAuthenticator):
     266+    """
     267+    Authenticator for an outgoing connection to verify an incoming connection.
     268+
     269+    This authenticator connects to C{otherHost} (the Authoritative Server) and
     270+    then initiates dialback as C{thisHost} (the Receiving Server) using
     271+    L{ReceivingDialbackInitializer}.
     272+
     273+    @ivar thisHost: The domain this server connects from (the Receiving
     274+                    Server) .
     275+    @ivar otherHost: The domain of the server this server connects to (the
     276+                     Authoritative Server).
     277+    @ivar originalStreamID: The stream ID of the incoming connection that is
     278+                            being verified.
     279+    @ivar key: The key provided by the Receving Server to be verified.
     280+    """
    252281+    namespace = 'jabber:server'
    253282+
     
    276305+
    277306+class XMPPServerListenAuthenticator(xmlstream.ListenAuthenticator):
     307+    """
     308+    Authenticator for an incoming XMPP server-to-server connection.
     309+
     310+    This authenticator handles two types of incoming connections. Regular
     311+    server-to-server connections are from the Originating Server to the
     312+    Receiving Server, where this server is the Receiving Server. These
     313+    connections start out by receiving a dialback key, verifying the
     314+    key with the Authoritative Server, and then accept normal XMPP stanzas.
     315+
     316+    The other type of connections is from a Receiving Server to an
     317+    Authoritative Server, where this server acts as the Authoritative Server.
     318+    These connections are used to verify the validity of an outgoing connection
     319+    from this server. In this case, this server receives a verification
     320+    request, checks the key and then returns the result.
     321+
     322+    @ivar service: The service that keeps the list of domains we accept
     323+                   connections for.
     324+    """
    278325+    namespace = 'jabber:server'
    279 +    connectorClass = XMPPServerConnector
    280 +
    281 +    def __init__(self, domain, secret):
     326+
     327+    def __init__(self, service):
    282328+        xmlstream.ListenAuthenticator.__init__(self)
    283 +        self.domain = domain
    284 +        self.secret = secret
     329+        self.service = service
    285330+
    286331+
     
    293338+            self.xmlstream.sid = randbytes.secureRandom(8).encode('hex')
    294339+
    295 +        def prepareStream():
     340+        if self.xmlstream.thisEntity:
     341+            targetDomain = self.xmlstream.thisEntity.host
     342+        else:
     343+            targetDomain = self.service.defaultDomain
     344+
     345+        def prepareStream(domain):
    296346+            self.xmlstream.namespace = self.namespace
    297347+            self.xmlstream.prefixes = {xmlstream.NS_STREAMS: 'stream',
    298348+                                       NS_DIALBACK: 'db'}
    299 +            self.xmlstream.thisEntity = jid.internJID(self.domain)
     349+            self.xmlstream.thisEntity = jid.internJID(domain)
    300350+
    301351+        try:
     
    305355+                raise error.StreamError('invalid-namespace')
    306356+
    307 +            if self.xmlstream.thisEntity.full() != self.domain:
     357+            if targetDomain not in self.service.domains:
    308358+                raise error.StreamError('host-unknown')
    309359+        except error.StreamError, exc:
    310 +            prepareStream()
     360+            prepareStream(self.service.defaultDomain)
    311361+            self.xmlstream.sendStreamError(exc)
    312362+            return
     
    318368+                                   self.onResult)
    319369+
    320 +        prepareStream()
     370+        prepareStream(targetDomain)
    321371+        self.xmlstream.sendHeader()
    322372+
     
    326376+
    327377+
    328 +
    329378+    def onVerify(self, verify):
    330379+        try:
    331 +            receivingServer = jid.JID(verify['from'])
    332 +            originatingServer = jid.JID(verify['to'])
     380+            receivingServer = jid.JID(verify['from']).host
     381+            originatingServer = jid.JID(verify['to']).host
    333382+        except (KeyError, jid.InvalidFormat):
    334383+            raise error.StreamError('improper-addressing')
    335384+
    336 +        if originatingServer != self.domain:
     385+        if originatingServer not in self.service.domains:
    337386+            raise error.StreamError('host-unknown')
    338387+
    339 +        if receivingServer != self.xmlstream.thisEntity:
     388+        if (self.xmlstream.otherEntity and
     389+            receivingServer != self.xmlstream.otherEntity.host):
    340390+            raise error.StreamError('invalid-from')
    341391+
     
    343393+        key = unicode(verify)
    344394+
    345 +        calculatedKey = generateKey(self.secret, receivingServer,
     395+        calculatedKey = generateKey(self.service.secret, receivingServer,
    346396+                                    originatingServer, streamID)
    347397+        validity = (key == calculatedKey) and 'valid' or 'invalid'
     
    356406+
    357407+    def onResult(self, result):
    358 +        def connected(xs):
    359 +            self.verifyStream = xs
    360 +
    361 +            def logDataIn(buf):
    362 +                log.msg("RECV!: %r" % buf)
    363 +
    364 +            def logDataOut(buf):
    365 +                log.msg("SEND!: %r" % buf)
    366 +
    367 +            xs.rawDataInFn = logDataIn
    368 +            xs.rawDataOutFn = logDataOut
    369 +
    370408+        def reply(validity):
    371 +            factory.stopTrying()
    372 +            self.verifyStream.transport.loseConnection()
    373 +            self.verifyStream = None
    374 +
    375409+            reply = domish.Element((NS_DIALBACK, 'result'))
    376410+            reply['from'] = result['to']
     
    386420+
    387421+        def invalid(failure):
     422+            log.err(failure)
    388423+            reply('invalid')
    389424+
     425+        receivingServer = result['to']
    390426+        originatingServer = result['from']
    391 +
    392 +        authenticator = XMPPServerVerifyAuthenticator(self.domain,
    393 +                                                      originatingServer,
    394 +                                                      self.xmlstream.sid,
    395 +                                                      unicode(result))
    396 +        factory = xmlstream.XmlStreamFactory(authenticator)
    397 +        factory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, connected)
    398 +        factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, valid)
    399 +        factory.addBootstrap(xmlstream.INIT_FAILED_EVENT, invalid)
    400 +        connector = self.connectorClass(reactor,
    401 +                                        originatingServer,
    402 +                                        factory)
    403 +        connector.connect()
     427+        key = unicode(result)
     428+
     429+        d = self.service.validateConnection(receivingServer, originatingServer,
     430+                                            self.xmlstream.sid, key)
     431+        d.addCallbacks(valid, invalid)
     432+        return d
    404433+
    405434+
     
    414443+    """
    415444+
    416 +    def __init__(self, domain, otherHost, secret):
    417 +        authenticator = XMPPServerConnectAuthenticator(domain,
    418 +                                                            otherHost,
    419 +                                                            secret)
     445+    def __init__(self, authenticator):
    420446+        DeferredXmlStreamFactory.__init__(self, authenticator)
     447+
     448+        self.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT,
     449+                          self.onConnectionMade)
     450+
     451+        self.serial = 0
     452+
     453+
     454+    def onConnectionMade(self, xs):
     455+        xs.serial = self.serial
     456+        self.serial += 1
     457+
     458+        def logDataIn(buf):
     459+            log.msg("RECV (%d): %r" % (xs.serial, buf))
     460+
     461+        def logDataOut(buf):
     462+            log.msg("SEND (%d): %r" % (xs.serial, buf))
     463+
     464+        if self.logTraffic:
     465+            xs.rawDataInFn = logDataIn
     466+            xs.rawDataOutFn = logDataOut
    421467+
    422468+
     
    430476+
    431477+
    432 +class ServerService(service.Service):
     478+class XMPPS2SServerFactory(XmlStreamServerFactory):
     479+    """
     480+    XMPP Server-to-Server Server factory.
     481+
     482+    This factory accepts XMPP server-to-server connections.
     483+    """
     484+
     485+    logTraffic = False
     486+
     487+    def __init__(self, service):
     488+        self.service = service
     489+
     490+        def authenticatorFactory():
     491+            return XMPPServerListenAuthenticator(service)
     492+
     493+        XmlStreamServerFactory.__init__(self, authenticatorFactory)
     494+        self.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT,
     495+                          self.onConnectionMade)
     496+        self.addBootstrap(xmlstream.STREAM_AUTHD_EVENT,
     497+                          self.onAuthenticated)
     498+
     499+        self.serial = 0
     500+
     501+
     502+    def onConnectionMade(self, xs):
     503+        """
     504+        Called when a server-to-server connection was made.
     505+
     506+        This enables traffic debugging on incoming streams.
     507+        """
     508+        xs.serial = self.serial
     509+        self.serial += 1
     510+
     511+        def logDataIn(buf):
     512+            log.msg("RECV (%d): %r" % (xs.serial, buf))
     513+
     514+        def logDataOut(buf):
     515+            log.msg("SEND (%d): %r" % (xs.serial, buf))
     516+
     517+        if self.logTraffic:
     518+            xs.rawDataInFn = logDataIn
     519+            xs.rawDataOutFn = logDataOut
     520+
     521+        xs.addObserver(xmlstream.STREAM_ERROR_EVENT, self.onError)
     522+
     523+
     524+    def onAuthenticated(self, xs):
     525+        thisHost = xs.thisEntity.host
     526+        otherHost = xs.otherEntity.host
     527+
     528+        log.msg("Incoming connection %d from %r to %r established" %
     529+                (xs.serial, otherHost, thisHost))
     530+
     531+        xs.addObserver(xmlstream.STREAM_END_EVENT, self.onConnectionLost,
     532+                                                   0, xs)
     533+        xs.addObserver('/*', self.onElement, 0, xs)
     534+
     535+
     536+    def onConnectionLost(self, xs, reason):
     537+        thisHost = xs.thisEntity.host
     538+        otherHost = xs.otherEntity.host
     539+
     540+        log.msg("Incoming connection %d from %r to %r disconnected" %
     541+                (xs.serial, otherHost, thisHost))
     542+
     543+
     544+    def onError(self, reason):
     545+        log.err(reason, "Stream Error")
     546+
     547+
     548+    def onElement(self, element, xs):
     549+        """
     550+        Called when an element was received from one of the connected streams.
     551+
     552+        """
     553+        if element.handled:
     554+            return
     555+
     556+        if jid.internJID(element["from"]).host != xs.otherEntity.host:
     557+            xs.sendStreamError(error.StreamError('invalid-from'))
     558+        else:
     559+            self.service.dispatch(element)
     560+
     561+
     562+
     563+class ServerService(object):
    433564+    """
    434565+    Service for managing XMPP server to server connections.
     
    437568+    logTraffic = False
    438569+
    439 +    def __init__(self, router, domain, port=5222):
     570+    def __init__(self, router, secret, domain):
    440571+        self.router = router
    441 +        self.domain = domain
    442 +        self.port = port
    443 +        self.secret = 'woei!'
    444 +
    445 +        def authenticatorFactory():
    446 +            return XMPPServerListenAuthenticator(self.domain, self.secret)
    447 +        self.factory = XmlStreamServerFactory(authenticatorFactory)
    448 +        self.factory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT,
    449 +                                  self.makeConnection)
    450 +        self.factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT,
    451 +                                  self.incomingInitialized)
    452 +
    453 +        self.incomingStreams = {}
    454 +        self.outgoingStreams = {}
    455 +        self.outgoingQueues = {}
    456 +        self.outgoingConnecting = set()
     572+        self.secret = secret
     573+        self.defaultDomain = domain
     574+        self.domains = set([domain])
     575+
     576+        self._outgoingStreams = {}
     577+        self._outgoingQueues = {}
     578+        self._outgoingConnecting = set()
    457579+        self.serial = 0
    458580+
    459 +
    460 +    def startService(self):
    461581+        pipe = XmlPipe()
    462582+        self.xmlstream = pipe.source
     
    464584+        self.xmlstream.addObserver('/*', self.send)
    465585+
    466 +        service.Service.startService(self)
    467 +        reactor.listenTCP(self.port, self.factory)
    468 +
    469 +
    470 +    def makeConnection(self, xs):
    471 +        xs.serial = self.serial
    472 +        self.serial += 1
    473 +
    474 +        def logDataIn(buf):
    475 +            log.msg("RECV (%d): %r" % (xs.serial, buf))
    476 +
    477 +        def logDataOut(buf):
    478 +            log.msg("SEND (%d): %r" % (xs.serial, buf))
    479 +
    480 +        if self.logTraffic:
    481 +            xs.rawDataInFn = logDataIn
    482 +            xs.rawDataOutFn = logDataOut
    483 +
    484 +
    485 +    def incomingInitialized(self, xs):
    486 +        self.incomingStreams[xs.otherEntity.host] = xs
    487 +        xs.addObserver(xmlstream.STREAM_END_EVENT,
    488 +                       lambda _: self.incomingDisconnected(xs))
    489 +        xs.addObserver('/*', lambda element: self.onElement(element, xs))
    490 +
    491 +
    492 +    def incomingDisconnected(self, xs):
    493 +        del self.incomingStreams[xs.otherEntity.host]
    494 +
    495586+
    496587+    def outgoingInitialized(self, xs):
    497 +        self.outgoingStreams[xs.otherEntity.host] = xs
     588+        thisHost = xs.thisEntity.host
     589+        otherHost = xs.otherEntity.host
     590+
     591+        log.msg("Outgoing connection %d from %r to %r established" %
     592+                (xs.serial, thisHost, otherHost))
     593+
     594+        self._outgoingStreams[thisHost, otherHost] = xs
    498595+        xs.addObserver(xmlstream.STREAM_END_EVENT,
    499596+                       lambda _: self.outgoingDisconnected(xs))
    500597+
    501 +        if xs.otherEntity.host in self.outgoingQueues:
    502 +            print "Hier!"
    503 +            for element in self.outgoingQueues[xs.otherEntity.host]:
     598+        if (thisHost, otherHost) in self._outgoingQueues:
     599+            for element in self._outgoingQueues[thisHost, otherHost]:
    504600+                xs.send(element)
    505 +            del self.outgoingQueues[xs.otherEntity.host]
     601+            del self._outgoingQueues[thisHost, otherHost]
    506602+
    507603+
    508604+    def outgoingDisconnected(self, xs):
    509 +        del self.outgoingStreams[xs.otherEntity.host]
    510 +
    511 +
    512 +    def initiateOutgoingStream(self, otherHost):
    513 +        if otherHost in self.outgoingConnecting:
     605+        thisHost = xs.thisEntity.host
     606+        otherHost = xs.otherEntity.host
     607+
     608+        log.msg("Outgoing connection %d from %r to %r disconnected" %
     609+                (xs.serial, thisHost, otherHost))
     610+
     611+        del self._outgoingStreams[thisHost, otherHost]
     612+
     613+
     614+    def initiateOutgoingStream(self, thisHost, otherHost):
     615+        """
     616+        Initiate an outgoing XMPP server-to-server connection.
     617+        """
     618+
     619+        def resetConnecting(_):
     620+            self._outgoingConnecting.remove((thisHost, otherHost))
     621+
     622+        if (thisHost, otherHost) in self._outgoingConnecting:
    514623+            return
    515624+
    516 +        factory = DeferredS2SClientFactory(self.domain,
    517 +                                           otherHost,
    518 +                                           self.secret)
    519 +        factory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT,
    520 +                             self.makeConnection)
     625+        authenticator = XMPPServerConnectAuthenticator(thisHost,
     626+                                                       otherHost,
     627+                                                       self.secret)
     628+        factory = DeferredS2SClientFactory(authenticator)
    521629+        factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT,
    522630+                             self.outgoingInitialized)
    523631+
    524 +        def resetConnecting(_):
    525 +            self.outgoingConnecting.remove(otherHost)
     632+        self._outgoingConnecting.add((thisHost, otherHost))
    526633+
    527634+        d = initiateS2S(factory)
    528 +        def debug(result):
    529 +            print result
    530 +            return result
    531 +        d.addBoth(debug)
    532635+        d.addBoth(resetConnecting)
    533 +        self.outgoingConnecting.add(otherHost)
    534 +
    535 +
    536 +    def onElement(self, element, xs):
    537 +        """
    538 +        Called when an element was received from one of the connected streams.
    539 +
    540 +        """
    541 +        if element.handled:
    542 +            return
    543 +
    544 +        if jid.internJID(element["from"]).host != xs.otherEntity.host:
    545 +            xs.sendStreamError(error.StreamError('invalid-from'))
    546 +        else:
    547 +            self.xmlstream.send(element)
     636+        return d
     637+
     638+
     639+    def validateConnection(self, thisHost, otherHost, sid, key):
     640+        """
     641+        Validate an incoming XMPP server-to-server connection.
     642+        """
     643+
     644+        def connected(xs):
     645+            # Set up stream for immediate disconnection.
     646+            def disconnect(_):
     647+                xs.transport.loseConnection()
     648+            xs.addObserver(xmlstream.STREAM_AUTHD_EVENT, disconnect)
     649+            xs.addObserver(xmlstream.INIT_FAILED_EVENT, disconnect)
     650+
     651+        authenticator = XMPPServerVerifyAuthenticator(thisHost, otherHost,
     652+                                                      sid, key)
     653+        factory = DeferredS2SClientFactory(authenticator)
     654+        factory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, connected)
     655+
     656+        d = initiateS2S(factory)
     657+        return d
    548658+
    549659+
     
    556666+        """
    557667+
    558 +        destination = jid.internJID(stanza["to"]).host
    559 +
    560 +        if destination not in self.outgoingStreams:
     668+        otherHost = jid.internJID(stanza["to"]).host
     669+        thisHost = jid.internJID(stanza["from"]).host
     670+
     671+        if (thisHost, otherHost) not in self._outgoingStreams:
    561672+            # There is no connection with the destination (yet). Cache the
    562673+            # outgoing stanza until the connection has been established.
    563674+            # XXX: If the connection cannot be established, the queue should
    564675+            #      be emptied at some point.
    565 +            if destination not in self.outgoingQueues:
    566 +                self.outgoingQueues[destination] = []
    567 +            self.outgoingQueues[destination].append(stanza)
    568 +            self.initiateOutgoingStream(destination)
     676+            if (thisHost, otherHost) not in self._outgoingQueues:
     677+                self._outgoingQueues[(thisHost, otherHost)] = []
     678+            self._outgoingQueues[(thisHost, otherHost)].append(stanza)
     679+            self.initiateOutgoingStream(thisHost, otherHost)
    569680+        else:
    570 +            self.outgoingStreams[destination].send(stanza)
    571 diff -r c52801c0d6c2 wokkel/test/test_server.py
     681+            self._outgoingStreams[(thisHost, otherHost)].send(stanza)
     682+
     683+
     684+    def dispatch(self, element):
     685+        """
     686+        Send on element to be routed within the server.
     687+        """
     688+        self.xmlstream.send(element)
     689diff -r 842c0a2f8fa1 wokkel/test/test_server.py
    572690--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
    573 +++ b/wokkel/test/test_server.py        Wed Apr 01 17:23:43 2009 +0200
    574 @@ -0,0 +1,227 @@
     691+++ b/wokkel/test/test_server.py        Tue Apr 07 09:17:35 2009 +0200
     692@@ -0,0 +1,412 @@
    575693+# Copyright (c) 2003-2008 Ralph Meijer
    576694+# See LICENSE for details.
     
    580698+"""
    581699+
     700+from twisted.internet import defer
     701+from twisted.python import failure
     702+from twisted.test.proto_helpers import StringTransport
    582703+from twisted.trial import unittest
    583 +from twisted.words.protocols.jabber import error, xmlstream
    584 +from twisted.test.proto_helpers import StringTransport
    585 +
    586 +from wokkel import server
     704+from twisted.words.protocols.jabber import error, jid, xmlstream
     705+from twisted.words.xish import domish
     706+
     707+from wokkel import component, server
    587708+
    588709+NS_STREAMS = 'http://etherx.jabber.org/streams'
    589 +DIALBACK_NS = "jabber:server:dialback"
     710+NS_DIALBACK = "jabber:server:dialback"
    590711+
    591712+class GenerateKeyTest(unittest.TestCase):
     
    595716+
    596717+    def testBasic(self):
     718+        originating = "example.org"
     719+        receiving = "xmpp.example.com"
     720+        sid = "D60000229F"
    597721+        secret = "s3cr3tf0rd14lb4ck"
    598 +        receiving = "example.net"
    599 +        originating = "example.com"
    600 +        id = "D60000229F"
    601 +
    602 +        key = server.generateKey(secret, receiving, originating, id)
     722+
     723+        key = server.generateKey(secret, receiving, originating, sid)
    603724+
    604725+        self.assertEqual(key,
    605 +            '008c689ff366b50c63d69a3e2d2c0e0e1f8404b0118eb688a0102c87cb691bdc')
     726+            '37c69b1cf07a3f67c04a5ef5902fa5114f2c76fe4a2686482ba5b89323075643')
    606727+
    607728+
     
    612733+    """
    613734+
    614 +    receiving = "example.org"
    615 +    originating = "example.net"
    616 +    id_ = "2093845023948"
    617 +    secret = "not-telling"
     735+    secret = "s3cr3tf0rd14lb4ck"
     736+    originating = "example.org"
     737+    receiving = "xmpp.example.com"
     738+    sid = "D60000229F"
     739+    key = '37c69b1cf07a3f67c04a5ef5902fa5114f2c76fe4a2686482ba5b89323075643'
    618740+
    619741+    def setUp(self):
    620742+        self.output = []
    621 +        self.authenticator = server.XMPPServerListenAuthenticator(
    622 +                        self.receiving, self.secret)
     743+
     744+        class MyService(object):
     745+            pass
     746+
     747+        self.service = MyService()
     748+        self.service.defaultDomain = self.receiving
     749+        self.service.domains = [self.receiving, 'pubsub.'+self.receiving]
     750+        self.service.secret = self.secret
     751+
     752+        self.authenticator = server.XMPPServerListenAuthenticator(self.service)
    623753+        self.xmlstream = xmlstream.XmlStream(self.authenticator)
    624754+        self.xmlstream.send = self.output.append
     
    630760+        Test attributes of authenticator and stream objects.
    631761+        """
    632 +        self.assertEquals(self.secret, self.authenticator.secret)
    633 +        self.assertEquals(self.receiving, self.authenticator.domain)
    634 +        self.assertEquals(self.xmlstream.initiating, False)
     762+        self.assertEqual(self.service, self.authenticator.service)
     763+        self.assertEqual(self.xmlstream.initiating, False)
    635764+
    636765+
     
    644773+                           "xmlns:db='jabber:server:dialback' "
    645774+                           "xmlns='jabber:server' "
    646 +                           "to='example.org'>")
     775+                           "to='xmpp.example.com'>")
    647776+        self.assertEqual((0, 0), self.xmlstream.version)
    648777+
     
    657786+                           "xmlns:db='jabber:server:dialback' "
    658787+                           "xmlns='jabber:server' "
    659 +                           "to='example.org' "
     788+                           "to='xmpp.example.com' "
    660789+                           "version='1.0'>")
    661790+        self.assertEqual((1, 0), self.xmlstream.version)
     
    673802+                           "xmlns:db='jabber:server:dialback' "
    674803+                           "xmlns='jabber:server' "
    675 +                           "to='example.org' "
     804+                           "to='xmpp.example.com' "
    676805+                           "version='1.0'>")
    677806+        self.assertNotIdentical(None, self.xmlstream.sid)
     
    689818+                           "xmlns:db='jabber:server:dialback' "
    690819+                           "xmlns='jabber:server' "
    691 +                           "to='example.org'>")
     820+                           "to='xmpp.example.com'>")
    692821+        self.assertTrue(self.xmlstream._headerSent)
    693822+
     
    702831+                           "xmlns:db='jabber:server:dialback' "
    703832+                           "xmlns='jabber:server' "
    704 +                           "to='example.org'>")
     833+                           "to='xmpp.example.com'>")
    705834+        self.assertEqual(1, len(self.output))
    706835+
     
    715844+                           "xmlns:db='jabber:server:dialback' "
    716845+                           "xmlns='jabber:server' "
    717 +                           "to='example.org' "
     846+                           "to='xmpp.example.com' "
    718847+                           "version='1.0'>")
    719848+        self.assertEqual(2, len(self.output))
     
    732861+                           "xmlns:db='jabber:server:dialback' "
    733862+                           "xmlns='jabber:server' "
    734 +                           "to='example.org'>")
    735 +
    736 +        self.assertEquals(3, len(self.output))
     863+                           "to='xmpp.example.com'>")
     864+
     865+        self.assertEqual(3, len(self.output))
    737866+        exc = error.exceptionFromStreamError(self.output[1])
    738 +        self.assertEquals('invalid-namespace', exc.condition)
     867+        self.assertEqual('invalid-namespace', exc.condition)
    739868+
    740869+
     
    748877+                           "xmlns:db='jabber:server:dialback' "
    749878+                           "xmlns='badns' "
    750 +                           "to='example.org'>")
    751 +
    752 +        self.assertEquals(3, len(self.output))
     879+                           "to='xmpp.example.com'>")
     880+
     881+        self.assertEqual(3, len(self.output))
    753882+        exc = error.exceptionFromStreamError(self.output[1])
    754 +        self.assertEquals('invalid-namespace', exc.condition)
     883+        self.assertEqual('invalid-namespace', exc.condition)
    755884+
    756885+
     
    763892+            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
    764893+                           "xmlns='jabber:server' "
    765 +                           "to='example.org'>")
    766 +
    767 +        self.assertEquals(3, len(self.output))
     894+                           "to='xmpp.example.com'>")
     895+
     896+        self.assertEqual(3, len(self.output))
    768897+        exc = error.exceptionFromStreamError(self.output[1])
    769 +        self.assertEquals('invalid-namespace', exc.condition)
     898+        self.assertEqual('invalid-namespace', exc.condition)
    770899+
    771900+
     
    779908+                           "xmlns:db='badns' "
    780909+                           "xmlns='jabber:server' "
    781 +                           "to='example.org'>")
    782 +
    783 +        self.assertEquals(3, len(self.output))
     910+                           "to='xmpp.example.com'>")
     911+
     912+        self.assertEqual(3, len(self.output))
    784913+        exc = error.exceptionFromStreamError(self.output[1])
    785 +        self.assertEquals('invalid-namespace', exc.condition)
     914+        self.assertEqual('invalid-namespace', exc.condition)
    786915+
    787916+
     
    797926+                           "to='badhost'>")
    798927+
    799 +        self.assertEquals(3, len(self.output))
     928+        self.assertEqual(3, len(self.output))
    800929+        exc = error.exceptionFromStreamError(self.output[1])
    801 +        self.assertEquals('host-unknown', exc.condition)
     930+        self.assertEqual('host-unknown', exc.condition)
     931+
     932+
     933+    def test_streamToOtherLocalHost(self):
     934+        """
     935+        The authenticator supports XMPP 1.0 streams.
     936+        """
     937+        self.xmlstream.connectionMade()
     938+        self.xmlstream.dataReceived(
     939+            "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
     940+                           "xmlns:db='jabber:server:dialback' "
     941+                           "xmlns='jabber:server' "
     942+                           "to='pubsub.xmpp.example.com' "
     943+                           "version='1.0'>")
     944+
     945+        self.assertEqual(2, len(self.output))
     946+        self.assertEqual(jid.JID('pubsub.xmpp.example.com'),
     947+                         self.xmlstream.thisEntity)
     948+
     949+    def test_onResult(self):
     950+        def cb(result):
     951+            self.assertEqual(1, len(self.output))
     952+            reply = self.output[0]
     953+            self.assertEqual(self.originating, reply['to'])
     954+            self.assertEqual(self.receiving, reply['from'])
     955+            self.assertEqual('valid', reply['type'])
     956+
     957+        def validateConnection(thisHost, otherHost, sid, key):
     958+            self.assertEqual(thisHost, self.receiving)
     959+            self.assertEqual(otherHost, self.originating)
     960+            self.assertEqual(sid, self.sid)
     961+            self.assertEqual(key, self.key)
     962+            return defer.succeed(None)
     963+
     964+        self.xmlstream.sid = self.sid
     965+        self.service.validateConnection = validateConnection
     966+
     967+        result = domish.Element((NS_DIALBACK, 'result'))
     968+        result['to'] = self.receiving
     969+        result['from'] = self.originating
     970+        result.addContent(self.key)
     971+
     972+        d = self.authenticator.onResult(result)
     973+        d.addCallback(cb)
     974+        return d
     975+
     976+
     977+    def test_onResultFailure(self):
     978+        class TestError(Exception):
     979+            pass
     980+
     981+        def cb(result):
     982+            reply = self.output[0]
     983+            self.assertEqual('invalid', reply['type'])
     984+            self.assertEqual(1, len(self.flushLoggedErrors(TestError)))
     985+
     986+
     987+        def validateConnection(thisHost, otherHost, sid, key):
     988+            return defer.fail(TestError())
     989+
     990+        self.xmlstream.sid = self.sid
     991+        self.service.validateConnection = validateConnection
     992+
     993+        result = domish.Element((NS_DIALBACK, 'result'))
     994+        result['to'] = self.receiving
     995+        result['from'] = self.originating
     996+        result.addContent(self.key)
     997+
     998+        d = self.authenticator.onResult(result)
     999+        d.addCallback(cb)
     1000+        return d
     1001+
     1002+
     1003+
     1004+class FakeService(object):
     1005+    domains = set(['example.org', 'pubsub.example.org'])
     1006+    defaultDomain = 'example.org'
     1007+    secret = 'mysecret'
     1008+
     1009+    def __init__(self):
     1010+        self.dispatched = []
     1011+
     1012+    def dispatch(self, element):
     1013+        self.dispatch.append(element)
     1014+
     1015+
     1016+
     1017+class XMPPS2SServerFactoryTest(unittest.TestCase):
     1018+    """
     1019+    Tests for L{component.XMPPS2SServerFactory}.
     1020+    """
     1021+
     1022+    def setUp(self):
     1023+        self.service = FakeService
     1024+        self.factory = server.XMPPS2SServerFactory(self.service)
     1025+        self.xmlstream = self.factory.buildProtocol(None)
     1026+        self.xmlstream.thisEntity = jid.JID('example.org')
     1027+        self.xmlstream.otherEntity = jid.JID('example.com')
     1028+
     1029+
     1030+    def test_makeConnection(self):
     1031+        """
     1032+        A new connection increases the stream serial count. No logs by default.
     1033+        """
     1034+        self.xmlstream.dispatch(self.xmlstream,
     1035+                                xmlstream.STREAM_CONNECTED_EVENT)
     1036+        self.assertEqual(0, self.xmlstream.serial)
     1037+        self.assertEqual(1, self.factory.serial)
     1038+        self.assertIdentical(None, self.xmlstream.rawDataInFn)
     1039+        self.assertIdentical(None, self.xmlstream.rawDataOutFn)
     1040+
     1041+
     1042+    def test_makeConnectionLogTraffic(self):
     1043+        """
     1044+        Setting logTraffic should set up raw data loggers.
     1045+        """
     1046+        self.factory.logTraffic = True
     1047+        self.xmlstream.dispatch(self.xmlstream,
     1048+                                xmlstream.STREAM_CONNECTED_EVENT)
     1049+        self.assertNotIdentical(None, self.xmlstream.rawDataInFn)
     1050+        self.assertNotIdentical(None, self.xmlstream.rawDataOutFn)
     1051+
     1052+
     1053+    def test_onError(self):
     1054+        """
     1055+        An observer for stream errors should trigger onError to log it.
     1056+        """
     1057+        self.xmlstream.dispatch(self.xmlstream,
     1058+                                xmlstream.STREAM_CONNECTED_EVENT)
     1059+
     1060+        class TestError(Exception):
     1061+            pass
     1062+
     1063+        reason = failure.Failure(TestError())
     1064+        self.xmlstream.dispatch(reason, xmlstream.STREAM_ERROR_EVENT)
     1065+        self.assertEqual(1, len(self.flushLoggedErrors(TestError)))
     1066+
     1067+
     1068+    def test_connectionInitialized(self):
     1069+        """
     1070+        """
     1071+        self.xmlstream.dispatch(self.xmlstream,
     1072+                                xmlstream.STREAM_CONNECTED_EVENT)
     1073+        self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
     1074+
     1075+
     1076+    def test_connectionLost(self):
     1077+        """
     1078+        """
     1079+        self.xmlstream.dispatch(self.xmlstream,
     1080+                                xmlstream.STREAM_CONNECTED_EVENT)
     1081+        self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
     1082+        self.xmlstream.dispatch(None, xmlstream.STREAM_END_EVENT)
     1083+
     1084+
     1085+    def test_ElementNotAuthenticated(self):
     1086+        self.xmlstream.dispatch(self.xmlstream,
     1087+                                xmlstream.STREAM_CONNECTED_EVENT)
     1088+        self.xmlstream.dataReceived("<presence/>")
     1089+
     1090+
     1091+class ServerServiceTest(unittest.TestCase):
     1092+
     1093+    def setUp(self):
     1094+        self.router = component.Router()
     1095+        self.service = server.ServerService(self.router,
     1096+                                            secret='mysecret',
     1097+                                            domain='example.org')
     1098+
     1099+
     1100+    def test_defaultDomainInDomains(self):
     1101+        """
     1102+        The default domain is part of the domains considered local.
     1103+        """
     1104+        self.assertIn(self.service.defaultDomain, self.service.domains)
Note: See TracChangeset for help on using the changeset viewer.