Пример #1
0
    def _handle_sasl_auth(self, xml):
        try:

            saslauth = base64.b64decode(xml.text).decode("utf-8").split("/")
            username = saslauth[0]
            username = saslauth[0].split("\x00")[1]
            authcode = ""
            self.uid = username
            if len(saslauth) > 1:
                resource = saslauth[1]
                self.clientresource = resource
            elif len(saslauth[0].split("\x00")) > 2:
                resource = saslauth[0].split("\x00")[2]
                self.clientresource = resource

            if len(saslauth) > 2:
                authcode = saslauth[2]

            if self.devclass:  # if there is a devclass it is a bot
                bumper.bot_add(self.uid, self.uid, self.devclass, "atom",
                               "eco-legacy")
                self.type = self.BOT
                xmppserverlog.info("bot authenticated SN: {}".format(self.uid))
                # Send response
                self.send('<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>'
                          )  # Success

                # Client authenticated, move to next state
                self._set_state("INIT")

            else:
                auth = False
                if bumper.check_authcode(self.uid, authcode):
                    auth = True
                elif bumper.use_auth == False:
                    auth = True

                if auth:
                    self.type = self.CONTROLLER
                    bumper.client_add(self.uid, "bumper", self.clientresource)
                    xmppserverlog.info("client authenticated {}".format(
                        self.uid))

                    # Client authenticated, move to next state
                    self._set_state("INIT")

                    # Send response
                    self.send(
                        '<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>'
                    )  # Success

                else:
                    # Failed to authenticate
                    self.send(
                        '<response xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>'
                    )  # Fail

        except Exception as e:
            xmppserverlog.exception("{}".format(e))
Пример #2
0
def test_client_db():
    bumper.db = "tests/tmp.db"  # Set db location for testing
    bumper.client_add("user_123", "realm_123", "resource_123")
    assert bumper.client_get("resource_123")  # Test client was added

    bumper.client_set_mqtt("resource_123", True)
    assert bumper.client_get("resource_123")[
        "mqtt_connection"]  # Test that mqtt was set True for client

    bumper.client_set_xmpp("resource_123", False)
    assert (bumper.client_get("resource_123")["xmpp_connection"] == False
            )  # Test that xmpp was set False for client
    assert (len(bumper.get_disconnected_xmpp_clients()) == 1
            )  # Test len of connected xmpp clients is 1
Пример #3
0
async def test_mqttserver():
    if os.path.exists("tests/tmp.db"):
        os.remove("tests/tmp.db")  # Remove existing db

    bumper.db = "tests/tmp.db"  # Set db location for testing

    mqtt_address = ("127.0.0.1", 8883)

    mqtt_server = bumper.MQTTServer(mqtt_address)
    await mqtt_server.broker_coro()

    # Test helperbot connect
    mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address)
    await mqtt_helperbot.start_helper_bot()
    assert (mqtt_helperbot.Client._connected_state._value == True
            )  # Check helperbot is connected
    await mqtt_helperbot.Client.disconnect()

    # Test client connect
    bumper.user_add("user_123")  # Add user to db
    bumper.client_add("user_123", "ecouser.net",
                      "resource_123")  # Add client to db
    test_client = bumper.MQTTHelperBot(mqtt_address)
    test_client.client_id = "[email protected]/resource_123"
    # await test_client.start_helper_bot()
    test_client.Client = hbmqtt.client.MQTTClient(
        client_id=test_client.client_id, config={"check_hostname": False})

    await test_client.Client.connect(
        "mqtts://{}:{}/".format(test_client.address[0],
                                test_client.address[1]),
        cafile=bumper.ca_cert,
    )
    assert (test_client.Client._connected_state._value == True
            )  # Check client is connected
    await test_client.Client.disconnect()
    assert (test_client.Client._connected_state._value == False
            )  # Check client is disconnected

    # Test fake_bot connect
    fake_bot = bumper.MQTTHelperBot(mqtt_address)
    fake_bot.client_id = "bot_serial@ls1ok3/wC3g"
    await fake_bot.start_helper_bot()
    assert (fake_bot.Client._connected_state._value == True
            )  # Check fake_bot is connected
    await fake_bot.Client.disconnect()

    await asyncio.sleep(0.1)

    await mqtt_server.broker.shutdown()
Пример #4
0
    async def authenticate(self, *args, **kwargs):
        authenticated = False

        try:
            session = kwargs.get("session", None)
            username = session.username
            password = session.password
            client_id = session.client_id

            if "@" in client_id:
                didsplit = str(client_id).split("@")
                if not (  # if ecouser or bumper aren't in details it is a bot
                        "ecouser" in didsplit[1] or "bumper" in didsplit[1]):
                    tmpbotdetail = str(didsplit[1]).split("/")
                    bumper.bot_add(
                        username,
                        didsplit[0],
                        tmpbotdetail[0],
                        tmpbotdetail[1],
                        "eco-ng",
                    )
                    mqttserverlog.info(
                        f"Bumper Authentication Success - Bot - SN: {username} - DID: {didsplit[0]} - Class: {tmpbotdetail[0]}"
                    )
                    authenticated = True

                else:
                    tmpclientdetail = str(didsplit[1]).split("/")
                    userid = didsplit[0]
                    realm = tmpclientdetail[0]
                    resource = tmpclientdetail[1]

                    if userid == "helperbot":
                        mqttserverlog.info(
                            f"Bumper Authentication Success - Helperbot: {client_id}"
                        )
                        authenticated = True
                    else:
                        auth = False
                        if bumper.check_authcode(didsplit[0], password):
                            auth = True
                        elif bumper.use_auth == False:
                            auth = True

                        if auth:
                            bumper.client_add(userid, realm, resource)
                            mqttserverlog.info(
                                f"Bumper Authentication Success - Client - Username: {username} - ClientID: {client_id}"
                            )
                            authenticated = True

                        else:
                            authenticated = False

            # Check for File Auth
            if username and not authenticated:  # If there is a username and it isn't already authenticated
                hash = self._users.get(username, None)
                if hash:  # If there is a matching entry in passwd, check hash
                    authenticated = pwd_context.verify(password, hash)
                    if authenticated:
                        mqttserverlog.info(
                            f"File Authentication Success - Username: {username} - ClientID: {client_id}"
                        )
                    else:
                        mqttserverlog.info(
                            f"File Authentication Failed - Username: {username} - ClientID: {client_id}"
                        )
                else:
                    mqttserverlog.info(
                        f"File Authentication Failed - No Entry for Username: {username} - ClientID: {client_id}"
                    )

        except Exception as e:
            mqttserverlog.exception("Session: {} - {}".format(
                (kwargs.get("session", None)), e))
            authenticated = False

        # Check for allow anonymous
        allow_anonymous = self.auth_config.get("allow-anonymous", True)
        if allow_anonymous and not authenticated:  # If anonymous auth is allowed and it isn't already authenticated
            authenticated = True
            self.context.logger.debug(
                f"Anonymous Authentication Success: config allows anonymous - Username: {username}"
            )
            mqttserverlog.info(
                f"Anonymous Authentication Success: config allows anonymous - Username: {username}"
            )

        return authenticated
Пример #5
0
    async def authenticate(self, *args, **kwargs):
        if not self.auth_config:
            # auth config section not found
            self.context.logger.warning(
                "'auth' section not found in context configuration"
            )
            return False

        allow_anonymous = self.auth_config.get(
            "allow-anonymous", True
        )  # allow anonymous by default
        if allow_anonymous:
            authenticated = True
            self.context.logger.debug("Authentication success: config allows anonymous")
        else:
            try:
                session = kwargs.get("session", None)
                username = session.username
                password = session.password
                client_id = session.client_id

                didsplit = str(client_id).split("@")
                # If this isn't a fake user (fuid) then add as a bot
                if not (
                    str(didsplit[0]).startswith("fuid")
                    or str(didsplit[0]).startswith("helper")
                ):
                    tmpbotdetail = str(didsplit[1]).split("/")
                    bumper.bot_add(
                        username,
                        didsplit[0],
                        tmpbotdetail[0],
                        tmpbotdetail[1],
                        "eco-ng",
                    )
                    
                    mqttserverlog.debug(
                        "new bot authenticated SN: {} DID: {}".format(
                            username, didsplit[0]
                        )
                    )
                    authenticated = True

                else:
                    tmpclientdetail = str(didsplit[1]).split("/")
                    userid = didsplit[0]
                    realm = tmpclientdetail[0]
                    resource = tmpclientdetail[1]

                    if userid == "helper1":
                        authenticated = True
                    else:
                        auth = False
                        if bumper.check_authcode(didsplit[0], password):
                            auth = True
                        elif bumper.use_auth == False:
                            auth = True

                        if auth:
                            bumper.client_add(userid, realm, resource)
                            mqttserverlog.debug(
                                "client authenticated {}".format(userid)
                            )
                            authenticated = True

                        else:
                            authenticated = False

            except Exception as e:
                mqttserverlog.exception("Session: {} - {}".format((kwargs.get("session", None)),e))
                authenticated = False

        return authenticated
Пример #6
0
async def test_mqttserver():
    if os.path.exists("tests/tmp.db"):
        os.remove("tests/tmp.db")  # Remove existing db

    bumper.db = "tests/tmp.db"  # Set db location for testing

    mqtt_address = ("127.0.0.1", 8883)

    mqtt_server = bumper.MQTTServer(mqtt_address, password_file="tests/passwd", allow_anonymous=True)
    
    await mqtt_server.broker_coro()

    # Test helperbot connect
    mqtt_helperbot = bumper.MQTTHelperBot(mqtt_address)
    await mqtt_helperbot.start_helper_bot()
    assert (
        mqtt_helperbot.Client._connected_state._value == True
    )  # Check helperbot is connected
    await mqtt_helperbot.Client.disconnect()

    # Test client connect
    bumper.user_add("user_123")  # Add user to db
    bumper.client_add("user_123", "ecouser.net", "resource_123")  # Add client to db
    test_client = bumper.MQTTHelperBot(mqtt_address)
    test_client.client_id = "[email protected]/resource_123"
    # await test_client.start_helper_bot()
    test_client.Client = hbmqtt.client.MQTTClient(
        client_id=test_client.client_id, config={"check_hostname": False}
    )

    await test_client.Client.connect(
        "mqtts://{}:{}/".format(test_client.address[0], test_client.address[1]),
        cafile=bumper.ca_cert,
    )
    assert (
        test_client.Client._connected_state._value == True
    )  # Check client is connected
    await test_client.Client.disconnect()
    assert (
        test_client.Client._connected_state._value == False
    )  # Check client is disconnected

    # Test fake_bot connect
    fake_bot = bumper.MQTTHelperBot(mqtt_address)
    fake_bot.client_id = "bot_serial@ls1ok3/wC3g"
    await fake_bot.start_helper_bot()
    assert (
        fake_bot.Client._connected_state._value == True
    )  # Check fake_bot is connected
    await fake_bot.Client.disconnect()

    # Test file auth client connect
    test_client = bumper.MQTTHelperBot(mqtt_address)
    test_client.client_id = "test-file-auth"
    # await test_client.start_helper_bot()
    test_client.Client = hbmqtt.client.MQTTClient(
        client_id=test_client.client_id, config={"check_hostname": False, "auto_reconnect": False, "reconnect_retries": 1}
    )

    # good user/pass
    await test_client.Client.connect(
        f"mqtts://*****:*****@{test_client.address[0]}:{test_client.address[1]}/",
        cafile=bumper.ca_cert, cleansession=True
    )

    assert (
        test_client.Client._connected_state._value == True
    )  # Check client is connected
    await test_client.Client.disconnect()
    assert (
        test_client.Client._connected_state._value == False
    )  # Check client is disconnected
    
    # bad password
    with LogCapture() as l:
        
        await test_client.Client.connect(
            f"mqtts://*****:*****@{test_client.address[0]}:{test_client.address[1]}/",
            cafile=bumper.ca_cert, cleansession=True
        )

        l.check_present(
                ("mqttserver", "INFO", "File Authentication Failed - Username: test-client - ClientID: test-file-auth"),
                order_matters=False
            )
    # no username in file    
        await test_client.Client.connect(
            f"mqtts://*****:*****@{test_client.address[0]}:{test_client.address[1]}/",
            cafile=bumper.ca_cert, cleansession=True
        )


        l.check_present(
            ("mqttserver", "INFO", 'File Authentication Failed - No Entry for Username: test-client-noexist - ClientID: test-file-auth'),
            order_matters=False
        )
    
    await mqtt_server.broker.shutdown()
Пример #7
0
    def _handle_iq_auth(self, data):
        try:
            xml = ET.fromstring(data.decode("utf-8"))
            ctl = xml[0][0]
            xmppserverlog.info("IQ AUTH XML: {}".format(xml))
            # Received username and auth tag, send username/password requirement
            if (
                xml.get("type") == "get"
                and "auth}username" in ctl.tag
                and self.type == self.UNKNOWN
            ):
                self.send(
                    '<iq type="result" id="{}"><query xmlns="jabber:iq:auth"><username/><password/></query></iq>'.format(
                        xml.get("id")
                    )
                )

            # Received username, password, resource - Handle auth here and return pass or fail
            if (
                xml.get("type") == "set"
                and "auth}username" in ctl.tag
                and self.type == self.UNKNOWN
            ):
                xmlauth = xml[0].getchildren()
                # uid = ""
                password = ""
                resource = ""
                for aitem in xmlauth:
                    if "username" in aitem.tag:
                        self.uid = aitem.text

                    elif "password" in aitem.tag:
                        password = aitem.text.split("/")[2]
                        authcode = password

                    elif "resource" in aitem.tag:
                        self.clientresource = aitem.text
                        resource = self.clientresource

                if not self.uid.startswith("fuid"):

                    # Need sample data to see details here
                    bumper.bot_add("", self.uid, "", resource, "eco-legacy")
                    xmppserverlog.info("bot authenticated {}".format(self.uid))

                    # Client authenticated, move to next state
                    self._set_state("INIT")

                    # Successful auth
                    self.send('<iq type="result" id="{}"/>'.format(xml.get("id")))

                else:
                    auth = False
                    if bumper.check_authcode(self.uid, authcode):
                        auth = True
                    elif bumper.use_auth == False:
                        auth = True

                    if auth:
                        bumper.client_add(self.uid, "bumper", self.clientresource)
                        xmppserverlog.debug("client authenticated {}".format(self.uid))

                        # Client authenticated, move to next state
                        self._set_state("INIT")

                        # Successful auth
                        self.send('<iq type="result" id="{}"/>'.format(xml.get("id")))

                    else:
                        # Failed auth
                        self.send(
                            '<iq type="error" id="{}"><error code="401" type="auth"><not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></iq>'.format(
                                xml.get("id")
                            )
                        )

        except ET.ParseError as e:
            if "no element found" in e.msg:
                xmppserverlog.debug(
                    "xml parse error - {} - {}".format(data.decode("utf-8"), e)
                )
            elif "not well-formed (invalid token)" in e.msg:
                xmppserverlog.debug(
                    "xml parse error - {} - {}".format(data.decode("utf-8"), e)
                )
            else:
                xmppserverlog.debug(
                    "xml parse error - {} - {}".format(data.decode("utf-8"), e)
                )

        except Exception as e:
            xmppserverlog.exception("{}".format(e))