def auth_keys(self, request, token): """ Log in using pre-shared keys. (POST) """ logging.debug('auth_keys, request: {0}'.format(request)) def fail(empty): logging.debug("Login/keys request fail.") wbSession = self.get_session(request) wbSession.reset() return self.return_unauthorized(request) # get and verify parameters signature = self.get_arg(request, "signature") key_hash = self.get_arg(request, "key_hash") algo = self.get_arg(request, "algo") method = self.get_arg(request, "method") encpk2 = self.get_arg(request, "encpk2") if signature is None or key_hash is None or algo is None or method is None or encpk2 is None: logging.error( "auth_keys error, signature, key, algo, method, or encpk2 is None, returning unauthorized" ) return fail() try: signature = long(signature) except Exception as e: logging.error( "auth_keys error, signature was not a valid Long, returning unauthorized" ) return fail() sessionid = request.getSession().uid def win(response): user, password, box = response logging.debug("Login/keys request win.") wbSession = self.get_session(request) wbSession.setAuthenticated(True) wbSession.setUser(user) wbSession.setUserType("auth") wbSession.limit_boxes = [box] # only allow access to this box wbSession.setPassword(password) self.return_ok(request) auth_keys(self.webserver.keystore, signature, key_hash, algo, method, sessionid, encpk2).addCallbacks(win, fail)
def auth_keys(self, request, token): """ Log in using pre-shared keys. (POST) """ logging.debug('auth_keys, request: {0}'.format(request)); def fail(empty): logging.debug("Login/keys request fail.") wbSession = self.get_session(request) wbSession.reset() return self.return_unauthorized(request) # get and verify parameters signature = self.get_arg(request, "signature") key_hash = self.get_arg(request, "key_hash") algo = self.get_arg(request, "algo") method = self.get_arg(request, "method") encpk2 = self.get_arg(request, "encpk2") if signature is None or key_hash is None or algo is None or method is None or encpk2 is None: logging.error("auth_keys error, signature, key, algo, method, or encpk2 is None, returning unauthorized") return fail() try: signature = long(signature) except Exception as e: logging.error("auth_keys error, signature was not a valid Long, returning unauthorized") return fail() sessionid = request.getSession().uid def win(response): user, password, box = response logging.debug("Login/keys request win.") wbSession = self.get_session(request) wbSession.setAuthenticated(True) wbSession.setUser(user) wbSession.setUserType("auth") wbSession.limit_boxes = [box] # only allow access to this box wbSession.setPassword(password) self.return_ok(request) auth_keys(self.webserver.keystore, signature, key_hash, algo, method, sessionid, encpk2).addCallbacks(win, fail)
def send_to_observer(self, data): # manage connections coming back from server first.. # TODO imple if data.get("action") == "diff" and data.get( "operation") == "start": def store_cb(store): logging.debug( "WebSocketsHandler listen_diff, store_cb: {0}". format(store)) def observer_local(diff): """ Receive an update from the server. """ logging.debug( "WebSocketsHandler listen_diff observer notified: {0}" .format(diff)) self.sendMessage( json.loads({ "action": "diff", "operation": "update", "data": diff })) store.listen( observer_local) # no callbacks, nothing to do # self.token is set by 'login_keys' below self.token.get_store().addCallbacks( store_cb, lambda failure: self.sendMessage( json.loads({ "success": False, "error": "500 Internal Server Error" }))) elif data.get("action") == "login_keys": try: signature, key_hash, algo, method, appid, encpk2 = data[ 'signature'], data['key_hash'], data['algo'], data[ 'method'], data['appid'], data['encpk2'] except Exception as e: logging.error( "IndxClient/ASync login_keys error getting all parameters." ) return self.sendMessage( json.loads({ "success": False, "error": "400 Bad Request" })) def win(resp): # authenticated now - state of this isn't saved though, we get a token immediately instead username, password, boxid = resp origin = "/ws" # TODO double-check this # get token, return that def got_acct(acct): if acct == False: return self.send401() db_user, db_pass = acct def token_cb(new_token): self.token = new_token def store_cb(store): # success, send token back to user return self.sendMessage( json.loads({ "success": True, "token": new_token.id, "respond_to": "login_keys" })) new_token.get_store().addCallbacks( store_cb, lambda failure: json. loads({ "success": False, "error": "500 Internal Server Error" })) # TODO extract IP from 'address' above webserver.tokens.new( username, password, boxid, appid, origin, "::1", webserver.server_id).addCallbacks( token_cb, lambda failure: json. loads({ "success": False, "error": "500 Internal Server Error" })) webserver.database.lookup_best_acct( boxid, username, password).addCallbacks( got_acct, lambda conn: json.loads( { "success": False, "error": "500 Internal Server Error" })) def fail(empty): self.sendMessage( json.loads({ "success": False, "error": "401 Unauthorized" })) auth_keys(keystore, signature, key_hash, algo, method, self.sessionid, encpk2).addCallbacks(win, fail) else: # otherwise send diffs back to indx indx_observer(data)
def receive(self, frame): """ Send data here when it is received from the real transport. """ try: def err_cb(failure): logging.error("WebSocketsHandler receive, err_cb: {0}".format(failure)) data = json.loads(frame) requestid = data.get("requestid") if data.get("action") == "diff" and data.get("operation") == "update": # received after login_keys succeeds and we send the diff/start message self.remote_observer(data) return if data.get("action") == "http": # a call to an http request, over the websocket (via the reactor mappings) logging.debug("Async got an http request, data: {0}".format(data)) request = data.get("request") #session = data.get("sessionid") session = None #if session is None: # return self.send400(requestid, "http", data = {"error": "'sessionid' required in 'http'" }) #session = self.sessionid # TODO enable multiple sessions per websocket logging.debug("Async got an http request: {0} in session {1}".format(request, session)) def req_cb(response): logging.debug("ASync sending http response in session: {0}".format(session)) frame = {"respond_to": "http", "response": response.to_json()} if session is not None: frame['session'] = session self.sendJSON(requestid, frame, "http") base_path = request.get("path") if base_path[0] == "/": base_path = base_path[1:] indx_request = IndxRequest( request.get("uri"), request.get("method"), base_path.split("/")[0], # e.g. box name / or auth/admin request.get("path"), request.get("params"), request.get("content"), session, req_cb, self.clientip, self.webserver.server_id ) self.webserver.indx_reactor.incoming(indx_request) return elif data.get("action") == "echo": logging.debug("Async got an echo request: {0}".format(data)) self.sendJSON(requestid, {}, "echo") return elif data.get("action") == "response": if data.get('respond_to') == "login_keys": # a response to our attempt to re-connect back to the client logging.debug("Async got a respond to login_keys: {0}".format(data)) # TODO handle errors self.sendJSON(requestid, {"action": "diff", "operation": "start"}, "login_keys") return else: respond_to = data.get("respond_to") # could be None self.send400(requestid, data.get("action"), data = {"error": "'respond_to' value of '{0}' is unknown for action 'response'.".format(respond_to)}) return elif data['action'] == "auth": def token_cb(token): try: if token is None: return self.send401(requestid, "auth") logging.debug("WebSocketsHandler Auth by Token {0} successful.".format(data.get('token'))) self.tokens[data.get('token')] = token return self.send200(requestid, "auth") except Exception as e: logging.error("WebSocketsHandler frameReceived, token error: {0}".format(e)) return self.send401(requestid, "auth") if not "token" in data: return self.send400(requestid, data.get("action"), data={"error": "'token' must be specified for action 'auth'."}) else: return self.tokenkeeper.get(data.get('token')).addCallbacks(token_cb, err_cb) elif data['action'] == "login_keys": if requestid is None: return self.send400(requestid, "login_keys", data = {"error": "'requestid' required for action 'login_keys'"}) try: signature, key_hash, algo, method, appid, encpk2 = data['signature'], data['key_hash'], data['algo'], data['method'], data['appid'], data['encpk2'] except Exception as e: logging.error("ASync login_keys error getting all parameters.") return self.send400(requestid, "login_keys") def win(resp): # authenticated now - state of this isn't saved though, we get a token immediately instead username, password, boxid = resp origin = "/ws" # TODO double-check this # get token, return that def got_acct(acct): if acct == False: return self.send401(requestid, "login_keys") db_user, db_pass = acct def token_cb(token): def store_cb(store): # success, send token back to user # first, try to connect back through the websocket self.tokens[token.id] = token self.connectBackToClient(key_hash, store).addCallbacks(lambda empty: logging.debug("ASync, success connecting back."), lambda failure: logging.error("ASync, failure connecting back: {0}".format(failure))) return self.send200(requestid, "login_keys", data = {"token": token.id}) token.get_store().addCallbacks(store_cb, lambda failure: self.send500(requestid, "login_keys")) self.webserver.tokens.new(username,password,boxid,appid,origin,self.clientip,self.webserver.server_id).addCallbacks(token_cb, lambda failure: self.send500(requestid, "login_keys")) self.webserver.database.lookup_best_acct(boxid, username, password).addCallbacks(got_acct, lambda conn: self.send401(requestid, "login_keys")) def fail(empty): self.send401(requestid, "login_keys") auth_keys(self.webserver.keystore, signature, key_hash, algo, method, requestid, encpk2).addCallbacks(win, fail) return elif data['action'] == "diff": # turn on/off diff listening token = data.get("token") if token is None: return self.send400(requestid, "diff", data = {"error": "'token' required for diff"}) try: operation = data.get("operation").lower() except Exception as e: return self.send400(requestid, "diff", data = {"error": "no valid 'operation' found."}) diffid = data.get("diffid") if operation != 'start': # only 'start' is allowed to not have a diff if diffid is None: return self.send400(requestid, "diff", data = {"error": "'diffid' required for diff"}) elif diffid not in self.listeners: return self.send400(requestid, "diff", data = {"error": "Existing diff with diffid '{0}' does not exist".format(diffid)}) # check that the 'ids' field is present and an array - sends a 400 back if not def check_ids(): if not data.get("ids") or type(data.get("ids")) != type([]): self.send400(requestid, "diff", data = {"error": "This action and operation requires an 'ids' field as an array of object IDs."}) return False return True # operation functions def op_start(): diffid = "{0}".format(uuid.uuid1()) # generate new diffid def started_cb(listener): logging.debug("WebSocketsHandler diff action response: {0}".format(operation)) self.send200(requestid, "diff", data = {"diffid": diffid, "respond_to": "diff/{0}".format(operation)}) def diff_err_cb(failure): logging.error("WebSocketsHandler diff action error: {0}".format(failure.value)) failure.trap(Exception) self.send400(requestid, "diff", data = {"error": "{0}".format(failure.value)}) def store_cb(store): self.listeners[diffid] = IndxDiffListener(store, requestid, diffid, self.sendJSON) if data.get("ids"): self.listeners[diffid].setIDs(data.get("ids")) if data.get("query"): self.listeners[diffid].setQuery(data.get("query")) self.listeners[diffid].subscribe().addCallbacks(started_cb, diff_err_cb) self.get_store_from_tokenid(token).addCallbacks(store_cb, diff_err_cb) def op_stop(): self.listeners[diffid].unsubscribe() del self.listeners[diffid] self.send200(requestid, "diff", data = {"diffid": diffid, "respond_to": "diff/{0}".format(operation)}) def op_addids(): if not check_ids(): return self.listeners[diffid].addIDs(data.get("ids")) self.send200(requestid, "diff", data = {"diffid": diffid, "respond_to": "diff/{0}".format(operation)}) def op_setids(): if not check_ids(): return self.listeners[diffid].setIDs(data.get("ids")) self.send200(requestid, "diff", data = {"diffid": diffid, "respond_to": "diff/{0}".format(operation)}) def op_removeids(): if not check_ids(): return self.listeners[diffid].removeIDs(data.get("ids")) self.send200(requestid, "diff", data = {"diffid": diffid, "respond_to": "diff/{0}".format(operation)}) def op_setquery(): if not (data.get("query") or type(data.get("query")) != type("")): return self.send400(requestid, "diff", data = {"error": "This action and operation requires a string 'query' field."}) self.listeners[diffid].setQuery(data.get("query")) self.send200(requestid, "diff", data = {"diffid": diffid, "respond_to": "diff/{0}".format(operation)}) ops = { "start": op_start, "stop": op_stop, "addids": op_addids, "setids": op_setids, "removeids": op_removeids, "setquery": op_setquery, } if operation in ops: return ops[operation]() else: return self.send400(requestid, "diff", data = {"error": "no valid 'operation' found."}) else: action = data.get("action") # could be None return self.send400(requestid, action, data = {"error": "'action' value of '{0}' is unknown".format(action)}) except Exception as e: logging.error("WebSocketsHandler frameRecevied, error: {0},\n trace: {1}".format(e, traceback.format_exc())) return self.send500(requestid, data.get("action"))
def send_to_observer(self, data): # manage connections coming back from server first.. # TODO imple if data.get("action") == "diff" and data.get("operation") == "start": def store_cb(store): logging.debug("WebSocketsHandler listen_diff, store_cb: {0}".format(store)) def observer_local(diff): """ Receive an update from the server. """ logging.debug("WebSocketsHandler listen_diff observer notified: {0}".format(diff)) self.sendMessage(json.loads({"action": "diff", "operation": "update", "data": diff})) store.listen(observer_local) # no callbacks, nothing to do # self.token is set by 'login_keys' below self.token.get_store().addCallbacks(store_cb, lambda failure: self.sendMessage(json.loads({"success": False, "error": "500 Internal Server Error"}))) elif data.get("action") == "login_keys": try: signature, key_hash, algo, method, appid, encpk2 = data['signature'], data['key_hash'], data['algo'], data['method'], data['appid'], data['encpk2'] except Exception as e: logging.error("IndxClient/ASync login_keys error getting all parameters.") return self.sendMessage(json.loads({"success": False, "error": "400 Bad Request"})) def win(resp, data): # authenticated now - state of this isn't saved though, we get a token immediately instead username, password, boxid = resp origin = "/ws" # TODO double-check this # get token, return that def got_acct(acct): if acct == False: return self.send401() db_user, db_pass = acct def token_cb(new_token): self.token = new_token def store_cb(store): # success, send token back to user msg = {"action": "response", "success": True, "token": new_token.id, "respond_to": "login_keys"} if data.get("requestid"): msg['requestid'] = data.get("requestid") return self.sendMessage(json.loads(msg)) new_token.get_store().addCallbacks(store_cb, lambda failure: json.loads({"success": False, "error": "500 Internal Server Error"})) # TODO extract IP from 'address' above webserver.tokens.new(username,password,boxid,appid,origin,"::1",webserver.server_id).addCallbacks(token_cb, lambda failure: json.loads({"success": False, "error": "500 Internal Server Error"})) webserver.database.lookup_best_acct(boxid, username, password).addCallbacks(got_acct, lambda conn: json.loads({"success": False, "error": "500 Internal Server Error"})) def fail(empty): self.sendMessage(json.loads({"success": False, "error": "401 Unauthorized"})) auth_keys(keystore, signature, key_hash, algo, method, self.sessionid, encpk2).addCallbacks(lambda resp: win(resp, data), fail) else: # otherwise send diffs back to indx indx_observer(data)
def receive(self, frame): """ Send data here when it is received from the real transport. """ try: def err_cb(failure): logging.error( "WebSocketsHandler receive, err_cb: {0}".format(failure)) data = json.loads(frame) if data.get("action") == "diff" and data.get( "operation") == "update": # received after login_keys succeeds and we send the diff/start message self.remote_observer(data) return elif data.get('respond_to') == "login_keys": # a response to our attempt to re-connect back to the client logging.debug( "Async got a respond to login_keys: {0}".format(data)) # TODO handle errors self.sendJSON({"action": "diff", "operation": "start"}) return elif data['action'] == "auth": def token_cb(token): try: if token is None: self.send401() return logging.debug( "WebSocketsHandler Auth by Token {0} successful.". format(data['token'])) self.token = token # also tell the webserver we just got a successful auth from an outside client via websocket # so it can try to connect back over this websocket. # self.webserver. self.send200() return except Exception as e: logging.error( "WebSocketsHandler frameReceived, token error: {0}" .format(e)) self.send401() return self.tokens.get(data['token']).addCallbacks(token_cb, err_cb) elif data['action'] == "get_session_id": self.send200(data={'sessionid': self.sessionid}) elif data['action'] == "login_keys": try: signature, key_hash, algo, method, appid, encpk2 = data[ 'signature'], data['key_hash'], data['algo'], data[ 'method'], data['appid'], data['encpk2'] except Exception as e: logging.error( "ASync login_keys error getting all parameters.") return self.send400() def win(resp): # authenticated now - state of this isn't saved though, we get a token immediately instead username, password, boxid = resp origin = "/ws" # TODO double-check this # get token, return that def got_acct(acct): if acct == False: return self.send401() db_user, db_pass = acct def token_cb(token): def store_cb(store): # success, send token back to user # first, try to connect back through the websocket self.token = token self.connectBackToClient( key_hash, store ).addCallbacks( lambda empty: logging.debug( "ASync, success connecting back."), lambda failure: logging.error( "ASync, failure connecting back: {0}". format(failure))) return self.send200(data={ "token": token.id, "respond_to": "login_keys" }) token.get_store().addCallbacks( store_cb, lambda failure: self.send500()) self.webserver.tokens.new( username, password, boxid, appid, origin, self.clientip, self.webserver.server_id).addCallbacks( token_cb, lambda failure: self.send500()) self.webserver.database.lookup_best_acct( boxid, username, password).addCallbacks(got_acct, lambda conn: self.send401()) def fail(empty): self.send401() auth_keys(self.webserver.keystore, signature, key_hash, algo, method, self.sessionid, encpk2).addCallbacks(win, fail) elif data['action'] == "diff": # turn on/off diff listening if data['operation'] == "start": self.listen_diff() self.send200() return elif data['operation'] == "stop": #self.stop_listen() self.send200() return else: self.send400() return else: self.send400() return except Exception as e: logging.error( "WebSocketsHandler frameRecevied, error: {0}".format(e)) self.send500() return