1
2"""
3Test connecting to a server with 2 accounts. Check one account does not block
4the second account.
5"""
6
7import os
8import sys
9import dbus
10import servicetest
11
12from twisted.words.xish import domish
13from twisted.words.protocols.jabber import xmlstream
14import twisted.internet.protocol
15from twisted.internet import reactor
16
17from servicetest import (Event, unwrap)
18
19from gabbletest import (
20    make_connection, make_stream, XmppAuthenticator, XmppXmlStream,
21    disconnect_conn, GabbleAuthenticator)
22import constants as cs
23
24NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls'
25NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl'
26
27class BlockForeverTlsAuthenticator(GabbleAuthenticator):
28    """A TLS stream authenticator that is deliberately broken. It sends
29    <proceed/> to the client but then do nothing, so the TLS handshake will
30    not work. Useful for testing regression of bug #14341."""
31
32    def __init__(self, username, password):
33        GabbleAuthenticator.__init__(self, username, password)
34        self.username = username
35        self.password = password
36        self.authenticated = False
37
38    def streamStarted(self, root=None):
39        if root:
40            self.xmlstream.sid = root.getAttribute('id')
41
42        self.xmlstream.sendHeader()
43
44        features = domish.Element((xmlstream.NS_STREAMS, 'features'))
45        mechanisms = features.addElement((NS_XMPP_SASL, 'mechanisms'))
46        mechanism = mechanisms.addElement('mechanism', content='DIGEST-MD5')
47        starttls = features.addElement((NS_XMPP_TLS, 'starttls'))
48        starttls.addElement('required')
49        self.xmlstream.send(features)
50
51        self.xmlstream.addOnetimeObserver("/starttls", self.auth)
52
53    def auth(self, auth):
54        proceed = domish.Element((NS_XMPP_TLS, 'proceed'))
55        self.xmlstream.send(proceed)
56
57        return; # auth blocks
58
59        self.xmlstream.reset()
60        self.authenticated = True
61
62
63def test(q, bus, conn1, conn2, stream1, stream2):
64    # Connection 1
65    conn1.Connect()
66    q.expect('dbus-signal', signal='StatusChanged',
67            args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED])
68
69    # Connection 1 blocks because the fake jabber server behind conn1 does not
70    # proceed to the tls handshake. The second connection is independant and
71    # should work.
72
73    # Connection 2
74    conn2.Connect()
75    q.expect('dbus-signal', signal='StatusChanged',
76            args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED])
77    q.expect('stream-authenticated')
78    q.expect('dbus-signal', signal='PresencesChanged',
79        args=[{1L: (cs.PRESENCE_AVAILABLE, 'available', '')}])
80    q.expect('dbus-signal', signal='StatusChanged',
81            args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])
82
83    # Disconnection 2
84    disconnect_conn(q, conn2, stream2)
85
86if __name__ == '__main__':
87    queue = servicetest.IteratingEventQueue(None)
88    queue.verbose = (
89        os.environ.get('CHECK_TWISTED_VERBOSE', '') != ''
90        or '-v' in sys.argv)
91
92    bus = dbus.SessionBus()
93
94    params = {
95        'account': 'test1@localhost/Resource',
96        'password': 'pass',
97        'resource': 'Resource',
98        'server': 'localhost',
99        'port': dbus.UInt32(4242),
100        }
101    conn1, jid1 = make_connection(bus, queue.append, params)
102    authenticator = BlockForeverTlsAuthenticator('test1', 'pass')
103    stream1 = make_stream(queue.append, authenticator, protocol=XmppXmlStream)
104
105    factory = twisted.internet.protocol.Factory()
106    factory.protocol = lambda:stream1
107    port1 = reactor.listenTCP(4242, factory, interface='localhost')
108
109    params = {
110        'account': 'test2@localhost/Resource',
111        'password': 'pass',
112        'resource': 'Resource',
113        'server': 'localhost',
114        'port': dbus.UInt32(4343),
115        }
116    conn2, jid2 = make_connection(bus, queue.append, params)
117    authenticator = XmppAuthenticator('test2', 'pass')
118    stream2 = make_stream(queue.append, authenticator, protocol=XmppXmlStream)
119
120    factory = twisted.internet.protocol.Factory()
121    factory.protocol = lambda:stream2
122    port1 = reactor.listenTCP(4343, factory, interface='localhost')
123
124
125    bus.add_signal_receiver(
126        lambda *args, **kw:
127            queue.append(Event('dbus-signal',
128                               path=unwrap(kw['path']),
129                               signal=kw['member'], args=map(unwrap, args),
130                               interface=kw['interface'])),
131        None,       # signal name
132        None,       # interface
133        None,
134        path_keyword='path',
135        member_keyword='member',
136        interface_keyword='interface',
137        byte_arrays=True
138        )
139
140    try:
141        test(queue, bus, conn1, conn2, stream1, stream2)
142    finally:
143        try:
144            conn1.Disconnect()
145            conn2.Disconnect()
146        except dbus.DBusException, e:
147            pass
148
149