Example #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))
Example #2
0
def test_user_db():
    if os.path.exists("tests/tmp.db"):
        os.remove("tests/tmp.db")  # Remove existing db

    # Test os_db_path
    platform.system = mock.MagicMock(return_value="Windows")
    p = platform.system()
    os.getenv = mock.MagicMock(return_value="C:\AppData")
    o = os.getenv("APPDATA")
    assert_equals(bumper.os_db_path(),
                  os.path.join(os.getenv("APPDATA"), "bumper.db"))

    platform.system = mock.MagicMock(return_value="Linux")
    assert_equals(bumper.os_db_path(),
                  os.path.expanduser("~/.config/bumper.db"))

    bumper.db = "tests/tmp.db"  # Set db location for testing
    bumper.user_add("testuser")  # Add testuser

    assert_equals(bumper.user_get("testuser")["userid"],
                  "testuser")  # Test that testuser was created and returned

    bumper.user_add_device("testuser", "dev_1234")  # Add device to testuser

    assert_equals(bumper.user_by_deviceid("dev_1234")["userid"],
                  "testuser")  # Test that testuser was found by deviceid

    bumper.user_remove_device("testuser",
                              "dev_1234")  # Remove device from testuser

    assert_true(
        "dev_1234" not in bumper.user_get("testuser")
        ["devices"])  # Test that dev_1234 was not found in testuser devices

    bumper.user_add_bot("testuser", "bot_1234")  # Add bot did to testuser

    assert_true("bot_1234" in bumper.user_get("testuser")
                ["bots"])  # Test that bot was found in testuser's bot list

    bumper.user_remove_bot("testuser",
                           "bot_1234")  # Remove bot did from testuser

    assert_true("bot_1234" not in bumper.user_get("testuser")
                ["bots"])  # Test that bot was not found in testuser's bot list

    bumper.user_add_token("testuser", "token_1234")  # Add token to testuser

    assert_true(bumper.check_token(
        "testuser", "token_1234"))  # Test that token was found for testuser

    assert_true(bumper.user_get_token(
        "testuser", "token_1234"))  # Test that token was returned for testuser

    bumper.user_add_authcode(
        "testuser", "token_1234",
        "auth_1234")  # Add authcode to token_1234 for testuser
    assert_true(bumper.check_authcode(
        "testuser", "auth_1234"))  # Test that authcode was found for testuser

    bumper.user_revoke_authcode("testuser", "token_1234",
                                "auth_1234")  # Remove authcode from testuser
    assert_false(bumper.check_authcode(
        "testuser",
        "auth_1234"))  # Test that authcode was not found for testuser
    bumper.user_revoke_token("testuser",
                             "token_1234")  # Remove token from testuser
    assert_false(bumper.check_token(
        "testuser",
        "token_1234"))  # Test that token was not found for testuser
    bumper.user_add_token("testuser", "token_1234")  # Add token_1234
    bumper.user_add_token("testuser", "token_4321")  # Add token_4321
    assert_equals(len(bumper.user_get_tokens("testuser")),
                  2)  # Test 2 tokens are available
    bumper.user_revoke_all_tokens("testuser")  # Revoke all tokens
    assert_equals(len(bumper.user_get_tokens("testuser")),
                  0)  # Test 0 tokens are available

    db = TinyDB("tests/tmp.db")
    tokens = db.table("tokens")
    tokens.insert({
        "userid":
        "testuser",
        "token":
        "token_1234",
        "expiration":
        "{}".format(datetime.datetime.now() + datetime.timedelta(seconds=-10)),
    })  # Add expired token
    db.close()
    assert_equals(len(bumper.user_get_tokens("testuser")),
                  1)  # Test 1 tokens are available
    bumper.user_revoke_expired_tokens("testuser")  # Revoke expired tokens
    assert_equals(len(bumper.user_get_tokens("testuser")),
                  0)  # Test 0 tokens are available

    db = TinyDB("tests/tmp.db")
    tokens = db.table("tokens")
    tokens.insert({
        "userid":
        "testuser",
        "token":
        "token_1234",
        "expiration":
        "{}".format(datetime.datetime.now() + datetime.timedelta(seconds=-10)),
    })  # Add expired token
    db.close()
    assert_equals(len(bumper.user_get_tokens("testuser")),
                  1)  # Test 1 tokens are available
    bumper.revoke_expired_tokens()  # Revoke expired tokens
    assert_equals(len(bumper.user_get_tokens("testuser")),
                  0)  # Test 0 tokens are available
Example #3
0
    async def handle_usersapi(self, request):
        if not request.method == "GET":  # Skip GET for now
            try:

                body = {}
                postbody = {}
                if request.content_type == "application/x-www-form-urlencoded":
                    postbody = await request.post()

                else:
                    postbody = json.loads(await request.text())

                todo = postbody["todo"]
                if todo == "FindBest":
                    service = postbody["service"]
                    if service == "EcoMsgNew":
                        body = {
                            "result": "ok",
                            "ip": socket.gethostbyname(socket.gethostname()),
                            "port": 5223,
                        }
                    elif service == "EcoUpdate":
                        body = {"result": "ok", "ip": "47.88.66.164", "port": 8005}

                elif todo == "loginByItToken":
                    if bumper.check_authcode(postbody["userId"], postbody["token"]):
                        body = {
                            "resource": postbody["resource"],
                            "result": "ok",
                            "todo": "result",
                            "token": postbody["token"],
                            "userId": postbody["userId"],
                        }

                elif todo == "GetDeviceList":
                    body = {
                        "devices": bumper.db_get().table("bots").all(),
                        "result": "ok",
                        "todo": "result",
                    }

                elif todo == "SetDeviceNick":
                    bumper.bot_set_nick(postbody["did"], postbody["nick"])
                    body = {"result": "ok", "todo": "result"}

                elif todo == "AddOneDevice":
                    bumper.bot_set_nick(postbody["did"], postbody["nick"])
                    body = {"result": "ok", "todo": "result"}

                elif todo == "DeleteOneDevice":
                    bumper.bot_remove(postbody["did"])
                    body = {"result": "ok", "todo": "result"}

                confserverlog.debug(
                    "\r\n POST: {} \r\n Response: {}".format(postbody, body)
                )

                return web.json_response(body)

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

        # Return fail for GET
        body = {"result": "fail", "todo": "result"}
        return web.json_response(body)
Example #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
Example #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
Example #6
0
def test_user_db():

    bumper.db = "tests/tmp.db"  # Set db location for testing
    bumper.user_add("testuser")  # Add testuser

    assert (bumper.user_get("testuser")["userid"] == "testuser"
            )  # Test that testuser was created and returned

    bumper.user_add_device("testuser", "dev_1234")  # Add device to testuser

    assert (bumper.user_by_deviceid("dev_1234")["userid"] == "testuser"
            )  # Test that testuser was found by deviceid

    bumper.user_remove_device("testuser",
                              "dev_1234")  # Remove device from testuser

    assert "dev_1234" not in bumper.user_get("testuser")["devices"]
    # Test that dev_1234 was not found in testuser devices

    bumper.user_add_bot("testuser", "bot_1234")  # Add bot did to testuser

    assert "bot_1234" in bumper.user_get("testuser")["bots"]
    # Test that bot was found in testuser's bot list

    bumper.user_remove_bot("testuser",
                           "bot_1234")  # Remove bot did from testuser

    assert "bot_1234" not in bumper.user_get("testuser")["bots"]
    # Test that bot was not found in testuser's bot list

    bumper.user_add_token("testuser", "token_1234")  # Add token to testuser

    assert bumper.check_token("testuser", "token_1234")
    # Test that token was found for testuser

    assert bumper.user_get_token("testuser", "token_1234")
    # Test that token was returned for testuser

    bumper.user_add_authcode(
        "testuser", "token_1234",
        "auth_1234")  # Add authcode to token_1234 for testuser
    assert bumper.check_authcode("testuser", "auth_1234")
    # Test that authcode was found for testuser

    bumper.user_revoke_authcode("testuser", "token_1234",
                                "auth_1234")  # Remove authcode from testuser
    assert bumper.check_authcode("testuser", "auth_1234") == False
    # Test that authcode was not found for testuser
    bumper.user_revoke_token("testuser",
                             "token_1234")  # Remove token from testuser
    assert (bumper.check_token("testuser", "token_1234") == False
            )  # Test that token was not found for testuser
    bumper.user_add_token("testuser", "token_1234")  # Add token_1234
    bumper.user_add_token("testuser", "token_4321")  # Add token_4321
    assert len(
        bumper.user_get_tokens("testuser")) == 2  # Test 2 tokens are available
    bumper.user_revoke_all_tokens("testuser")  # Revoke all tokens
    assert len(
        bumper.user_get_tokens("testuser")) == 0  # Test 0 tokens are available

    db = TinyDB("tests/tmp.db")
    tokens = db.table("tokens")
    tokens.insert({
        "userid":
        "testuser",
        "token":
        "token_1234",
        "expiration":
        "{}".format(datetime.now() + timedelta(seconds=-10)),
    })  # Add expired token
    db.close()
    assert len(
        bumper.user_get_tokens("testuser")) == 1  # Test 1 tokens are available
    bumper.user_revoke_expired_tokens("testuser")  # Revoke expired tokens
    assert len(
        bumper.user_get_tokens("testuser")) == 0  # Test 0 tokens are available

    db = TinyDB("tests/tmp.db")
    tokens = db.table("tokens")
    tokens.insert({
        "userid":
        "testuser",
        "token":
        "token_1234",
        "expiration":
        "{}".format(datetime.now() + timedelta(seconds=-10)),
    })  # Add expired token
    db.close()
    assert len(
        bumper.user_get_tokens("testuser")) == 1  # Test 1 tokens are available
    bumper.revoke_expired_tokens()  # Revoke expired tokens
    assert len(
        bumper.user_get_tokens("testuser")) == 0  # Test 0 tokens are available
Example #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))
    async def handle_usersapi(self, request):
        if not request.method == "GET":  # Skip GET for now
            try:

                body = {}
                postbody = {}
                if request.content_type == "application/x-www-form-urlencoded":
                    postbody = await request.post()

                else:
                    postbody = json.loads(await request.text())

                todo = postbody["todo"]
                if todo == "FindBest":
                    service = postbody["service"]
                    if service == "EcoMsgNew":
                        srvip = bumper.bumper_announce_ip
                        srvport = 5223
                        logging.info(
                            "Announcing EcoMsgNew Server to bot as: {}:{}".
                            format(srvip, srvport))
                        msgserver = {
                            "ip": srvip,
                            "port": srvport,
                            "result": "ok"
                        }
                        msgserver = json.dumps(msgserver)
                        msgserver = msgserver.replace(
                            " ", ""
                        )  # bot seems to be very picky about having no spaces, only way was with text

                        return web.json_response(text=msgserver)

                    elif service == "EcoUpdate":
                        srvip = "47.88.66.164"  # EcoVacs Server
                        srvport = 8005
                        logging.info(
                            "Announcing EcoUpdate Server to bot as: {}:{}".
                            format(srvip, srvport))
                        body = {"result": "ok", "ip": srvip, "port": srvport}

                elif todo == "loginByItToken":
                    if "userId" in postbody:
                        if bumper.check_authcode(postbody["userId"],
                                                 postbody["token"]):
                            body = {
                                "resource": postbody["resource"],
                                "result": "ok",
                                "todo": "result",
                                "token": postbody["token"],
                                "userId": postbody["userId"],
                            }
                    else:  # EcoVacs Home LoginByITToken
                        loginToken = bumper.loginByItToken(postbody["token"])
                        if not loginToken == {}:
                            body = {
                                "resource": postbody["resource"],
                                "result": "ok",
                                "todo": "result",
                                "token": loginToken["token"],
                                "userId": loginToken["userid"],
                            }
                        else:
                            body = {"result": "fail", "todo": "result"}

                elif todo == "GetDeviceList":
                    body = {
                        "devices": bumper.db_get().table("bots").all(),
                        "result": "ok",
                        "todo": "result",
                    }

                elif todo == "SetDeviceNick":
                    bumper.bot_set_nick(postbody["did"], postbody["nick"])
                    body = {"result": "ok", "todo": "result"}

                elif todo == "AddOneDevice":
                    bumper.bot_set_nick(postbody["did"], postbody["nick"])
                    body = {"result": "ok", "todo": "result"}

                elif todo == "DeleteOneDevice":
                    bumper.bot_remove(postbody["did"])
                    body = {"result": "ok", "todo": "result"}

                return web.json_response(body)

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

        # Return fail for GET
        body = {"result": "fail", "todo": "result"}
        return web.json_response(body)