Exemplo n.º 1
0
    def get(self, path):
        if Check_state_cookie and GTSocket.get_auth_code():
            state_cookie = self.get_cookie(COOKIE_NAME) or self.get_argument("state_cookie", "")
            if not GTSocket.get_state(state_cookie):
                raise tornado.web.HTTPError(403, "Invalid cookie to access %s", path)

        host, sep, self.file_path = path.partition("/")
        if not host or not self.file_path:
            raise tornado.web.HTTPError(403, "Null host/filename")

        if_mod_since_datetime = None
        if_mod_since = self.request.headers.get("If-Modified-Since")
        if if_mod_since:
            if_mod_since_datetime = gtermhost.str2datetime(if_mod_since)

        self.cached_copy = None
        last_modified = None
        last_modified_datetime = None
        btime, bheaders, bcontent = Proxy_cache.get_blob(self.request.path)
        if bheaders:
            # Path in cache
            last_modified = dict(bheaders).get("Last-Modified")
            if last_modified:
                last_modified_datetime = gtermhost.str2datetime(last_modified)

            if self.request.path.startswith("/blob/"):
                if last_modified_datetime and \
                   if_mod_since_datetime and \
                   if_mod_since_datetime >= last_modified_datetime:
                      # Remote copy is up-to-date
                      self.send_error(304)  # Not modified status code
                      return
                # Return immutable cached blob
                self.finish_write(bheaders, bcontent)
                return

        if self.request.path.startswith("/file/"):
            # Check if access to file is permitted
            self.file_path = "/" + self.file_path

            normalized_host = gtermhost.get_normalized_host(host)
            host_secret = TerminalConnection.host_secrets.get(normalized_host)

            if not host_secret:
                raise tornado.web.HTTPError(403, "Unauthorized access to %s", path)

            shared_secret = self.get_cookie("GRAPHTERM_HOST_"+normalized_host)

            if shared_secret:
                if host_secret != shared_secret:
                    raise tornado.web.HTTPError(403, "Unauthorized access to %s", path)
            else:
                shared_secret = self.get_argument("shared_secret", "")
                check_host = gtermhost.get_normalized_host(self.get_argument("host", ""))
                expect_secret = TerminalConnection.host_secrets.get(check_host)
                if not expect_secret or expect_secret != shared_secret:
                    raise tornado.web.HTTPError(403, "Unauthorized access to %s", path)

            fpath_hmac = hmac.new(str(host_secret), self.file_path, digestmod=hashlib.sha256).hexdigest()[:HEX_DIGITS]
            if fpath_hmac != self.get_argument("hmac", ""):
                raise tornado.web.HTTPError(403, "Unauthorized access to %s", path)

            if bheaders:
                # File copy is cached
                if last_modified_datetime and \
                    if_mod_since_datetime and \
                    if_mod_since_datetime < last_modified_datetime:
                        # Remote copy older than cached copy; change if_mod_since to cache copy time
                        self.cached_copy = (btime, bheaders, bcontent)
                        if_mod_since = last_modified

        self.async_id = self.get_async_id()
        self._async_requests[self.async_id] = self

        self.timeout_callback = IO_loop.add_timeout(time.time()+REQUEST_TIMEOUT, functools.partial(self.complete_request, self.async_id))

        TerminalConnection.send_to_connection(host, "request", "", [["file_request", self.async_id, self.request.method, self.file_path, if_mod_since]])
Exemplo n.º 2
0
    def open(self):
        need_code = bool(self._auth_code)
        need_user = need_code      ##bool(self._auth_users)

        user = ""
        try:
            if not self._auth_code:
                self.authorized = {"user": "", "auth_type": "null_auth", "time": time.time(), "state_id": ""}

            elif COOKIE_NAME in self.request.cookies:
                state_value = self.get_state(self.request.cookies[COOKIE_NAME].value)
                if state_value:
                    self.authorized = state_value

            webcast_auth = False
            if not self.authorized:
                query_data = {}
                if self.request_query:
                    try:
                        query_data = urlparse.parse_qs(self.request_query)
                    except Exception:
                        pass

                user = query_data.get("user", [""])[0]
                code = query_data.get("code", [""])[0]

                expect_code = self._auth_code
                if self._auth_users:
                    if user in self._auth_users:
                        expect_code = self._auth_users[user]
                    else:
                        self.write_json([["authenticate", need_user, need_code, "Invalid user" if user else ""]])
                        self.close()
                        return

                if code == self._auth_code or code == expect_code:
                    state_id = uuid.uuid4().hex[:HEX_DIGITS]
                    self.authorized = {"user": user, "auth_type": "code_auth", "time": time.time(), "state_id": state_id}
                    if len(self._cookie_states) >= MAX_COOKIE_STATES:
                        self._cookie_states.pop(last=False)
                    self._cookie_states[state_id] = self.authorized

                elif self.req_path in self._webcast_paths:
                    self.authorized = {"user": user, "auth_type": "webcast_auth", "time": time.time(), "state_id": ""}
                    webcast_auth = True

            if not self.authorized:
                self.write_json([["authenticate", need_user, need_code, "Authentication failed; retry"]])
                self.close()
                return

            comps = self.req_path.split("/")
            if len(comps) < 1 or not comps[0]:
                host_list = TerminalConnection.get_connection_ids()
                if self._auth_users and self.authorized["user"] not in SUPER_USERS:
                    if LOCAL_HOST in host_list:
                        host_list.remove(LOCAL_HOST)
                host_list.sort()
                self.write_json([["host_list", self.authorized["state_id"], host_list]])
                self.close()
                return

            host = comps[0].lower()
            if not host or not gtermhost.HOST_RE.match(host):
                self.write_json([["abort", "Invalid characters in host name"]])
                self.close()
                return

            if host == LOCAL_HOST and self._auth_users and self.authorized["user"] not in SUPER_USERS: 
                self.write_json([["abort", "Local host access not allowed for user %s" % self.authorized["user"]]])
                self.close()
                return

            wildhost = "?" in host or "*" in host or "[" in host
            term_feedback = False
            
            if wildhost:
                if len(comps) < 2 or not comps[1] or comps[1].lower() == "new":
                    self.write_json([["abort", "Must specify terminal name for wildcard host"]])
                    self.close()
                    return
                term_name = comps[1].lower()
            else:
                conn = TerminalConnection.get_connection(host)
                if not conn:
                    self.write_json([["abort", "Invalid host"]])
                    self.close()
                    return

                if len(comps) < 2 or not comps[1]:
                    term_list = list(conn.term_set)
                    term_list.sort()
                    self.write_json([["term_list", self.authorized["state_id"], host, term_list]])
                    self.close()
                    return

                term_name = comps[1].lower()
                if term_name == "new":
                    term_name = conn.remote_terminal_update()
                    self.write_json([["redirect", "/"+host+"/"+term_name]])
                    self.close()

                if not gtermhost.SESSION_RE.match(term_name):
                    self.write_json([["abort", "Invalid characters in terminal name"]])
                    self.close()
                    return

                term_feedback = term_name in conn.allow_feedback

            path = host + "/" + term_name

            option = comps[2] if len(comps) > 2 else ""

            if option == "kill" and not webcast_auth and not wildhost:
                kill_remote(path)
                return

            self.oshell = (term_name == gtermhost.OSHELL_NAME)

            self._counter[0] += 1
            self.websocket_id = str(self._counter[0])

            if "?" in path or "*" in path or "[" in path:
                self.wildcard = re.compile("^"+path.replace("+", "\\+").replace(".", "\\.").replace("?", ".?").replace("*", ".*")+"$")
                self._wildcards[path] = (self.wildcard, self.websocket_id)

            self._watch_set[path].add(self.websocket_id)
            if webcast_auth:
                self.controller = False
            elif self.wildcard:
                self.controller = True
            elif option == "share":
                self.controller = True
                self._control_set[path].add(self.websocket_id)
            elif option == "steal":
                msg = ["update", "controller", False]
                for ws_id in self._control_set[path]:
                    ws = GTSocket._all_websockets.get(ws_id)
                    if ws and ws_id != self.websocket_id:
                        ws.write_json([msg])
                self.controller = True
                self._control_set[path] = set([self.websocket_id])
            elif option == "watch" or (path in self._control_set and self._control_set[path]):
                self.controller = False
            else:
                self.controller = True
                self._control_set[path] = set([self.websocket_id])

            self.remote_path = path
            self._all_websockets[self.websocket_id] = self
            if user:
                self._all_users[user][self.websocket_id] = self

            display_splash = self.controller and self._counter[0] <= 2
            normalized_host, host_secret = "", ""
            if not self.wildcard:
                TerminalConnection.send_to_connection(host, "request", term_name, [["reconnect", self.websocket_id]])
                normalized_host = gtermhost.get_normalized_host(host)
                if self.authorized["auth_type"] in ("null_auth", "code_auth"):
                    host_secret = TerminalConnection.host_secrets.get(normalized_host)
            self.write_json([["setup", {"host": host, "term": term_name, "oshell": self.oshell,
                                        "host_secret": host_secret, "normalized_host": normalized_host,
                                        "about_version": about.version, "about_authors": about.authors,
                                        "about_url": about.url, "about_description": about.description,
                                        "controller": self.controller,
                                        "wildcard": bool(self.wildcard), "display_splash": display_splash,
                                        "apps_url": APPS_URL, "feedback": term_feedback,
                                        "state_id": self.authorized["state_id"]}]])
        except Exception, excp:
            logging.warning("GTSocket.open: ERROR %s", excp)
            self.close()