def test_auth_fail(self): handler = EventRecorder() settings = XMPPSettings({ u"username": u"user", u"password": u"bad", }) self.stream = StreamBase(u"jabber:client", None, [StreamSASLHandler(settings), handler], settings) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(AUTH_FEATURES) xml = self.wait(expect=re.compile(br".*(<auth.*</auth>)")) self.assertIsNotNone(xml) element = ElementTree.XML(xml) self.assertEqual(element.tag, "{urn:ietf:params:xml:ns:xmpp-sasl}auth") mech = element.get("mechanism") self.assertEqual(mech, "PLAIN") data = binascii.a2b_base64(element.text.encode("utf-8")) self.assertNotEqual(data, b"\000user\000secret") self.server.write( b"""<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <not-authorized/></failure>""") with self.assertRaises(SASLAuthenticationFailed): self.wait() self.assertFalse(self.stream.authenticated) self.server.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, DisconnectedEvent ])
def test_bind_no_resource(self): handler = AuthorizedEventHandler() handlers = [ResourceBindingHandler(), handler] processor = StanzaProcessor() processor.setup_stanza_handlers(handlers, "post-auth") self.stream = StreamBase(u"jabber:client", processor, handlers) processor.uplink = self.stream self.stream.me = JID("[email protected]") self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short(1) self.server.write(BIND_FEATURES) req_id = self.wait( 1, expect=re.compile(br".*<iq[^>]*id=[\"']([^\"']*)[\"']")) self.assertIsNotNone(req_id) req_id = req_id.decode("utf-8") self.server.write( BIND_GENERATED_RESPONSE.format(req_id).encode("utf-8")) self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, BindingResourceEvent, AuthorizedEvent, DisconnectedEvent ])
def test_parse_error(self): handler = IgnoreEventHandler() self.start_transport([handler]) self.stream = StreamBase(u"jabber:client", None, []) self.stream.receive(self.transport, self.addr[0]) self.client.write(C2S_CLIENT_STREAM_HEAD) self.wait_short(0.25) self.wait_short(0.25) self.client.write(b"</stream:test>") logger.debug("waiting for exception...") with self.assertRaises(StreamParseError): self.wait() logger.debug(" got it!") self.assertFalse(self.stream.is_connected()) self.wait_short(0.1) logger.debug("waiting for connection close...") self.client.wait(1) logger.debug(" done") self.assertTrue(self.client.eof) self.assertTrue(self.client.rdata.endswith(PARSE_ERROR_RESPONSE)) self.client.disconnect() logger.debug("final wait...") self.wait() logger.debug(" done") event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [StreamConnectedEvent, DisconnectedEvent])
def test_required_missing(self): """Test TLS required in settings, and missing on the server.""" self.start_server() settings = XMPPSettings({ u"starttls": True, u"tls_require": True, u"tls_cacert_file": os.path.join(DATA_DIR, "ca.pem"), }) handler = EventRecorder() handlers = [StreamTLSHandler(settings), handler] self.stream = StreamBase(u"jabber:client", None, handlers, settings) self.start_transport(handlers) self.stream.initiate(self.transport, to="server.example.org") self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(EMPTY_FEATURES) self.server.write(b"</stream:stream>") with self.assertRaises(TLSNegotiationFailed): self.wait() self.server.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, DisconnectedEvent ])
def test_stanza_receive(self): handler = IgnoreEventHandler() route = RecordingRoute() self.stream = StreamBase(u"jabber:client", route, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() logger.debug("-- waiting for connect") self.wait_short(0.25) self.wait_short(0.25) logger.debug("-- checking connected") self.assertTrue(self.stream.is_connected()) self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(b"<message><body>Test</body></message>") self.server.write(STREAM_TAIL) self.server.disconnect() self.wait(expect=re.compile(b".*(</stream:stream>)")) self.stream.disconnect() self.wait() self.assertEqual(route.sent, []) self.assertEqual(len(route.received), 1) stanza = route.received[0] self.assertIsInstance(stanza, Message) self.assertEqual(stanza.body, u"Test") event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent ])
def test_stanza_send(self): handler = IgnoreEventHandler() route = RecordingRoute() self.stream = StreamBase(u"jabber:client", route, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short(0.25) self.wait_short(0.25) self.assertTrue(self.stream.is_connected()) self.stream.send(Message(to_jid=JID(u"*****@*****.**"), body=u"Test")) xml = self.wait(expect=re.compile(b".*(<message.*</message>)")) self.assertIsNotNone(xml) if b"xmlns" not in xml: xml = xml.replace(b"<message", b"<message xmlns='jabber:client'") element = XML(xml) stanza = Message(element) self.assertEqual(stanza.body, u"Test") self.stream.disconnect() self.server.write(STREAM_TAIL) self.server.disconnect() self.wait() self.assertEqual(route.sent, []) self.assertEqual(route.received, []) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent ])
def test_parse_error(self): handler = IgnoreEventHandler() self.stream = StreamBase(u"jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short() self.server.write(b"</stream:test>") with self.assertRaises(StreamParseError): logger.debug("-- WAIT start") self.wait() logger.debug("-- WAIT end") self.assertFalse(self.stream.is_connected()) self.wait_short() self.server.wait(1) self.assertTrue(self.server.eof) self.assertTrue(self.server.rdata.endswith(PARSE_ERROR_RESPONSE)) self.server.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent ])
def test_bind_resource(self): handler = EventRecorder() handlers = [ResourceBindingHandler(), handler] processor = StanzaProcessor() self.start_transport(handlers) self.stream = StreamBase(u"jabber:client", processor, handlers) processor.uplink = self.stream self.stream.receive(self.transport, self.addr[0]) self.stream.set_peer_authenticated(JID("[email protected]")) processor.setup_stanza_handlers(handlers, "post-auth") self.client.write(C2S_CLIENT_STREAM_HEAD) features = self.wait( expect=re.compile(br".*<stream:features>" br"(.*<bind.*urn:ietf:params:xml:ns:xmpp-bind.*)" br"</stream:features>")) self.assertIsNotNone(features) self.client.write(BIND_PROVIDED_REQUEST) resource = self.wait(expect=re.compile( br".*<iq.*id=(?:\"42\"|'42').*>" br"<bind.*<jid>[email protected]/(.*)</jid>.*</bind>")) self.assertEqual(resource, b"Provided") self.client.write(STREAM_TAIL) self.client.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ AuthenticatedEvent, StreamConnectedEvent, AuthorizedEvent, DisconnectedEvent ])
class TestBindingInitiator(InitiatorSelectTestCase): def test_bind_no_resource(self): handler = AuthorizedEventHandler() handlers = [ResourceBindingHandler(), handler] processor = StanzaProcessor() processor.setup_stanza_handlers(handlers, "post-auth") self.stream = StreamBase(u"jabber:client", processor, handlers) processor.uplink = self.stream self.stream.me = JID("[email protected]") self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short(1) self.server.write(BIND_FEATURES) req_id = self.wait(1, expect = re.compile(br".*<iq[^>]*id=[\"']([^\"']*)[\"']")) self.assertIsNotNone(req_id) req_id = req_id.decode("utf-8") self.server.write(BIND_GENERATED_RESPONSE.format(req_id) .encode("utf-8")) self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, BindingResourceEvent, AuthorizedEvent, DisconnectedEvent]) def test_bind(self): handler = AuthorizedEventHandler() handlers = [ResourceBindingHandler(), handler] processor = StanzaProcessor() processor.setup_stanza_handlers(handlers, "post-auth") self.stream = StreamBase(u"jabber:client", processor, handlers, XMPPSettings({"resource": "Provided"})) processor.uplink = self.stream self.stream.me = JID("[email protected]") self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short(1) self.server.write(BIND_FEATURES) req_id = self.wait(1, expect = re.compile(br".*<iq[^>]*id=[\"']([^\"']*)[\"'].*" br"<resource>Provided</resource>")) self.assertIsNotNone(req_id) req_id = req_id.decode("utf-8") self.server.write(BIND_PROVIDED_RESPONSE.format(req_id).encode("utf-8")) self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, BindingResourceEvent, AuthorizedEvent, DisconnectedEvent])
def test_connect_close(self): handler = JustConnectEventHandler() self.stream = StreamBase(u"jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, DisconnectedEvent])
def test_stream_connect_disconnect(self): handler = JustStreamConnectEventHandler() self.start_transport([handler]) self.stream = StreamBase(u"jabber:client", None, []) self.stream.receive(self.transport, self.addr[0]) self.client.write(C2S_CLIENT_STREAM_HEAD) self.wait_short(0.25) self.wait_short(0.25) self.client.write(STREAM_TAIL) self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [StreamConnectedEvent, DisconnectedEvent])
def test_stanza_send(self): handler = IgnoreEventHandler() route = RecordingRoute() self.stream = StreamBase("jabber:client", route, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short(0.25) self.wait_short(0.25) self.assertTrue(self.stream.is_connected()) self.stream.send(Message(to_jid = JID("*****@*****.**"), body = "Test")) xml = self.wait(expect = re.compile(b".*(<message.*</message>)")) self.assertIsNotNone(xml) if b"xmlns" not in xml: xml = xml.replace(b"<message", b"<message xmlns='jabber:client'") element = XML(xml) stanza = Message(element) self.assertEqual(stanza.body, "Test") self.stream.disconnect() self.server.write(STREAM_TAIL) self.server.disconnect() self.wait() self.assertEqual(route.sent, []) self.assertEqual(route.received, []) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent])
def test_stanza_receive(self): handler = IgnoreEventHandler() route = RecordingRoute() self.stream = StreamBase("jabber:client", route, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() logger.debug("-- waiting for connect") self.wait_short(0.25) self.wait_short(0.25) logger.debug("-- checking connected") self.assertTrue(self.stream.is_connected()) self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(b"<message><body>Test</body></message>") self.server.write(STREAM_TAIL) self.server.disconnect() self.wait(expect = re.compile(b".*(</stream:stream>)")) self.stream.disconnect() self.wait() self.assertEqual(route.sent, []) self.assertEqual(len(route.received), 1) stanza = route.received[0] self.assertIsInstance(stanza, Message) self.assertEqual(stanza.body, "Test") event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent])
def test_parse_error(self): handler = IgnoreEventHandler() self.start_transport([handler]) self.stream = StreamBase("jabber:client", None, []) self.stream.receive(self.transport, self.addr[0]) self.client.write(C2S_CLIENT_STREAM_HEAD) self.wait_short(0.25) self.wait_short(0.25) self.client.write(b"</stream:test>") logger.debug("waiting for exception...") with self.assertRaises(StreamParseError): self.wait() logger.debug(" got it!") self.assertFalse(self.stream.is_connected()) self.wait_short(0.1) logger.debug("waiting for connection close...") self.client.wait(1) logger.debug(" done") self.assertTrue(self.client.eof) self.assertTrue(self.client.rdata.endswith(PARSE_ERROR_RESPONSE)) self.client.disconnect() logger.debug("final wait...") self.wait() logger.debug(" done") event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [StreamConnectedEvent, DisconnectedEvent])
def test_auth_fail(self): handler = EventRecorder() settings = XMPPSettings({ "username": "******", "password": "******", }) self.stream = StreamBase("jabber:client", None, [StreamSASLHandler(settings), handler], settings) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(AUTH_FEATURES) xml = self.wait(expect = re.compile(br".*(<auth.*</auth>)")) self.assertIsNotNone(xml) element = ElementTree.XML(xml) self.assertEqual(element.tag, "{urn:ietf:params:xml:ns:xmpp-sasl}auth") mech = element.get("mechanism") self.assertEqual(mech, "PLAIN") data = binascii.a2b_base64(element.text.encode("utf-8")) self.assertNotEqual(data, b"\000user\000secret") self.server.write(b"""<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <not-authorized/></failure>""") with self.assertRaises(SASLAuthenticationFailed): self.wait() self.assertFalse(self.stream.authenticated) self.server.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, DisconnectedEvent])
def test_required_missing(self): """Test TLS required in settings, and missing on the server.""" self.start_server() settings = XMPPSettings({ "starttls": True, "tls_require": True, "tls_cacert_file": os.path.join(DATA_DIR, "ca.pem"), }) handler = EventRecorder() handlers = [StreamTLSHandler(settings), handler] self.stream = StreamBase("jabber:client", None, handlers, settings) self.start_transport(handlers) self.stream.initiate(self.transport, to = "server.example.org") self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(EMPTY_FEATURES) self.server.write(b"</stream:stream>") with self.assertRaises(TLSNegotiationFailed): self.wait() self.server.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, DisconnectedEvent])
def test_bind_resource(self): handler = EventRecorder() handlers = [ResourceBindingHandler(), handler] processor = StanzaProcessor() self.start_transport(handlers) self.stream = StreamBase(u"jabber:client", processor, handlers) processor.uplink = self.stream self.stream.receive(self.transport, self.addr[0]) self.stream.set_peer_authenticated(JID("[email protected]")) processor.setup_stanza_handlers(handlers, "post-auth") self.client.write(C2S_CLIENT_STREAM_HEAD) features = self.wait( expect = re.compile(br".*<stream:features>" br"(.*<bind.*urn:ietf:params:xml:ns:xmpp-bind.*)" br"</stream:features>")) self.assertIsNotNone(features) self.client.write(BIND_PROVIDED_REQUEST) resource = self.wait( expect = re.compile(br".*<iq.*id=(?:\"42\"|'42').*>" br"<bind.*<jid>[email protected]/(.*)</jid>.*</bind>")) self.assertEqual(resource, b"Provided") self.client.write(STREAM_TAIL) self.client.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [AuthenticatedEvent, StreamConnectedEvent, AuthorizedEvent, DisconnectedEvent])
def test_enabled_required(self): """Test TLS enabled in settings, and required on the server.""" self.start_server() settings = XMPPSettings({ u"starttls": True, u"tls_cacert_file": os.path.join(DATA_DIR, "ca.pem"), }) handler = EventRecorder() handlers = [StreamTLSHandler(settings), handler] self.stream = StreamBase(u"jabber:client", None, handlers, settings) self.start_transport(handlers) self.stream.initiate(self.transport, to="server.example.org") self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(TLS_REQUIRED_FEATURES) xml = self.wait(expect=re.compile(br".*(<starttls.*/>)")) self.assertIsNotNone(xml) element = XML(xml) self.assertEqual(element.tag, "{urn:ietf:params:xml:ns:xmpp-tls}starttls") self.server.write(PROCEED) self.server.starttls( self.server.sock, keyfile=os.path.join(DATA_DIR, "server-key.pem"), certfile=os.path.join(DATA_DIR, "server.pem"), server_side=True, ca_certs=os.path.join(DATA_DIR, "ca.pem"), ) stream_start = self.wait(expect=re.compile(br"(<stream:stream[^>]*>)")) self.assertIsNotNone(stream_start) self.assertTrue(self.stream.tls_established) self.stream.disconnect() self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(EMPTY_FEATURES) self.server.write(b"</stream:stream>") self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, TLSConnectingEvent, TLSConnectedEvent, StreamRestartedEvent, GotFeaturesEvent, DisconnectedEvent ])
def test_auth(self): handler = EventRecorder() self.start_transport([handler]) settings = XMPPSettings({ u"user_passwords": { u"user": u"secret", }, u"sasl_mechanisms": ["SCRAM-SHA-1", "PLAIN"], }) self.stream = StreamBase(u"jabber:client", None, [StreamSASLHandler(settings), handler], settings) self.stream.receive(self.transport, self.addr[0]) self.client.write(C2S_CLIENT_STREAM_HEAD) xml = self.wait( expect=re.compile(br".*<stream:features>(.*)</stream:features>")) self.assertIsNotNone(xml) element = ElementTree.XML(xml) self.assertEqual(element.tag, "{urn:ietf:params:xml:ns:xmpp-sasl}mechanisms") self.assertEqual(element[0].tag, "{urn:ietf:params:xml:ns:xmpp-sasl}mechanism") self.assertEqual(element[0].text, "SCRAM-SHA-1") self.assertEqual(element[1].tag, "{urn:ietf:params:xml:ns:xmpp-sasl}mechanism") self.assertEqual(element[1].text, "PLAIN") response = base64.standard_b64encode(b"\000user\000secret") self.client.write( PLAIN_AUTH.format(response.decode("utf-8")).encode("utf-8")) xml = self.wait(expect=re.compile(br".*(<success.*>)")) self.assertIsNotNone(xml) self.client.write(C2S_CLIENT_STREAM_HEAD) xml = self.wait(expect=re.compile(br".*(<stream:stream.*>)")) self.assertIsNotNone(xml) self.assertTrue(self.stream.peer_authenticated) self.client.write(b"</stream:stream>") self.client.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ StreamConnectedEvent, AuthenticatedEvent, StreamRestartedEvent, DisconnectedEvent ])
def test_stream_connect_disconnect(self): handler = JustStreamConnectEventHandler() self.stream = StreamBase(u"jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.wait_short(0.25) self.wait_short(0.25) self.assertTrue(self.stream.is_connected()) self.server.write(C2S_SERVER_STREAM_HEAD) self.wait(expect=re.compile(b".*(</stream:stream>)")) self.server.write(STREAM_TAIL) self.server.disconnect() self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent ])
def test_connect_close(self): handler = JustConnectEventHandler() self.stream = StreamBase("jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, DisconnectedEvent])
def test_auth(self): handler = EventRecorder() settings = XMPPSettings({ u"username": u"user", u"password": u"secret", }) self.stream = StreamBase(u"jabber:client", None, [StreamSASLHandler(settings), handler], settings) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(AUTH_FEATURES) xml = self.wait(expect=re.compile(br".*(<auth.*</auth>)")) self.assertIsNotNone(xml) element = ElementTree.XML(xml) self.assertEqual(element.tag, "{urn:ietf:params:xml:ns:xmpp-sasl}auth") mech = element.get("mechanism") self.assertEqual(mech, "PLAIN") data = binascii.a2b_base64(element.text.encode("utf-8")) self.assertEqual(data, b"\000user\000secret") self.server.rdata = b"" self.server.write( b"<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>") stream_start = self.wait(expect=re.compile(br"(<stream:stream[^>]*>)")) self.assertIsNotNone(stream_start) self.assertTrue(self.stream.authenticated) self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(BIND_FEATURES) self.server.write(b"</stream:stream>") self.server.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, AuthenticatedEvent, StreamRestartedEvent, GotFeaturesEvent, DisconnectedEvent ])
def test_stream_connect_disconnect(self): handler = JustStreamConnectEventHandler() self.start_transport([handler]) self.stream = StreamBase("jabber:client", None, []) self.stream.receive(self.transport, self.addr[0]) self.client.write(C2S_CLIENT_STREAM_HEAD) self.wait_short(0.25) self.wait_short(0.25) self.client.write(STREAM_TAIL) self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [StreamConnectedEvent, DisconnectedEvent])
def test_stream_connect_disconnect(self): handler = JustStreamConnectEventHandler() self.stream = StreamBase("jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.wait_short(0.25) self.wait_short(0.25) self.assertTrue(self.stream.is_connected()) self.server.write(C2S_SERVER_STREAM_HEAD) self.wait(expect = re.compile(b".*(</stream:stream>)")) self.server.write(STREAM_TAIL) self.server.disconnect() self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent])
def __init__(self, transport, avatars): StanzaProcessor.__init__(self) logger.debug('-- New connection') self.avatars = avatars self.settings = XMPPSettings() self.handlers = [self, ResourceBindingHandler(self.settings)] self.stream = StreamBase(u"jabber:client", self, self.handlers, self.settings) self.stream.set_authenticated(JID(domain='tlen.pl')) self.tlen = None self.transport = transport self.stream.receive(self.transport, 'tlen.pl') self.uplink = self.stream self.stream.set_authenticated(JID(domain='tlen.pl'))
def test_enabled_required(self): """Test TLS enabled in settings, and required on the server.""" self.start_server() settings = XMPPSettings({ "starttls": True, "tls_cacert_file": os.path.join(DATA_DIR, "ca.pem"), }) handler = EventRecorder() handlers = [StreamTLSHandler(settings), handler] self.stream = StreamBase("jabber:client", None, handlers, settings) self.start_transport(handlers) self.stream.initiate(self.transport, to = "server.example.org") self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(TLS_REQUIRED_FEATURES) xml = self.wait(expect = re.compile(br".*(<starttls.*/>)")) self.assertIsNotNone(xml) element = XML(xml) self.assertEqual(element.tag, "{urn:ietf:params:xml:ns:xmpp-tls}starttls") self.server.write(PROCEED) self.server.starttls(self.server.sock, keyfile = os.path.join(DATA_DIR, "server-key.pem"), certfile = os.path.join(DATA_DIR, "server.pem"), server_side = True, ca_certs = os.path.join(DATA_DIR, "ca.pem"), ) stream_start = self.wait(expect = re.compile( br"(<stream:stream[^>]*>)")) self.assertIsNotNone(stream_start) self.assertTrue(self.stream.tls_established) self.stream.disconnect() self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(EMPTY_FEATURES) self.server.write(b"</stream:stream>") self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, TLSConnectingEvent, TLSConnectedEvent, StreamRestartedEvent, GotFeaturesEvent, DisconnectedEvent])
def test_auth(self): handler = EventRecorder() self.start_transport([handler]) settings = XMPPSettings({ "user_passwords": { "user": "******", }, "sasl_mechanisms": ["SCRAM-SHA-1", "PLAIN"], }) self.stream = StreamBase("jabber:client", None, [StreamSASLHandler(settings), handler], settings) self.stream.receive(self.transport, self.addr[0]) self.client.write(C2S_CLIENT_STREAM_HEAD) xml = self.wait(expect = re.compile( br".*<stream:features>(.*)</stream:features>")) self.assertIsNotNone(xml) element = ElementTree.XML(xml) self.assertEqual(element.tag, "{urn:ietf:params:xml:ns:xmpp-sasl}mechanisms") self.assertEqual(element[0].tag, "{urn:ietf:params:xml:ns:xmpp-sasl}mechanism") self.assertEqual(element[0].text, "SCRAM-SHA-1") self.assertEqual(element[1].tag, "{urn:ietf:params:xml:ns:xmpp-sasl}mechanism") self.assertEqual(element[1].text, "PLAIN") response = base64.standard_b64encode(b"\000user\000secret") self.client.write(PLAIN_AUTH.format(response.decode("utf-8")) .encode("utf-8")) xml = self.wait(expect = re.compile(br".*(<success.*>)")) self.assertIsNotNone(xml) self.client.write(C2S_CLIENT_STREAM_HEAD) xml = self.wait(expect = re.compile(br".*(<stream:stream.*>)")) self.assertIsNotNone(xml) self.assertTrue(self.stream.peer_authenticated) self.client.write(b"</stream:stream>") self.client.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ StreamConnectedEvent, AuthenticatedEvent, StreamRestartedEvent, DisconnectedEvent])
def test_auth(self): handler = EventRecorder() settings = XMPPSettings({ "username": "******", "password": "******", }) self.stream = StreamBase("jabber:client", None, [StreamSASLHandler(settings), handler], settings) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(AUTH_FEATURES) xml = self.wait(expect = re.compile(br".*(<auth.*</auth>)")) self.assertIsNotNone(xml) element = ElementTree.XML(xml) self.assertEqual(element.tag, "{urn:ietf:params:xml:ns:xmpp-sasl}auth") mech = element.get("mechanism") self.assertEqual(mech, "PLAIN") data = binascii.a2b_base64(element.text.encode("utf-8")) self.assertEqual(data, b"\000user\000secret") self.server.rdata = b"" self.server.write( b"<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>") stream_start = self.wait(expect = re.compile( br"(<stream:stream[^>]*>)")) self.assertIsNotNone(stream_start) self.assertTrue(self.stream.authenticated) self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(BIND_FEATURES) self.server.write(b"</stream:stream>") self.server.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, GotFeaturesEvent, AuthenticatedEvent, StreamRestartedEvent, GotFeaturesEvent, DisconnectedEvent])
def test_parse_error(self): handler = IgnoreEventHandler() self.stream = StreamBase("jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short() self.server.write(b"</stream:test>") with self.assertRaises(StreamParseError): logger.debug("-- WAIT start") self.wait() logger.debug("-- WAIT end") self.assertFalse(self.stream.is_connected()) self.wait_short() self.server.wait(1) self.assertTrue(self.server.eof) self.assertTrue(self.server.rdata.endswith(PARSE_ERROR_RESPONSE)) self.server.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent])
class Server(StanzaProcessor, EventHandler, TimeoutHandler, XMPPFeatureHandler): """ The XMPP end of the proxy. Handles local XMPP client connections. Forwards stanzas from the client to the Tlen server, and the other way around. Stanzas are adapted to achieve maximum satisfaction on both sides ;) """ def __init__(self, transport, avatars): StanzaProcessor.__init__(self) logger.debug('-- New connection') self.avatars = avatars self.settings = XMPPSettings() self.handlers = [self, ResourceBindingHandler(self.settings)] self.stream = StreamBase(u"jabber:client", self, self.handlers, self.settings) self.stream.set_authenticated(JID(domain='tlen.pl')) self.tlen = None self.transport = transport self.stream.receive(self.transport, 'tlen.pl') self.uplink = self.stream self.stream.set_authenticated(JID(domain='tlen.pl')) @event_handler(AuthenticatedEvent) def authenticated(self, event): self.setup_stanza_handlers(self.handlers, 'post-auth') @event_handler(DisconnectedEvent) def disconnected(self, event): logger.debug('Client disconnected') if self.tlen: self.tlen.close() self.tlen = None return QUIT # Stanza handlers. Except for authentication stuff, they # push everything to the TlenClient. Anything that needs # fixing up before being sent to the server is performed # in TlenClient.send() @iq_get_stanza_handler(XMLPayload, '{jabber:iq:auth}query') def handle_auth_get(self, stanza): logger.debug('auth get %s', stanza.serialize()) resp = stanza.make_result_response() query = ElementTree.Element('{jabber:iq:auth}query') for x in ('username', 'password', 'resource'): query.append(ElementTree.Element('{jabber:iq:auth}' + x)) resp.add_payload(query) return resp @iq_set_stanza_handler(XMLPayload, '{jabber:iq:auth}query') def handle_auth_set(self, stanza): """ This is the part that actually starts the Tlen end of the proxy. We're expecting PLAIN XMPP authentication here, so we can grab the auth data and log in to Tlen.pl, on behalf of the user. """ query = stanza.get_payload(None, 'query').as_xml() # XXX: Assuming the client will use legacy auth username = query.findtext('{jabber:iq:auth}username') password = query.findtext('{jabber:iq:auth}password') resource = query.findtext('{jabber:iq:auth}resource') if not username or not password: # XXX return stanza.make_error_response('bad-request') self.tlen = TlenStream(JID(username, 'tlen.pl'), password, resource, self.avatars) self.tlen.uplink = self.stream self.tlen.start() if self.tlen.wait_for_auth(): return stanza.make_result_response() else: # XXX: is this code ok? return stanza.make_error_response('not-authorized') @iq_get_stanza_handler(XMLPayload, '{jabber:iq:roster}query') def handle_roster_get(self, stanza): self.tlen.send(stanza) @iq_set_stanza_handler(XMLPayload, '{jabber:iq:roster}query') def handle_roster_set(self, stanza): self.tlen.send(stanza) @iq_get_stanza_handler(XMLPayload, DISCO_INFO_NS_QNP + 'query') def handle_disco_info_get(self, stanza): """ Handle feature discovery on behalf of a @tlen.pl user. """ logger.debug('DISCO INFO get, jid=%s', stanza.to_jid) resp = stanza.make_result_response() # Target is client entity query = ElementTree.Element(DISCO_INFO_NS_QNP + 'query') if stanza.to_jid.local: logger.debug('disco to client') query.append(ElementTree.Element(DISCO_INFO_NS_QNP + 'feature', var=CHATSTATES_NS)) else: query.append(ElementTree.Element(DISCO_INFO_NS_QNP + 'feature', var='urn:xmpp:blocking')) resp.add_payload(query) return resp @iq_get_stanza_handler(XMLPayload, DISCO_ITEMS_NS_QNP + 'query') def handle_disco_items_get(self, stanza): response = stanza.make_result_response() query = ElementTree.Element(DISCO_ITEMS_NS_QNP + 'query') response.add_payload(query) return response @iq_get_stanza_handler(XMLPayload, '{vcard-temp}vCard') def handle_vcard_get(self, iq): logger.debug('vCard: %s', iq) job = jobs.VCardGet(self) return job.perform(iq) @presence_stanza_handler() def handle_presence(self, stanza): logger.debug('handle presence=%s', stanza.serialize()) self.tlen.send(stanza) @presence_stanza_handler('subscribed') def handle_presence_subscribed(self, stanza): logger.debug('handle presence subscr=%s', stanza.serialize()) self.tlen.send(stanza) @presence_stanza_handler('subscribe') def handle_presence_subscribe(self, stanza): logger.debug('handle presence subscr=%s', stanza.serialize()) self.tlen.send(stanza) @presence_stanza_handler('unsubscribe') def handle_presence_unsubscribe(self, stanza): logger.debug('handle presence subscr=%s', stanza.serialize()) self.tlen.send(stanza) @presence_stanza_handler('unsubscribed') def handle_presence_unsubscribed(self, stanza): logger.debug('handle presence subscr=%s', stanza.serialize()) self.tlen.send(stanza) @message_stanza_handler() def handle_message(self, stanza): self.tlen.send(stanza)
class TestInitiatorSelect(InitiatorSelectTestCase): def test_connect_close(self): handler = JustConnectEventHandler() self.stream = StreamBase(u"jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, DisconnectedEvent]) def test_stream_connect_disconnect(self): handler = JustStreamConnectEventHandler() self.stream = StreamBase(u"jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.wait_short(0.25) self.wait_short(0.25) self.assertTrue(self.stream.is_connected()) self.server.write(C2S_SERVER_STREAM_HEAD) self.wait(expect=re.compile(b".*(</stream:stream>)")) self.server.write(STREAM_TAIL) self.server.disconnect() self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent ]) def test_parse_error(self): handler = IgnoreEventHandler() self.stream = StreamBase(u"jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short() self.server.write(b"</stream:test>") with self.assertRaises(StreamParseError): logger.debug("-- WAIT start") self.wait() logger.debug("-- WAIT end") self.assertFalse(self.stream.is_connected()) self.wait_short() self.server.wait(1) self.assertTrue(self.server.eof) self.assertTrue(self.server.rdata.endswith(PARSE_ERROR_RESPONSE)) self.server.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent ]) def test_stanza_send(self): handler = IgnoreEventHandler() route = RecordingRoute() self.stream = StreamBase(u"jabber:client", route, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short(0.25) self.wait_short(0.25) self.assertTrue(self.stream.is_connected()) self.stream.send(Message(to_jid=JID(u"*****@*****.**"), body=u"Test")) xml = self.wait(expect=re.compile(b".*(<message.*</message>)")) self.assertIsNotNone(xml) if b"xmlns" not in xml: xml = xml.replace(b"<message", b"<message xmlns='jabber:client'") element = XML(xml) stanza = Message(element) self.assertEqual(stanza.body, u"Test") self.stream.disconnect() self.server.write(STREAM_TAIL) self.server.disconnect() self.wait() self.assertEqual(route.sent, []) self.assertEqual(route.received, []) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent ]) def test_stanza_receive(self): handler = IgnoreEventHandler() route = RecordingRoute() self.stream = StreamBase(u"jabber:client", route, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() logger.debug("-- waiting for connect") self.wait_short(0.25) self.wait_short(0.25) logger.debug("-- checking connected") self.assertTrue(self.stream.is_connected()) self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(b"<message><body>Test</body></message>") self.server.write(STREAM_TAIL) self.server.disconnect() self.wait(expect=re.compile(b".*(</stream:stream>)")) self.stream.disconnect() self.wait() self.assertEqual(route.sent, []) self.assertEqual(len(route.received), 1) stanza = route.received[0] self.assertIsInstance(stanza, Message) self.assertEqual(stanza.body, u"Test") event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent ])
class TestInitiatorSelect(InitiatorSelectTestCase): def test_connect_close(self): handler = JustConnectEventHandler() self.stream = StreamBase("jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, DisconnectedEvent]) def test_stream_connect_disconnect(self): handler = JustStreamConnectEventHandler() self.stream = StreamBase("jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.wait_short(0.25) self.wait_short(0.25) self.assertTrue(self.stream.is_connected()) self.server.write(C2S_SERVER_STREAM_HEAD) self.wait(expect = re.compile(b".*(</stream:stream>)")) self.server.write(STREAM_TAIL) self.server.disconnect() self.wait() self.assertFalse(self.stream.is_connected()) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent]) def test_parse_error(self): handler = IgnoreEventHandler() self.stream = StreamBase("jabber:client", None, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short() self.server.write(b"</stream:test>") with self.assertRaises(StreamParseError): logger.debug("-- WAIT start") self.wait() logger.debug("-- WAIT end") self.assertFalse(self.stream.is_connected()) self.wait_short() self.server.wait(1) self.assertTrue(self.server.eof) self.assertTrue(self.server.rdata.endswith(PARSE_ERROR_RESPONSE)) self.server.disconnect() self.wait() event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent]) def test_stanza_send(self): handler = IgnoreEventHandler() route = RecordingRoute() self.stream = StreamBase("jabber:client", route, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() self.server.write(C2S_SERVER_STREAM_HEAD) self.wait_short(0.25) self.wait_short(0.25) self.assertTrue(self.stream.is_connected()) self.stream.send(Message(to_jid = JID("*****@*****.**"), body = "Test")) xml = self.wait(expect = re.compile(b".*(<message.*</message>)")) self.assertIsNotNone(xml) if b"xmlns" not in xml: xml = xml.replace(b"<message", b"<message xmlns='jabber:client'") element = XML(xml) stanza = Message(element) self.assertEqual(stanza.body, "Test") self.stream.disconnect() self.server.write(STREAM_TAIL) self.server.disconnect() self.wait() self.assertEqual(route.sent, []) self.assertEqual(route.received, []) event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent]) def test_stanza_receive(self): handler = IgnoreEventHandler() route = RecordingRoute() self.stream = StreamBase("jabber:client", route, []) self.start_transport([handler]) self.stream.initiate(self.transport) self.connect_transport() logger.debug("-- waiting for connect") self.wait_short(0.25) self.wait_short(0.25) logger.debug("-- checking connected") self.assertTrue(self.stream.is_connected()) self.server.write(C2S_SERVER_STREAM_HEAD) self.server.write(b"<message><body>Test</body></message>") self.server.write(STREAM_TAIL) self.server.disconnect() self.wait(expect = re.compile(b".*(</stream:stream>)")) self.stream.disconnect() self.wait() self.assertEqual(route.sent, []) self.assertEqual(len(route.received), 1) stanza = route.received[0] self.assertIsInstance(stanza, Message) self.assertEqual(stanza.body, "Test") event_classes = [e.__class__ for e in handler.events_received] self.assertEqual(event_classes, [ConnectingEvent, ConnectedEvent, StreamConnectedEvent, DisconnectedEvent])