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))
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
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)
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
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
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
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)