Changeset 40:2bcb10fb4da4 for wokkel


Ignore:
Timestamp:
Oct 18, 2008, 12:18:02 PM (14 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
default
Convert:
svn:b33ecbfc-034c-dc11-8662-000475d9059e/trunk@112
Message:

Track changes to Twisted branch for the XMPP router.

Location:
wokkel
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • wokkel/component.py

    r39 r40  
    134134    """
    135135    Authenticator for accepting components.
    136     """
     136
     137    @ivar secret: The shared used to authorized incoming component connections.
     138    @type secret: C{str}.
     139    """
     140
    137141    namespace = NS_COMPONENT_ACCEPT
    138142
     
    143147
    144148    def associateWithStream(self, xs):
     149        """
     150        Associate the authenticator with a stream.
     151
     152        This sets the stream's version to 0.0, because the XEP-0114 component
     153        protocol was not designed for XMPP 1.0.
     154        """
    145155        xs.version = (0, 0)
    146156        xmlstream.ListenAuthenticator.associateWithStream(self, xs)
     
    148158
    149159    def streamStarted(self, rootElement):
     160        """
     161        Called by the stream when it has started.
     162
     163        This examines the default namespace of the incoming stream and whether
     164        there is a requested hostname for the component. Then it generates a
     165        stream identifier, sends a response header and adds an observer for
     166        the first incoming element, triggering L{onElement}.
     167        """
     168
    150169        xmlstream.ListenAuthenticator.streamStarted(self, rootElement)
     170
     171        # Compatibility fix
     172        if not self.xmlstream.sid:
     173            from twisted.python import randbytes
     174            self.xmlstream.sid = randbytes.secureRandom(8).encode('hex')
    151175
    152176        if rootElement.defaultUri != self.namespace:
     
    156180
    157181        # self.xmlstream.thisEntity is set to the address the component
    158         # wants to assume. This should probably be checked.
     182        # wants to assume.
    159183        if not self.xmlstream.thisEntity:
    160184            exc = error.StreamError('improper-addressing')
     
    162186            return
    163187
    164         self.xmlstream.sid = 'random' # FIXME
    165 
    166188        self.xmlstream.sendHeader()
    167189        self.xmlstream.addOnetimeObserver('/*', self.onElement)
     
    169191
    170192    def onElement(self, element):
     193        """
     194        Called on incoming XML Stanzas.
     195
     196        The very first element received should be a request for handshake.
     197        Otherwise, the stream is dropped with a 'not-authorized' error. If a
     198        handshake request was received, the hash is extracted and passed to
     199        L{onHandshake}.
     200        """
    171201        if (element.uri, element.name) == (self.namespace, 'handshake'):
    172202            self.onHandshake(unicode(element))
    173203        else:
    174             exc = error.streamError('not-authorized')
     204            exc = error.StreamError('not-authorized')
    175205            self.xmlstream.sendStreamError(exc)
    176206
    177207
    178208    def onHandshake(self, handshake):
     209        """
     210        Called upon receiving the handshake request.
     211
     212        This checks that the given hash in C{handshake} is equal to a
     213        calculated hash, responding with a handshake reply or a stream error.
     214        If the handshake was ok, the stream is authorized, and  XML Stanzas may
     215        be exchanged.
     216        """
    179217        calculatedHash = xmlstream.hashPassword(self.xmlstream.sid, self.secret)
    180218        if handshake != calculatedHash:
     
    188226
    189227
    190 class RouterService(service.Service):
    191     """
    192     XMPP Server's Router Service.
    193 
    194     This service connects the different components of the XMPP service and
    195     routes messages between them based on the given routing table.
     228class Router(object):
     229    """
     230    XMPP Server's Router.
     231
     232    A router connects the different components of the XMPP service and routes
     233    messages between them based on the given routing table.
    196234
    197235    Connected components are trusted to have correct addressing in the
     
    251289        @type stanza: L{domish.Element}.
    252290        """
    253         if not list(stanza.elements()):
    254             return
    255 
    256291        destination = JID(stanza['to'])
    257292
     
    265300
    266301
    267 class ComponentServer(service.Service):
    268     """
    269     XMPP Component Server service.
    270 
    271     This service accepts XMPP external component connections and makes
     302class XMPPComponentServerFactory(xmlstream.XmlStreamServerFactory):
     303    """
     304    XMPP Component Server factory.
     305
     306    This factory accepts XMPP external component connections and makes
    272307    the router service route traffic for a component's bound domain
    273308    to that component.
     
    276311    logTraffic = False
    277312
    278     def __init__(self, router, port=5347, secret='secret'):
     313    def __init__(self, router, secret='secret'):
    279314        self.router = router
    280         self.port = port
    281315        self.secret = secret
    282316
     
    284318            return ListenComponentAuthenticator(self.secret)
    285319
    286         self.factory = xmlstream.XmlStreamServerFactory(authenticatorFactory)
    287         self.factory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT,
    288                                   self.makeConnection)
    289         self.factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT,
    290                                   self.connectionInitialized)
     320        xmlstream.XmlStreamServerFactory.__init__(self, authenticatorFactory)
     321        self.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT,
     322                          self.makeConnection)
     323        self.addBootstrap(xmlstream.STREAM_AUTHD_EVENT,
     324                          self.connectionInitialized)
    291325
    292326        self.serial = 0
    293 
    294 
    295     def startService(self):
    296         service.Service.startService(self)
    297         reactor.listenTCP(self.port, self.factory)
    298327
    299328
  • wokkel/test/test_component.py

    r39 r40  
    2424
    2525    def setUp(self):
    26         self.router = component.RouterService()
     26        self.router = component.Router()
    2727        self.component = component.InternalComponent(self.router, 'component')
    2828
     
    114114        message = domish.Element((None, 'message'))
    115115
     116        self.router.route = fn
    116117        self.component.startService()
    117         self.router.routes['component'].addObserver('/message', fn)
    118118        self.component.send(message)
    119119
     
    122122
    123123
    124 class RouterServiceTest(unittest.TestCase):
    125     """
    126     Tests for L{component.RouterService}.
     124class RouterTest(unittest.TestCase):
     125    """
     126    Tests for L{component.Router}.
    127127    """
    128128
     
    131131        Test route registration and routing on incoming stanzas.
    132132        """
    133         router = component.RouterService()
     133        router = component.Router()
    134134        routed = []
    135135        router.route = lambda element: routed.append(element)
     
    151151        component1 = XmlPipe()
    152152        component2 = XmlPipe()
    153         router = component.RouterService()
     153        router = component.Router()
    154154        router.addRoute('component1.example.org', component1.sink)
    155155        router.addRoute('component2.example.org', component2.sink)
     
    158158        component2.source.addObserver('/*',
    159159                                      lambda element: outgoing.append(element))
    160         stanza = domish.Element((None, 'route'))
     160        stanza = domish.Element((None, 'presence'))
    161161        stanza['from'] = 'component1.example.org'
    162162        stanza['to'] = 'component2.example.org'
    163         stanza.addElement('presence')
    164163        component1.source.send(stanza)
    165164        self.assertEquals([stanza], outgoing)
     
    176175        component1 = XmlPipe()
    177176        s2s = XmlPipe()
    178         router = component.RouterService()
     177        router = component.Router()
    179178        router.addRoute('component1.example.org', component1.sink)
    180179        router.addRoute(None, s2s.sink)
     
    182181        outgoing = []
    183182        s2s.source.addObserver('/*', lambda element: outgoing.append(element))
    184         stanza = domish.Element((None, 'route'))
     183        stanza = domish.Element((None, 'presence'))
    185184        stanza['from'] = 'component1.example.org'
    186185        stanza['to'] = 'example.com'
    187         stanza.addElement('presence')
    188186        component1.source.send(stanza)
    189187        self.assertEquals([stanza], outgoing)
     
    211209
    212210    def test_streamStarted(self):
     211        """
     212        The received stream header should set several attributes.
     213        """
    213214        observers = []
    214215
     
    249250
    250251    def test_streamStartedNoTo(self):
     252        """
     253        The received stream header should have a 'to' attribute.
     254        """
    251255        streamErrors = []
    252256
     
    274278        self.assertEqual('1234', handshakes[-1])
    275279
     280    def test_onElementNotHandshake(self):
     281        """
     282        Reject elements that are not handshakes
     283        """
     284        handshakes = []
     285        streamErrors = []
     286
     287        xs = self.xmlstream
     288        xs.authenticator.onHandshake = handshakes.append
     289        xs.sendStreamError = streamErrors.append
     290
     291        element = domish.Element(('jabber:component:accept', 'message'))
     292        xs.authenticator.onElement(element)
     293        self.assertFalse(handshakes)
     294        self.assertEquals('not-authorized', streamErrors[-1].condition)
     295
     296
    276297    def test_onHandshake(self):
    277         xs = self.xmlstream
     298        """
     299        Receiving a handshake matching the secret authenticates the stream.
     300        """
     301        authd = []
     302
     303        def authenticated(xs):
     304            authd.append(xs)
     305
     306        xs = self.xmlstream
     307        xs.addOnetimeObserver(xmlstream.STREAM_AUTHD_EVENT, authenticated)
    278308        xs.sid = '1234'
    279309        theHash = '32532c0f7dbf1253c095b18b18e36d38d94c1256'
    280310        xs.authenticator.onHandshake(theHash)
    281311        self.assertEqual('<handshake/>', self.output[-1])
     312        self.assertEquals(1, len(authd))
    282313
    283314
    284315    def test_onHandshakeWrongHash(self):
     316        """
     317        Receiving a bad handshake should yield a stream error.
     318        """
    285319        streamErrors = []
    286320        authd = []
    287321
    288         def authenticated(self, xs):
     322        def authenticated(xs):
    289323            authd.append(xs)
    290324
     
    301335
    302336
    303 class ComponentServerTest(unittest.TestCase):
    304     """
    305     Tests for L{component.ComponentServer}.
     337class XMPPComponentServerFactoryTest(unittest.TestCase):
     338    """
     339    Tests for L{component.XMPPComponentServerFactory}.
    306340    """
    307341
    308342    def setUp(self):
    309         self.router = component.RouterService()
    310         self.server = component.ComponentServer(self.router)
    311         self.xmlstream = self.server.factory.buildProtocol(None)
     343        self.router = component.Router()
     344        self.factory = component.XMPPComponentServerFactory(self.router,
     345                                                            'secret')
     346        self.xmlstream = self.factory.buildProtocol(None)
    312347        self.xmlstream.thisEntity = JID('component.example.org')
    313348
     
    320355                                xmlstream.STREAM_CONNECTED_EVENT)
    321356        self.assertEqual(0, self.xmlstream.serial)
    322         self.assertEqual(1, self.server.serial)
     357        self.assertEqual(1, self.factory.serial)
    323358        self.assertIdentical(None, self.xmlstream.rawDataInFn)
    324359        self.assertIdentical(None, self.xmlstream.rawDataOutFn)
     
    329364        Setting logTraffic should set up raw data loggers.
    330365        """
    331         self.server.logTraffic = True
     366        self.factory.logTraffic = True
    332367        self.xmlstream.dispatch(self.xmlstream,
    333368                                xmlstream.STREAM_CONNECTED_EVENT)
Note: See TracChangeset for help on using the changeset viewer.