Esempio n. 1
0
    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)
Esempio n. 2
0
File: auth.py Progetto: imclab/indx
    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)
Esempio n. 3
0
            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)
Esempio n. 4
0
File: async.py Progetto: sociam/indx
    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"))
Esempio n. 5
0
            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)
Esempio n. 6
0
    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