def test_bad_anonymous(self):
        # do not allow anonymous and signature is not good
        context = BaseContext()
        context.logger = logging.getLogger(__name__)
        context.config = {
            'auth': {
                'puk-file':
                os.path.join(os.path.dirname(os.path.realpath(__file__)),
                             "passwd"),
                'allow-only-registered':
                False
            }
        }
        s = Session()
        s.client_id = "client_using_secp256k1"
        # secp256k1 public key from int(hashlib.sha256(b"other secret").digets())
        # puk = '02d3a9b4022ab24b9218ae3290d2cbecf6d773ef70769afe9f15e7055a79cc90c4'
        # prk = 'fffc49122308b5e5666e6874ff4535d5a0e3f270a3a7545703c59da25378cbb3'
        s.username = "******"
        prk = binascii.unhexlify(
            "fffc49122308b5e5666e6874ff4535d5a0e3f270a3a7545703c59da25378cbb3")
        msg = schnorr.hash_sha256(datetime.datetime.utcnow().isoformat()[:18] +
                                  s.client_id[1:])
        s.password = binascii.hexlify(schnorr.sign(msg, prk))

        auth_plugin = EcdsaAuthPlugin(context)
        ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
        self.assertFalse(ret)
    def test_bad_signature(self):
        # do not allow anonymous and signature is not good
        context = BaseContext()
        context.logger = logging.getLogger(__name__)
        context.config = {
            'auth': {
                'puk-file':
                os.path.join(os.path.dirname(os.path.realpath(__file__)),
                             "passwd"),
                'allow-only-registered':
                True
            }
        }
        s = Session()
        s.client_id = "client_using_secp256k1"
        # secp256k1 public key from int(hashlib.sha256(b"secret").digets())
        # puk = '030cfbf62534dfa5f32e37145b27d2875c1a1ecf884e39f0b098e962acc7aeaaa7'
        # prk = '2c495f4933631f014d93f059c15b03bac6eaaead53a675e09574c4bcccab09d6'
        s.username = "******"  # the puk actually
        prk = binascii.unhexlify(
            "2c495f4933631f014d93f059c15b03bac6eaaead53a675e09574c4bcccab09d6")
        msg = schnorr.hash_sha256(
            datetime.datetime.utcnow().isoformat()[:18] + s.client_id[1:]
        )  # remove first char of client_id to generate a bad signature
        s.password = binascii.hexlify(schnorr.sign(msg, prk))

        auth_plugin = EcdsaAuthPlugin(context)
        ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
        self.assertFalse(ret)
Example #3
0
 async def coro():
     s = Session(None)
     s.username = "******"
     s.password = "******"
     auth_plugin = FileAuthPlugin(context)
     ret = await auth_plugin.authenticate(session=s)
     self.assertFalse(ret)
Example #4
0
 def test_allow_nonanonymous(self):
     context = BaseContext()
     context.logger = logging.getLogger(__name__)
     context.config = {'auth': {'allow-anonymous': False}}
     s = Session()
     s.username = "******"
     auth_plugin = AnonymousAuthPlugin(context)
     ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
     self.assertTrue(ret)
Example #5
0
 def test_allow_anonymous(self):
     context = BaseContext()
     context.logger = logging.getLogger(__name__)
     context.config = {"auth": {"allow-anonymous": True}}
     s = Session()
     s.username = ""
     auth_plugin = AnonymousAuthPlugin(context)
     ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
     assert ret
 def test_allow_nonanonymous(self):
     context = BaseContext()
     context.logger = logging.getLogger(__name__)
     context.config = {
         'auth': {
             'allow-anonymous': False
         }
     }
     s = Session()
     s.username = "******"
     auth_plugin = AnonymousAuthPlugin(context)
     ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
     self.assertTrue(ret)
 def test_unknown_password(self):
     context = BaseContext()
     context.logger = logging.getLogger(__name__)
     context.config = {
         'auth': {
             'password-file': os.path.join(os.path.dirname(os.path.realpath(__file__)), "passwd")
         }
     }
     s = Session()
     s.username = "******"
     s.password = "******"
     auth_plugin = FileAuthPlugin(context)
     ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
     self.assertFalse(ret)
Example #8
0
 def test_allow(self):
     context = BaseContext()
     context.logger = logging.getLogger(__name__)
     context.config = {
         "auth": {
             "password-file":
             os.path.join(os.path.dirname(os.path.realpath(__file__)),
                          "passwd")
         }
     }
     s = Session()
     s.username = "******"
     s.password = "******"
     auth_plugin = FileAuthPlugin(context)
     ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
     self.assertTrue(ret)
Example #9
0
 def test_unknown_password(self):
     context = BaseContext()
     context.logger = logging.getLogger(__name__)
     context.config = {
         'auth': {
             'password-file':
             os.path.join(os.path.dirname(os.path.realpath(__file__)),
                          "passwd")
         }
     }
     s = Session()
     s.username = "******"
     s.password = "******"
     auth_plugin = FileAuthPlugin(context)
     ret = self.loop.run_until_complete(auth_plugin.authenticate(session=s))
     self.assertFalse(ret)
Example #10
0
    def test_publish_qos2(self):
        @asyncio.coroutine
        def server_mock(reader, writer):
            try:
                packet = yield from PublishPacket.from_stream(reader)
                self.assertEqual(packet.topic_name, '/topic')
                self.assertEqual(packet.qos, QOS_2)
                self.assertIsNotNone(packet.packet_id)
                self.assertIn(packet.packet_id, self.session.inflight_out)
                self.assertIn(packet.packet_id, self.handler._pubrec_waiters)
                pubrec = PubrecPacket.build(packet.packet_id)
                yield from pubrec.to_stream(writer)

                pubrel = yield from PubrelPacket.from_stream(reader)
                self.assertIn(packet.packet_id, self.handler._pubcomp_waiters)
                pubcomp = PubcompPacket.build(packet.packet_id)
                yield from pubcomp.to_stream(writer)
            except Exception as ae:
                future.set_exception(ae)

        @asyncio.coroutine
        def test_coro():
            try:
                reader, writer = yield from asyncio.open_connection(
                    '127.0.0.1', 8888, loop=self.loop)
                reader_adapted, writer_adapted = adapt(reader, writer)
                self.handler = ProtocolHandler(self.plugin_manager,
                                               loop=self.loop)
                self.handler.attach(self.session, reader_adapted,
                                    writer_adapted)
                yield from self.start_handler(self.handler, self.session)
                message = yield from self.handler.mqtt_publish(
                    '/topic', b'test_data', QOS_2, False)
                self.assertIsInstance(message, OutgoingApplicationMessage)
                self.assertIsNotNone(message.publish_packet)
                self.assertIsNone(message.puback_packet)
                self.assertIsNotNone(message.pubrec_packet)
                self.assertIsNotNone(message.pubrel_packet)
                self.assertIsNotNone(message.pubcomp_packet)
                yield from self.stop_handler(self.handler, self.session)
                if not future.done():
                    future.set_result(True)
            except Exception as ae:
                future.set_exception(ae)

        self.handler = None
        self.session = Session()
        future = asyncio.Future(loop=self.loop)

        coro = asyncio.start_server(server_mock,
                                    '127.0.0.1',
                                    8888,
                                    loop=self.loop)
        server = self.loop.run_until_complete(coro)
        self.loop.run_until_complete(test_coro())
        server.close()
        self.loop.run_until_complete(server.wait_closed())
        if future.exception():
            raise future.exception()
Example #11
0
 async def test_coro(stream_adapted):
     try:
         s = Session(None)
         handler = ProtocolHandler(self.plugin_manager)
         handler.attach(s, stream_adapted)
         await self.start_handler(handler, s)
         await self.stop_handler(handler, s)
     except Exception as ae:
         raise
Example #12
0
    def test_publish_qos2_retry(self):
        async def server_mock(reader, writer):
            try:
                packet = await PublishPacket.from_stream(reader)
                self.assertEqual(packet.topic_name, "/topic")
                self.assertEqual(packet.qos, QOS_2)
                self.assertIsNotNone(packet.packet_id)
                self.assertIn(packet.packet_id, self.session.inflight_out)
                self.assertIn(packet.packet_id, self.handler._pubrec_waiters)
                pubrec = PubrecPacket.build(packet.packet_id)
                await pubrec.to_stream(writer)

                await PubrelPacket.from_stream(reader)
                self.assertIn(packet.packet_id, self.handler._pubcomp_waiters)
                pubcomp = PubcompPacket.build(packet.packet_id)
                await pubcomp.to_stream(writer)
            except Exception as ae:
                future.set_exception(ae)

        async def test_coro():
            try:
                reader, writer = await asyncio.open_connection("127.0.0.1",
                                                               8888,
                                                               loop=self.loop)
                reader_adapted, writer_adapted = adapt(reader, writer)
                self.handler = ProtocolHandler(self.plugin_manager,
                                               loop=self.loop)
                self.handler.attach(self.session, reader_adapted,
                                    writer_adapted)
                await self.handler.start()
                await self.stop_handler(self.handler, self.session)
                if not future.done():
                    future.set_result(True)
            except Exception as ae:
                future.set_exception(ae)

        self.handler = None
        self.session = Session()
        message = OutgoingApplicationMessage(1, "/topic", QOS_2, b"test_data",
                                             False)
        message.publish_packet = PublishPacket.build("/topic", b"test_data",
                                                     rand_packet_id(), False,
                                                     QOS_2, False)
        self.session.inflight_out[1] = message
        future = asyncio.Future(loop=self.loop)

        coro = asyncio.start_server(server_mock,
                                    "127.0.0.1",
                                    8888,
                                    loop=self.loop)
        server = self.loop.run_until_complete(coro)
        self.loop.run_until_complete(test_coro())
        server.close()
        self.loop.run_until_complete(server.wait_closed())
        if future.exception():
            raise future.exception()
Example #13
0
    def test_receive_qos2(self):
        async def server_mock(reader, writer):
            try:
                packet = PublishPacket.build("/topic", b"test_data",
                                             rand_packet_id(), False, QOS_2,
                                             False)
                await packet.to_stream(writer)
                pubrec = await PubrecPacket.from_stream(reader)
                self.assertIsNotNone(pubrec)
                self.assertEqual(packet.packet_id, pubrec.packet_id)
                self.assertIn(packet.packet_id, self.handler._pubrel_waiters)
                pubrel = PubrelPacket.build(packet.packet_id)
                await pubrel.to_stream(writer)
                pubcomp = await PubcompPacket.from_stream(reader)
                self.assertIsNotNone(pubcomp)
                self.assertEqual(packet.packet_id, pubcomp.packet_id)
            except Exception as ae:
                future.set_exception(ae)

        async def test_coro():
            try:
                reader, writer = await asyncio.open_connection("127.0.0.1",
                                                               8888,
                                                               loop=self.loop)
                reader_adapted, writer_adapted = adapt(reader, writer)
                self.handler = ProtocolHandler(self.plugin_manager,
                                               loop=self.loop)
                self.handler.attach(self.session, reader_adapted,
                                    writer_adapted)
                await self.start_handler(self.handler, self.session)
                message = await self.handler.mqtt_deliver_next_message()
                self.assertIsInstance(message, IncomingApplicationMessage)
                self.assertIsNotNone(message.publish_packet)
                self.assertIsNone(message.puback_packet)
                self.assertIsNotNone(message.pubrec_packet)
                self.assertIsNotNone(message.pubrel_packet)
                self.assertIsNotNone(message.pubcomp_packet)
                await self.stop_handler(self.handler, self.session)
                future.set_result(True)
            except Exception as ae:
                future.set_exception(ae)

        self.handler = None
        self.session = Session()
        future = asyncio.Future(loop=self.loop)
        coro = asyncio.start_server(server_mock,
                                    "127.0.0.1",
                                    8888,
                                    loop=self.loop)
        server = self.loop.run_until_complete(coro)
        self.loop.run_until_complete(test_coro())
        server.close()
        self.loop.run_until_complete(server.wait_closed())
        if future.exception():
            raise future.exception()
Example #14
0
    def test_publish_qos1(self):
        async def server_mock(reader, writer):
            packet = await PublishPacket.from_stream(reader)
            try:
                self.assertEqual(packet.variable_header.topic_name, "/topic")
                self.assertEqual(packet.qos, QOS_1)
                self.assertIsNotNone(packet.packet_id)
                self.assertIn(packet.packet_id, self.session.inflight_out)
                self.assertIn(packet.packet_id, self.handler._puback_waiters)
                puback = PubackPacket.build(packet.packet_id)
                await puback.to_stream(writer)
            except Exception as ae:
                future.set_exception(ae)

        async def test_coro():
            try:
                reader, writer = await asyncio.open_connection("127.0.0.1",
                                                               8888,
                                                               loop=self.loop)
                reader_adapted, writer_adapted = adapt(reader, writer)
                self.handler = ProtocolHandler(self.plugin_manager,
                                               loop=self.loop)
                self.handler.attach(self.session, reader_adapted,
                                    writer_adapted)
                await self.start_handler(self.handler, self.session)
                message = await self.handler.mqtt_publish(
                    "/topic", b"test_data", QOS_1, False)
                self.assertIsInstance(message, OutgoingApplicationMessage)
                self.assertIsNotNone(message.publish_packet)
                self.assertIsNotNone(message.puback_packet)
                self.assertIsNone(message.pubrec_packet)
                self.assertIsNone(message.pubrel_packet)
                self.assertIsNone(message.pubcomp_packet)
                await self.stop_handler(self.handler, self.session)
                if not future.done():
                    future.set_result(True)
            except Exception as ae:
                future.set_exception(ae)

        self.handler = None
        self.session = Session()
        future = asyncio.Future(loop=self.loop)

        coro = asyncio.start_server(server_mock,
                                    "127.0.0.1",
                                    8888,
                                    loop=self.loop)
        server = self.loop.run_until_complete(coro)
        self.loop.run_until_complete(test_coro())
        server.close()
        self.loop.run_until_complete(server.wait_closed())
        if future.exception():
            raise future.exception()
Example #15
0
 def test_coro():
     try:
         s = Session()
         reader, writer = yield from asyncio.open_connection('127.0.0.1', 8888)
         reader_adapted, writer_adapted = adapt(reader, writer)
         handler = ProtocolHandler(self.plugin_manager)
         handler.attach(s, reader_adapted, writer_adapted)
         yield from self.start_handler(handler, s)
         yield from self.stop_handler(handler, s)
         future.set_result(True)
     except Exception as ae:
         future.set_exception(ae)
Example #16
0
    def test_receive_qos1(self):
        @asyncio.coroutine
        def server_mock(reader, writer):
            try:
                packet = PublishPacket.build('/topic', b'test_data',
                                             rand_packet_id(), False, QOS_1,
                                             False)
                yield from packet.to_stream(writer)
                puback = yield from PubackPacket.from_stream(reader)
                self.assertIsNotNone(puback)
                self.assertEqual(packet.packet_id, puback.packet_id)
            except Exception as ae:
                print(ae)
                future.set_exception(ae)

        @asyncio.coroutine
        def test_coro():
            try:
                reader, writer = yield from asyncio.open_connection(
                    '127.0.0.1', 8888, loop=self.loop)
                reader_adapted, writer_adapted = adapt(reader, writer)
                self.handler = ProtocolHandler(self.plugin_manager,
                                               loop=self.loop)
                self.handler.attach(self.session, reader_adapted,
                                    writer_adapted)
                yield from self.start_handler(self.handler, self.session)
                message = yield from self.handler.mqtt_deliver_next_message()
                self.assertIsInstance(message, IncomingApplicationMessage)
                self.assertIsNotNone(message.publish_packet)
                self.assertIsNotNone(message.puback_packet)
                self.assertIsNone(message.pubrec_packet)
                self.assertIsNone(message.pubrel_packet)
                self.assertIsNone(message.pubcomp_packet)
                yield from self.stop_handler(self.handler, self.session)
                future.set_result(True)
            except Exception as ae:
                future.set_exception(ae)

        self.handler = None
        self.session = Session()
        future = asyncio.Future(loop=self.loop)
        self.event = asyncio.Event(loop=self.loop)
        coro = asyncio.start_server(server_mock,
                                    '127.0.0.1',
                                    8888,
                                    loop=self.loop)
        server = self.loop.run_until_complete(coro)
        self.loop.run_until_complete(test_coro())
        server.close()
        self.loop.run_until_complete(server.wait_closed())
        if future.exception():
            raise future.exception()
Example #17
0
 async def test_coro(stream_adapted):
     self.session = Session(None)
     message = OutgoingApplicationMessage(1, '/topic', QOS_2,
                                          b'test_data', False)
     message.publish_packet = PublishPacket.build(
         '/topic', b'test_data', rand_packet_id(), False, QOS_2, False)
     self.session.inflight_out[1] = message
     try:
         self.handler = ProtocolHandler(self.plugin_manager)
         self.handler.attach(self.session, stream_adapted)
         await self.handler.start()
         await self.stop_handler(self.handler, self.session)
     except Exception as ae:
         raise
Example #18
0
 async def test_coro(stream_adapted):
     self.session = Session(None)
     try:
         self.handler = ProtocolHandler(self.plugin_manager)
         self.handler.attach(self.session, stream_adapted)
         await self.start_handler(self.handler, self.session)
         message = await self.handler.mqtt_deliver_next_message()
         self.assertIsInstance(message, IncomingApplicationMessage)
         self.assertIsNotNone(message.publish_packet)
         self.assertIsNone(message.puback_packet)
         self.assertIsNotNone(message.pubrec_packet)
         self.assertIsNotNone(message.pubrel_packet)
         self.assertIsNotNone(message.pubcomp_packet)
         await self.stop_handler(self.handler, self.session)
     except Exception as ae:
         raise
Example #19
0
 async def test_coro(stream_adapted):
     try:
         s = Session(None)
         handler = ProtocolHandler(self.plugin_manager)
         handler.attach(s, stream_adapted)
         await self.start_handler(handler, s)
         message = await handler.mqtt_publish('/topic', b'test_data',
                                              QOS_0, False)
         self.assertIsInstance(message, OutgoingApplicationMessage)
         self.assertIsNotNone(message.publish_packet)
         self.assertIsNone(message.puback_packet)
         self.assertIsNone(message.pubrec_packet)
         self.assertIsNone(message.pubrel_packet)
         self.assertIsNone(message.pubcomp_packet)
         await self.stop_handler(handler, s)
     except Exception as ae:
         raise
Example #20
0
 def test_coro():
     try:
         s = Session()
         reader, writer = yield from asyncio.open_connection('127.0.0.1', 8888, loop=self.loop)
         reader_adapted, writer_adapted = adapt(reader, writer)
         handler = ProtocolHandler(self.plugin_manager, loop=self.loop)
         handler.attach(s, reader_adapted, writer_adapted)
         yield from self.start_handler(handler, s)
         message = yield from handler.mqtt_publish('/topic', b'test_data', QOS_0, False)
         self.assertIsInstance(message, OutgoingApplicationMessage)
         self.assertIsNotNone(message.publish_packet)
         self.assertIsNone(message.puback_packet)
         self.assertIsNone(message.pubrec_packet)
         self.assertIsNone(message.pubrel_packet)
         self.assertIsNone(message.pubcomp_packet)
         yield from self.stop_handler(handler, s)
         future.set_result(True)
     except Exception as ae:
         future.set_exception(ae)
Example #21
0
 async def coro():
     s = Session(None)
     s.username = "******"
     auth_plugin = AnonymousAuthPlugin(context)
     ret = await auth_plugin.authenticate(session=s)
     self.assertTrue(ret)
Example #22
0
    def _initsession(self,
                     uri=None,
                     cleansession=None,
                     cafile=None,
                     capath=None,
                     cadata=None) -> Session:
        # Load config
        broker_conf = self.config.get("broker", dict()).copy()
        if uri:
            broker_conf["uri"] = uri
        if cafile:
            broker_conf["cafile"] = cafile
        elif "cafile" not in broker_conf:
            broker_conf["cafile"] = None
        if capath:
            broker_conf["capath"] = capath
        elif "capath" not in broker_conf:
            broker_conf["capath"] = None
        if cadata:
            broker_conf["cadata"] = cadata
        elif "cadata" not in broker_conf:
            broker_conf["cadata"] = None

        if cleansession is not None:
            broker_conf["cleansession"] = cleansession

        for key in ["uri"]:
            if not_in_dict_or_none(broker_conf, key):
                raise ClientException("Missing connection parameter '%s'" %
                                      key)

        s = Session()
        s.broker_uri = uri
        s.client_id = self.client_id
        s.cafile = broker_conf["cafile"]
        s.capath = broker_conf["capath"]
        s.cadata = broker_conf["cadata"]
        if cleansession is not None:
            s.clean_session = cleansession
        else:
            s.clean_session = self.config.get("cleansession", True)
        s.keep_alive = self.config["keep_alive"] - self.config["ping_delay"]
        if "will" in self.config:
            s.will_flag = True
            s.will_retain = self.config["will"]["retain"]
            s.will_topic = self.config["will"]["topic"]
            s.will_message = self.config["will"]["message"]
            s.will_qos = self.config["will"]["qos"]
        else:
            s.will_flag = False
            s.will_retain = False
            s.will_topic = None
            s.will_message = None
        return s
Example #23
0
    def _initsession(self,
                     uri=None,
                     cleansession=None,
                     cafile=None,
                     capath=None,
                     cadata=None) -> Session:
        # Load config
        broker_conf = self.config.get('broker', dict()).copy()
        if uri:
            broker_conf['uri'] = uri
        if cafile:
            broker_conf['cafile'] = cafile
        elif 'cafile' not in broker_conf:
            broker_conf['cafile'] = None
        if capath:
            broker_conf['capath'] = capath
        elif 'capath' not in broker_conf:
            broker_conf['capath'] = None
        if cadata:
            broker_conf['cadata'] = cadata
        elif 'cadata' not in broker_conf:
            broker_conf['cadata'] = None

        if cleansession is not None:
            broker_conf['cleansession'] = cleansession

        for key in ['uri']:
            if not_in_dict_or_none(broker_conf, key):
                raise ClientException("Missing connection parameter '%s'" %
                                      key)

        s = Session()
        s.broker_uri = uri
        s.client_id = self.client_id
        s.cafile = broker_conf['cafile']
        s.capath = broker_conf['capath']
        s.cadata = broker_conf['cadata']
        if cleansession is not None:
            s.clean_session = cleansession
        else:
            s.clean_session = self.config.get('cleansession', True)
        s.keep_alive = self.config['keep_alive'] - self.config['ping_delay']
        if 'will' in self.config:
            s.will_flag = True
            s.will_retain = self.config['will']['retain']
            s.will_topic = self.config['will']['topic']
            s.will_message = self.config['will']['message']
            s.will_qos = self.config['will']['qos']
        else:
            s.will_flag = False
            s.will_retain = False
            s.will_topic = None
            s.will_message = None
        return s
Example #24
0
    async def init_from_connect(cls, stream: StreamAdapter, plugins_manager):
        """

        :param stream:
        :param plugins_manager:
        :return:
        """
        remote_address, remote_port = stream.get_peer_info()
        try:
            connect = await ConnectPacket.from_stream(stream)
        except NoDataException:
            raise MQTTException('Client closed the connection')
        logger.debug("< B %r", connect)
        await plugins_manager.fire_event(EVENT_MQTT_PACKET_RECEIVED,
                                         packet=connect)
        #this shouldn't be required anymore since broker generates for each client a random client_id if not provided
        #[MQTT-3.1.3-6]
        if connect.payload.client_id is None:
            raise MQTTException(
                '[[MQTT-3.1.3-3]] : Client identifier must be present')

        if connect.variable_header.will_flag:
            if connect.payload.will_topic is None or connect.payload.will_message is None:
                raise MQTTException(
                    'will flag set, but will topic/message not present in payload'
                )

        if connect.variable_header.reserved_flag:
            raise MQTTException(
                '[MQTT-3.1.2-3] CONNECT reserved flag must be set to 0')
        if connect.proto_name != "MQTT":
            raise MQTTException(
                '[MQTT-3.1.2-1] Incorrect protocol name: "%s"' %
                connect.proto_name)

        connack = None
        error_msg = None
        if connect.proto_level != 4:
            # only MQTT 3.1.1 supported
            error_msg = 'Invalid protocol from %s: %d' % (
                format_client_message(address=remote_address,
                                      port=remote_port), connect.proto_level)
            connack = ConnackPacket.build(0, UNACCEPTABLE_PROTOCOL_VERSION
                                          )  # [MQTT-3.2.2-4] session_parent=0
        elif not connect.username_flag and connect.password_flag:
            connack = ConnackPacket.build(
                0, BAD_USERNAME_PASSWORD)  # [MQTT-3.1.2-22]
        elif connect.username_flag and not connect.password_flag:
            connack = ConnackPacket.build(
                0, BAD_USERNAME_PASSWORD)  # [MQTT-3.1.2-22]
        elif connect.username_flag and connect.username is None:
            error_msg = 'Invalid username from %s' % (format_client_message(
                address=remote_address, port=remote_port))
            connack = ConnackPacket.build(
                0, BAD_USERNAME_PASSWORD)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.password_flag and connect.password is None:
            error_msg = 'Invalid password %s' % (format_client_message(
                address=remote_address, port=remote_port))
            connack = ConnackPacket.build(
                0, BAD_USERNAME_PASSWORD)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.clean_session_flag is False and (
                connect.payload.client_id_is_random):
            error_msg = '[MQTT-3.1.3-8] [MQTT-3.1.3-9] %s: No client Id provided (cleansession=0)' % (
                format_client_message(address=remote_address,
                                      port=remote_port))
            connack = ConnackPacket.build(0, IDENTIFIER_REJECTED)
        if connack is not None:
            logger.debug("B > %r", connack)
            await plugins_manager.fire_event(EVENT_MQTT_PACKET_SENT,
                                             packet=connack)
            await connack.to_stream(stream)

            await stream.close()
            raise MQTTException(error_msg)

        incoming_session = Session(plugins_manager)
        incoming_session.client_id = connect.client_id
        incoming_session.clean_session = connect.clean_session_flag
        incoming_session.will_flag = connect.will_flag
        incoming_session.will_retain = connect.will_retain_flag
        incoming_session.will_qos = connect.will_qos
        incoming_session.will_topic = connect.will_topic
        incoming_session.will_message = connect.will_message
        incoming_session.username = connect.username
        incoming_session.password = connect.password
        if connect.keep_alive > 0:
            incoming_session.keep_alive = connect.keep_alive
        else:
            incoming_session.keep_alive = 0

        handler = cls(plugins_manager)
        return handler, incoming_session
Example #25
0
    def _initsession(self, host=None, port=None, username=None, password=None, uri=None, cleansession=None) -> dict:
        # Load config
        broker_conf = self.config.get('broker', dict()).copy()
        if 'mqtt' not in broker_conf:
            broker_conf['scheme'] = 'mqtt'
        if 'username' not in broker_conf:
            broker_conf['username'] = None
        if 'password' not in broker_conf:
            broker_conf['password'] = None

        if uri is not None:
            result = urlparse(uri)
            if result.scheme:
                broker_conf['scheme'] = result.scheme
            if result.hostname:
                broker_conf['host'] = result.hostname
            if result.port:
                broker_conf['port'] = result.port
            if result.username:
                broker_conf['username'] = result.username
            if result.password:
                broker_conf['password'] = result.password
        if host:
            broker_conf['host'] = host
        if port:
            broker_conf['port'] = int(port)
        if username:
            broker_conf['username'] = username
        if password:
            broker_conf['password'] = password
        if cleansession is not None:
            broker_conf['cleansession'] = cleansession

        for key in ['scheme', 'host', 'port']:
            if not_in_dict_or_none(broker_conf, key):
                raise ClientException("Missing connection parameter '%s'" % key)

        s = Session()
        s.client_id = self.client_id
        s.remote_address = broker_conf['host']
        s.remote_port = broker_conf['port']
        s.username = broker_conf['username']
        s.password = broker_conf['password']
        s.scheme = broker_conf['scheme']
        if cleansession is not None:
            s.cleansession = cleansession
        else:
            s.cleansession = self.config.get('cleansession', True)
        s.keep_alive = self.config['keep_alive']
        if 'will' in self.config:
            s.will_flag = True
            s.will_retain = self.config['will']['retain']
            s.will_topic = self.config['will']['topic']
            s.will_message = self.config['will']['message']
        else:
            s.will_flag = False
            s.will_retain = False
            s.will_topic = None
            s.will_message = None
        return s
Example #26
0
    def _initsession(
            self,
            uri=None,
            cleansession=None,
            cafile=None,
            capath=None,
            cadata=None) -> Session:
        # Load config
        broker_conf = self.config.get('broker', dict()).copy()
        if uri:
            broker_conf['uri'] = uri
        if cafile:
            broker_conf['cafile'] = cafile
        elif 'cafile' not in broker_conf:
            broker_conf['cafile'] = None
        if capath:
            broker_conf['capath'] = capath
        elif 'capath' not in broker_conf:
            broker_conf['capath'] = None
        if cadata:
            broker_conf['cadata'] = cadata
        elif 'cadata' not in broker_conf:
            broker_conf['cadata'] = None

        if cleansession is not None:
            broker_conf['cleansession'] = cleansession

        for key in ['uri']:
            if not_in_dict_or_none(broker_conf, key):
                raise ClientException("Missing connection parameter '%s'" % key)

        s = Session()
        s.broker_uri = uri
        s.client_id = self.client_id
        s.cafile = broker_conf['cafile']
        s.capath = broker_conf['capath']
        s.cadata = broker_conf['cadata']
        if cleansession is not None:
            s.clean_session = cleansession
        else:
            s.clean_session = self.config.get('cleansession', True)
        s.keep_alive = self.config['keep_alive'] - self.config['ping_delay']
        if 'will' in self.config:
            s.will_flag = True
            s.will_retain = self.config['will']['retain']
            s.will_topic = self.config['will']['topic']
            s.will_message = self.config['will']['message']
            s.will_qos = self.config['will']['qos']
        else:
            s.will_flag = False
            s.will_retain = False
            s.will_topic = None
            s.will_message = None
        return s
Example #27
0
    def client_connected(self, listener_name, reader: ReaderAdapter, writer: WriterAdapter):
        # Wait for connection available
        server = self._servers[listener_name]
        yield from server.acquire_connection()

        remote_address, remote_port = writer.get_peer_info()
        self.logger.debug("Connection from %s:%d on listener '%s'" % (remote_address, remote_port, listener_name))

        # Wait for first packet and expect a CONNECT
        connect = None
        try:
            connect = yield from ConnectPacket.from_stream(reader)
            self.logger.debug(" <-in-- " + repr(connect))
            self.check_connect(connect)
        except HBMQTTException as exc:
            self.logger.warn("[MQTT-3.1.0-1] %s: Can't read first packet an CONNECT: %s" %
                             (format_client_message(address=remote_address, port=remote_port), exc))
            yield from writer.close()
            self.logger.debug("Connection closed")
            return
        except BrokerException as be:
            self.logger.error('Invalid connection from %s : %s' %
                              (format_client_message(address=remote_address, port=remote_port), be))
            yield from writer.close()
            self.logger.debug("Connection closed")
            return

        connack = None
        if connect.variable_header.proto_level != 4:
            # only MQTT 3.1.1 supported
            self.logger.error('Invalid protocol from %s: %d' %
                              (format_client_message(address=remote_address, port=remote_port),
                               connect.variable_header.protocol_level))
            connack = ConnackPacket.build(0, UNACCEPTABLE_PROTOCOL_VERSION)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.variable_header.username_flag and connect.payload.username is None:
            self.logger.error('Invalid username from %s' %
                              (format_client_message(address=remote_address, port=remote_port)))
            connack = ConnackPacket.build(0, BAD_USERNAME_PASSWORD)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.variable_header.password_flag and connect.payload.password is None:
            self.logger.error('Invalid password %s' % (format_client_message(address=remote_address, port=remote_port)))
            connack = ConnackPacket.build(0, BAD_USERNAME_PASSWORD)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.variable_header.clean_session_flag is False and connect.payload.client_id is None:
            self.logger.error('[MQTT-3.1.3-8] [MQTT-3.1.3-9] %s: No client Id provided (cleansession=0)' %
                              format_client_message(address=remote_address, port=remote_port))
            connack = ConnackPacket.build(0, IDENTIFIER_REJECTED)
            self.logger.debug(" -out-> " + repr(connack))
        if connack is not None:
            self.logger.debug(" -out-> " + repr(connack))
            yield from connack.to_stream(writer)
            yield from writer.close()
            return

        client_session = None
        self.logger.debug("Clean session={0}".format(connect.variable_header.clean_session_flag))
        self.logger.debug("known sessions={0}".format(self._sessions))
        client_id = connect.payload.client_id
        if connect.variable_header.clean_session_flag:
            # Delete existing session and create a new one
            if client_id is not None:
                self.delete_session(client_id)
            client_session = Session()
            client_session.parent = 0
            client_session.client_id = client_id
            self._sessions[client_id] = client_session
        else:
            # Get session from cache
            if client_id in self._sessions:
                self.logger.debug("Found old session %s" % repr(self._sessions[client_id]))
                client_session = self._sessions[client_id]
                client_session.parent = 1
            else:
                client_session = Session()
                client_session.client_id = client_id
                self._sessions[client_id] = client_session
                client_session.parent = 0

        if client_session.client_id is None:
            # Generate client ID
            client_session.client_id = gen_client_id()
        client_session.remote_address = remote_address
        client_session.remote_port = remote_port
        client_session.clean_session = connect.variable_header.clean_session_flag
        client_session.will_flag = connect.variable_header.will_flag
        client_session.will_retain = connect.variable_header.will_retain_flag
        client_session.will_qos = connect.variable_header.will_qos
        client_session.will_topic = connect.payload.will_topic
        client_session.will_message = connect.payload.will_message
        client_session.username = connect.payload.username
        client_session.password = connect.payload.password
        client_session.client_id = connect.payload.client_id
        if connect.variable_header.keep_alive > 0:
            client_session.keep_alive = connect.variable_header.keep_alive + self.config['timeout-disconnect-delay']
        else:
            client_session.keep_alive = 0
        client_session.publish_retry_delay = self.config['publish-retry-delay']

        client_session.reader = reader
        client_session.writer = writer

        if self.authenticate(client_session):
            connack = ConnackPacket.build(client_session.parent, CONNECTION_ACCEPTED)
            self.logger.info('%s : connection accepted' % format_client_message(session=client_session))
            self.logger.debug(" -out-> " + repr(connack))
            yield from connack.to_stream(writer)
        else:
            connack = ConnackPacket.build(client_session.parent, NOT_AUTHORIZED)
            self.logger.info('%s : connection refused' % format_client_message(session=client_session))
            self.logger.debug(" -out-> " + repr(connack))
            yield from connack.to_stream(writer)
            yield from writer.close()
            return

        client_session.transitions.connect()
        handler = self._init_handler(reader, writer, client_session)
        self.logger.debug("%s Start messages handling" % client_session.client_id)
        yield from handler.start()
        self.logger.debug("Retained messages queue size: %d" % client_session.retained_messages.qsize())
        yield from self.publish_session_retained_messages(client_session)
        self.logger.debug("%s Wait for disconnect" % client_session.client_id)

        connected = True
        wait_disconnect = asyncio.Task(handler.wait_disconnect())
        wait_subscription = asyncio.Task(handler.get_next_pending_subscription())
        wait_unsubscription = asyncio.Task(handler.get_next_pending_unsubscription())
        wait_deliver = asyncio.Task(handler.mqtt_deliver_next_message())
        while connected:
            done, pending = yield from asyncio.wait(
                [wait_disconnect, wait_subscription, wait_unsubscription, wait_deliver],
                return_when=asyncio.FIRST_COMPLETED)
            if wait_disconnect in done:
                result = wait_disconnect.result()
                self.logger.debug("%s Result from wait_diconnect: %s" % (client_session.client_id, result))
                if result is None:
                    self.logger.debug("Will flag: %s" % client_session.will_flag)
                    # Connection closed anormally, send will message
                    if client_session.will_flag:
                        self.logger.debug("Client %s disconnected abnormally, sending will message" %
                                          format_client_message(client_session))
                        yield from self.broadcast_application_message(
                            client_session, client_session.will_topic,
                            client_session.will_message,
                            client_session.will_qos)
                        if client_session.will_retain:
                            self.retain_message(client_session,
                                                client_session.will_topic,
                                                client_session.will_message,
                                                client_session.will_qos)
                connected = False
            if wait_unsubscription in done:
                self.logger.debug("%s handling unsubscription" % client_session.client_id)
                unsubscription = wait_unsubscription.result()
                for topic in unsubscription['topics']:
                    self.del_subscription(topic, client_session)
                yield from handler.mqtt_acknowledge_unsubscription(unsubscription['packet_id'])
                wait_unsubscription = asyncio.Task(handler.get_next_pending_unsubscription())
            if wait_subscription in done:
                self.logger.debug("%s handling subscription" % client_session.client_id)
                subscriptions = wait_subscription.result()
                return_codes = []
                for subscription in subscriptions['topics']:
                    return_codes.append(self.add_subscription(subscription, client_session))
                yield from handler.mqtt_acknowledge_subscription(subscriptions['packet_id'], return_codes)
                for index, subscription in enumerate(subscriptions['topics']):
                    if return_codes[index] != 0x80:
                        yield from self.publish_retained_messages_for_subscription(subscription, client_session)
                wait_subscription = asyncio.Task(handler.get_next_pending_subscription())
                self.logger.debug(repr(self._subscriptions))
            if wait_deliver in done:
                self.logger.debug("%s handling message delivery" % client_session.client_id)
                publish_packet = wait_deliver.result()
                packet_id = publish_packet.variable_header.packet_id
                topic_name = publish_packet.variable_header.topic_name
                data = publish_packet.payload.data
                yield from self.broadcast_application_message(client_session, topic_name, data)
                if publish_packet.retain_flag:
                    self.retain_message(client_session, topic_name, data)
                # Acknowledge message delivery
                yield from handler.mqtt_acknowledge_delivery(packet_id)
                wait_deliver = asyncio.Task(handler.mqtt_deliver_next_message())
        wait_subscription.cancel()
        wait_unsubscription.cancel()
        wait_deliver.cancel()

        self.logger.debug("%s Client disconnecting" % client_session.client_id)
        yield from self._stop_handler(handler)
        client_session.transitions.disconnect()
        yield from writer.close()
        self.logger.debug("%s Session disconnected" % client_session.client_id)
        server.release_connection()
Example #28
0
    def init_from_connect(cls, reader: ReaderAdapter, writer: WriterAdapter, plugins_manager, loop=None):
        """

        :param reader:
        :param writer:
        :param plugins_manager:
        :param loop:
        :return:
        """
        remote_address, remote_port = writer.get_peer_info()
        connect = yield from ConnectPacket.from_stream(reader)
        yield from plugins_manager.fire_event(EVENT_MQTT_PACKET_RECEIVED, packet=connect)
        if connect.payload.client_id is None:
            raise MQTTException('[[MQTT-3.1.3-3]] : Client identifier must be present' )

        if connect.variable_header.will_flag:
            if connect.payload.will_topic is None or connect.payload.will_message is None:
                raise MQTTException('will flag set, but will topic/message not present in payload')

        if connect.variable_header.reserved_flag:
            raise MQTTException('[MQTT-3.1.2-3] CONNECT reserved flag must be set to 0')
        if connect.proto_name != "MQTT":
            raise MQTTException('[MQTT-3.1.2-1] Incorrect protocol name: "%s"' % connect.proto_name)

        connack = None
        error_msg = None
        if connect.proto_level != 4:
            # only MQTT 3.1.1 supported
            error_msg = 'Invalid protocol from %s: %d' % \
                              (format_client_message(address=remote_address, port=remote_port), connect.proto_level)
            connack = ConnackPacket.build(0, UNACCEPTABLE_PROTOCOL_VERSION)  # [MQTT-3.2.2-4] session_parent=0
        elif not connect.username_flag and connect.password_flag:
            connack = ConnackPacket.build(0, BAD_USERNAME_PASSWORD)  # [MQTT-3.1.2-22]
        elif connect.username_flag and not connect.password_flag:
            connack = ConnackPacket.build(0, BAD_USERNAME_PASSWORD)  # [MQTT-3.1.2-22]
        elif connect.username_flag and connect.username is None:
            error_msg = 'Invalid username from %s' % \
                              (format_client_message(address=remote_address, port=remote_port))
            connack = ConnackPacket.build(0, BAD_USERNAME_PASSWORD)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.password_flag and connect.password is None:
            error_msg = 'Invalid password %s' % (format_client_message(address=remote_address, port=remote_port))
            connack = ConnackPacket.build(0, BAD_USERNAME_PASSWORD)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.clean_session_flag is False and (connect.payload.client_id is None or connect.payload.client_id == ""):
            error_msg = '[MQTT-3.1.3-8] [MQTT-3.1.3-9] %s: No client Id provided (cleansession=0)' % \
                              format_client_message(address=remote_address, port=remote_port)
            connack = ConnackPacket.build(0, IDENTIFIER_REJECTED)
        if connack is not None:
            yield from plugins_manager.fire_event(EVENT_MQTT_PACKET_SENT, packet=connack)
            yield from connack.to_stream(writer)
            yield from writer.close()
            raise MQTTException(error_msg)

        incoming_session = Session(loop)
        incoming_session.client_id = connect.client_id
        incoming_session.clean_session = connect.clean_session_flag
        incoming_session.will_flag = connect.will_flag
        incoming_session.will_retain = connect.will_retain_flag
        incoming_session.will_qos = connect.will_qos
        incoming_session.will_topic = connect.will_topic
        incoming_session.will_message = connect.will_message
        incoming_session.username = connect.username
        incoming_session.password = connect.password
        if connect.keep_alive > 0:
            incoming_session.keep_alive = connect.keep_alive
        else:
            incoming_session.keep_alive = 0

        handler = cls(plugins_manager, loop=loop)
        return handler, incoming_session
Example #29
0
    def init_from_connect(cls, reader: ReaderAdapter, writer: WriterAdapter, plugins_manager, loop=None):
        """

        :param reader:
        :param writer:
        :param plugins_manager:
        :param loop:
        :return:
        """
        remote_address, remote_port = writer.get_peer_info()
        connect = yield from ConnectPacket.from_stream(reader)
        yield from plugins_manager.fire_event(EVENT_MQTT_PACKET_RECEIVED, packet=connect)
        if connect.payload.client_id is None:
            raise MQTTException('[[MQTT-3.1.3-3]] : Client identifier must be present' )

        if connect.variable_header.will_flag:
            if connect.payload.will_topic is None or connect.payload.will_message is None:
                raise MQTTException('will flag set, but will topic/message not present in payload')

        if connect.variable_header.reserved_flag:
            raise MQTTException('[MQTT-3.1.2-3] CONNECT reserved flag must be set to 0')
        if connect.proto_name != "MQTT":
            raise MQTTException('[MQTT-3.1.2-1] Incorrect protocol name: "%s"' % connect.proto_name)

        connack = None
        error_msg = None
        if connect.proto_level != 4:
            # only MQTT 3.1.1 supported
            error_msg = 'Invalid protocol from %s: %d' % \
                              (format_client_message(address=remote_address, port=remote_port),
                               connect.variable_header.protocol_level)
            connack = ConnackPacket.build(0, UNACCEPTABLE_PROTOCOL_VERSION)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.username_flag and connect.username is None:
            error_msg = 'Invalid username from %s' % \
                              (format_client_message(address=remote_address, port=remote_port))
            connack = ConnackPacket.build(0, BAD_USERNAME_PASSWORD)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.password_flag and connect.password is None:
            error_msg = 'Invalid password %s' % (format_client_message(address=remote_address, port=remote_port))
            connack = ConnackPacket.build(0, BAD_USERNAME_PASSWORD)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.clean_session_flag is False and connect.payload.client_id is None:
            error_msg = '[MQTT-3.1.3-8] [MQTT-3.1.3-9] %s: No client Id provided (cleansession=0)' % \
                              format_client_message(address=remote_address, port=remote_port)
            connack = ConnackPacket.build(0, IDENTIFIER_REJECTED)
        if connack is not None:
            yield from plugins_manager.fire_event(EVENT_MQTT_PACKET_SENT, packet=connack)
            yield from connack.to_stream(writer)
            yield from writer.close()
            raise MQTTException(error_msg)

        incoming_session = Session(loop)
        incoming_session.client_id = connect.client_id
        incoming_session.clean_session = connect.clean_session_flag
        incoming_session.will_flag = connect.will_flag
        incoming_session.will_retain = connect.will_retain_flag
        incoming_session.will_qos = connect.will_qos
        incoming_session.will_topic = connect.will_topic
        incoming_session.will_message = connect.will_message
        incoming_session.username = connect.username
        incoming_session.password = connect.password
        if connect.keep_alive > 0:
            incoming_session.keep_alive = connect.keep_alive
        else:
            incoming_session.keep_alive = 0

        handler = cls(plugins_manager, loop=loop)
        return handler, incoming_session
Example #30
0
 def test_init_handler(self):
     s = Session()
     handler = ProtocolHandler(self.plugin_manager, loop=self.loop)
     self.assertIsNone(handler.session)
     self.assertIs(handler._loop, self.loop)
     self.check_empty_waiters(handler)
Example #31
0
    def client_connected(self, listener_name, reader: ReaderAdapter,
                         writer: WriterAdapter):
        # Wait for connection available
        server = self._servers[listener_name]
        yield from server.acquire_connection()

        remote_address, remote_port = writer.get_peer_info()
        self.logger.debug("Connection from %s:%d on listener '%s'" %
                          (remote_address, remote_port, listener_name))

        # Wait for first packet and expect a CONNECT
        connect = None
        try:
            connect = yield from ConnectPacket.from_stream(reader)
            self.logger.debug(" <-in-- " + repr(connect))
            self.check_connect(connect)
        except HBMQTTException as exc:
            self.logger.warn(
                "[MQTT-3.1.0-1] %s: Can't read first packet an CONNECT: %s" %
                (format_client_message(address=remote_address,
                                       port=remote_port), exc))
            yield from writer.close()
            self.logger.debug("Connection closed")
            return
        except BrokerException as be:
            self.logger.error('Invalid connection from %s : %s' %
                              (format_client_message(address=remote_address,
                                                     port=remote_port), be))
            yield from writer.close()
            self.logger.debug("Connection closed")
            return

        connack = None
        if connect.variable_header.proto_level != 4:
            # only MQTT 3.1.1 supported
            self.logger.error(
                'Invalid protocol from %s: %d' % (format_client_message(
                    address=remote_address,
                    port=remote_port), connect.variable_header.protocol_level))
            connack = ConnackPacket.build(0, UNACCEPTABLE_PROTOCOL_VERSION
                                          )  # [MQTT-3.2.2-4] session_parent=0
        elif connect.variable_header.username_flag and connect.payload.username is None:
            self.logger.error('Invalid username from %s' %
                              (format_client_message(address=remote_address,
                                                     port=remote_port)))
            connack = ConnackPacket.build(
                0, BAD_USERNAME_PASSWORD)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.variable_header.password_flag and connect.payload.password is None:
            self.logger.error('Invalid password %s' % (format_client_message(
                address=remote_address, port=remote_port)))
            connack = ConnackPacket.build(
                0, BAD_USERNAME_PASSWORD)  # [MQTT-3.2.2-4] session_parent=0
        elif connect.variable_header.clean_session_flag is False and connect.payload.client_id is None:
            self.logger.error(
                '[MQTT-3.1.3-8] [MQTT-3.1.3-9] %s: No client Id provided (cleansession=0)'
                % format_client_message(address=remote_address,
                                        port=remote_port))
            connack = ConnackPacket.build(0, IDENTIFIER_REJECTED)
            self.logger.debug(" -out-> " + repr(connack))
        if connack is not None:
            self.logger.debug(" -out-> " + repr(connack))
            yield from connack.to_stream(writer)
            yield from writer.close()
            return

        client_session = None
        self.logger.debug("Clean session={0}".format(
            connect.variable_header.clean_session_flag))
        self.logger.debug("known sessions={0}".format(self._sessions))
        client_id = connect.payload.client_id
        if connect.variable_header.clean_session_flag:
            # Delete existing session and create a new one
            if client_id is not None:
                self.delete_session(client_id)
            client_session = Session()
            client_session.parent = 0
            client_session.client_id = client_id
            self._sessions[client_id] = client_session
        else:
            # Get session from cache
            if client_id in self._sessions:
                self.logger.debug("Found old session %s" %
                                  repr(self._sessions[client_id]))
                client_session = self._sessions[client_id]
                client_session.parent = 1
            else:
                client_session = Session()
                client_session.client_id = client_id
                self._sessions[client_id] = client_session
                client_session.parent = 0

        if client_session.client_id is None:
            # Generate client ID
            client_session.client_id = gen_client_id()
        client_session.remote_address = remote_address
        client_session.remote_port = remote_port
        client_session.clean_session = connect.variable_header.clean_session_flag
        client_session.will_flag = connect.variable_header.will_flag
        client_session.will_retain = connect.variable_header.will_retain_flag
        client_session.will_qos = connect.variable_header.will_qos
        client_session.will_topic = connect.payload.will_topic
        client_session.will_message = connect.payload.will_message
        client_session.username = connect.payload.username
        client_session.password = connect.payload.password
        client_session.client_id = connect.payload.client_id
        if connect.variable_header.keep_alive > 0:
            client_session.keep_alive = connect.variable_header.keep_alive + self.config[
                'timeout-disconnect-delay']
        else:
            client_session.keep_alive = 0
        client_session.publish_retry_delay = self.config['publish-retry-delay']

        client_session.reader = reader
        client_session.writer = writer

        if self.authenticate(client_session):
            connack = ConnackPacket.build(client_session.parent,
                                          CONNECTION_ACCEPTED)
            self.logger.info('%s : connection accepted' %
                             format_client_message(session=client_session))
            self.logger.debug(" -out-> " + repr(connack))
            yield from connack.to_stream(writer)
        else:
            connack = ConnackPacket.build(client_session.parent,
                                          NOT_AUTHORIZED)
            self.logger.info('%s : connection refused' %
                             format_client_message(session=client_session))
            self.logger.debug(" -out-> " + repr(connack))
            yield from connack.to_stream(writer)
            yield from writer.close()
            return

        client_session.transitions.connect()
        handler = self._init_handler(reader, writer, client_session)
        self.logger.debug("%s Start messages handling" %
                          client_session.client_id)
        yield from handler.start()
        self.logger.debug("Retained messages queue size: %d" %
                          client_session.retained_messages.qsize())
        yield from self.publish_session_retained_messages(client_session)
        self.logger.debug("%s Wait for disconnect" % client_session.client_id)

        connected = True
        wait_disconnect = asyncio.Task(handler.wait_disconnect())
        wait_subscription = asyncio.Task(
            handler.get_next_pending_subscription())
        wait_unsubscription = asyncio.Task(
            handler.get_next_pending_unsubscription())
        wait_deliver = asyncio.Task(handler.mqtt_deliver_next_message())
        while connected:
            done, pending = yield from asyncio.wait(
                [
                    wait_disconnect, wait_subscription, wait_unsubscription,
                    wait_deliver
                ],
                return_when=asyncio.FIRST_COMPLETED)
            if wait_disconnect in done:
                result = wait_disconnect.result()
                self.logger.debug("%s Result from wait_diconnect: %s" %
                                  (client_session.client_id, result))
                if result is None:
                    self.logger.debug("Will flag: %s" %
                                      client_session.will_flag)
                    # Connection closed anormally, send will message
                    if client_session.will_flag:
                        self.logger.debug(
                            "Client %s disconnected abnormally, sending will message"
                            % format_client_message(client_session))
                        yield from self.broadcast_application_message(
                            client_session, client_session.will_topic,
                            client_session.will_message,
                            client_session.will_qos)
                        if client_session.will_retain:
                            self.retain_message(client_session,
                                                client_session.will_topic,
                                                client_session.will_message,
                                                client_session.will_qos)
                connected = False
            if wait_unsubscription in done:
                self.logger.debug("%s handling unsubscription" %
                                  client_session.client_id)
                unsubscription = wait_unsubscription.result()
                for topic in unsubscription['topics']:
                    self.del_subscription(topic, client_session)
                yield from handler.mqtt_acknowledge_unsubscription(
                    unsubscription['packet_id'])
                wait_unsubscription = asyncio.Task(
                    handler.get_next_pending_unsubscription())
            if wait_subscription in done:
                self.logger.debug("%s handling subscription" %
                                  client_session.client_id)
                subscriptions = wait_subscription.result()
                return_codes = []
                for subscription in subscriptions['topics']:
                    return_codes.append(
                        self.add_subscription(subscription, client_session))
                yield from handler.mqtt_acknowledge_subscription(
                    subscriptions['packet_id'], return_codes)
                for index, subscription in enumerate(subscriptions['topics']):
                    if return_codes[index] != 0x80:
                        yield from self.publish_retained_messages_for_subscription(
                            subscription, client_session)
                wait_subscription = asyncio.Task(
                    handler.get_next_pending_subscription())
                self.logger.debug(repr(self._subscriptions))
            if wait_deliver in done:
                self.logger.debug("%s handling message delivery" %
                                  client_session.client_id)
                publish_packet = wait_deliver.result()
                packet_id = publish_packet.variable_header.packet_id
                topic_name = publish_packet.variable_header.topic_name
                data = publish_packet.payload.data
                yield from self.broadcast_application_message(
                    client_session, topic_name, data)
                if publish_packet.retain_flag:
                    self.retain_message(client_session, topic_name, data)
                # Acknowledge message delivery
                yield from handler.mqtt_acknowledge_delivery(packet_id)
                wait_deliver = asyncio.Task(
                    handler.mqtt_deliver_next_message())
        wait_subscription.cancel()
        wait_unsubscription.cancel()
        wait_deliver.cancel()

        self.logger.debug("%s Client disconnecting" % client_session.client_id)
        yield from self._stop_handler(handler)
        client_session.transitions.disconnect()
        yield from writer.close()
        self.logger.debug("%s Session disconnected" % client_session.client_id)
        server.release_connection()