Example #1
0
        /* TODO: Figure out how PollServiceHTTPHandler can access the request headers
         * in order to use m_AllowedOrigin as a regular expression
         * private Hashtable CheckOrigin(Hashtable headers, Hashtable result)
         * {
         *  if (!string.IsNullOrEmpty(m_AllowedOrigin))
         *  {
         *      if (headers.ContainsKey("origin"))
         *      {
         *          string origin = headers["origin"].ToString();
         *          if (Regex.IsMatch(origin, m_AllowedOrigin))
         *              result["access_control_allow_origin"] = origin;
         *      }
         *  }
         *  return result;
         * }
         */

        private void DoExpire()
        {
            List <UUID>             expired  = new List <UUID>();
            List <AsyncHttpRequest> requests = new List <AsyncHttpRequest>();

            lock (m_Connections)
            {
                foreach (KeyValuePair <UUID, ConsoleConnection> kvp in m_Connections)
                {
                    if (System.Environment.TickCount - kvp.Value.last > 500000)
                    {
                        expired.Add(kvp.Key);
                    }
                }

                foreach (UUID id in expired)
                {
                    ConsoleConnection connection = m_Connections[id];
                    m_Connections.Remove(id);
                    CloseConnection(id);
                    if (connection.request != null)
                    {
                        requests.Add(connection.request);
                        connection.request = null;
                    }
                }
            }

            foreach (AsyncHttpRequest request in requests)
            {
                request.SendResponse(ProcessEvents(request));
            }
        }
Example #2
0
        private Hashtable HandleHttpCloseSession(Hashtable request)
        {
            DoExpire();

            Hashtable post  = DecodePostString(request["body"].ToString());
            Hashtable reply = new Hashtable();

            reply["str_response_string"] = "";
            reply["int_response_code"]   = 404;
            reply["content_type"]        = "text/plain";

            if (post["ID"] == null)
            {
                return(reply);
            }

            UUID id;

            if (!UUID.TryParse(post["ID"].ToString(), out id))
            {
                return(reply);
            }

            lock (m_Connections)
            {
                if (m_Connections.ContainsKey(id))
                {
                    ConsoleConnection connection = m_Connections[id];
                    m_Connections.Remove(id);
                    CloseConnection(id);
                    if (connection.request != null)
                    {
                        AsyncHttpRequest req = connection.request;
                        connection.request = null;
                        req.SendResponse(ProcessEvents(req));
                    }
                }
            }

            XmlDocument xmldoc  = new XmlDocument();
            XmlNode     xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, "", "");

            xmldoc.AppendChild(xmlnode);
            XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", "");

            xmldoc.AppendChild(rootElement);

            XmlElement res = xmldoc.CreateElement("", "Result", "");

            res.AppendChild(xmldoc.CreateTextNode("OK"));

            rootElement.AppendChild(res);

            reply["str_response_string"] = xmldoc.InnerXml;
            reply["int_response_code"]   = 200;
            reply["content_type"]        = "text/xml";
            reply = CheckOrigin(reply);

            return(reply);
        }
        private bool HasEvents(UUID RequestID, UUID sessionID)
        {
            ConsoleConnection c = null;

            if (!m_Connections.TryGetValue(sessionID, out c))
            {
                return(false);
            }
            c.last = System.Environment.TickCount;
            if (c.lastLineSeen < m_LineNumber)
            {
                return(true);
            }
            return(false);
        }
Example #4
0
        private bool HasEvents(UUID RequestID, UUID sessionID)
        {
            ConsoleConnection c = null;

            lock (m_Connections)
            {
                if (!m_Connections.ContainsKey(sessionID))
                {
                    return(false);
                }
                c = m_Connections[sessionID];
            }
            c.last = Environment.TickCount;

            return(c.lastLineSeen < m_LineNumber);
        }
Example #5
0
        // Check if there is anything to send. Return true if this client has
        // lines pending.
        protected bool HasEvents(UUID RequestID, UUID sessionID)
        {
            ConsoleConnection c = null;

            lock (m_Connections)
            {
                if (!m_Connections.ContainsKey(sessionID))
                {
                    return(false);
                }
                c = m_Connections[sessionID];
            }
            c.last = System.Environment.TickCount;
            if (c.lastLineSeen < m_lineNumber)
            {
                return(true);
            }
            return(false);
        }
Example #6
0
        private void TimeoutHandler(AsyncHttpRequest pRequest)
        {
            UUID sessionid = pRequest.AgentID;

            lock (m_Connections)
            {
                ConsoleConnection connection = null;
                m_Connections.TryGetValue(sessionid, out connection);
                if (connection == null)
                {
                    return;
                }
                if (connection.request == pRequest)
                {
                    connection.request = null;
                }
            }

            pRequest.SendResponse(ProcessEvents(pRequest));
        }
Example #7
0
        internal void ResponseReady()
        {
            List <AsyncHttpRequest> requests = new List <AsyncHttpRequest>();

            lock (m_Connections)
            {
                foreach (KeyValuePair <UUID, ConsoleConnection> kvp in m_Connections)
                {
                    ConsoleConnection connection = kvp.Value;
                    if (connection.request != null)
                    {
                        requests.Add(connection.request);
                        connection.request = null;
                    }
                }
            }

            foreach (AsyncHttpRequest request in requests)
            {
                request.SendResponse(ProcessEvents(request));
            }
        }
Example #8
0
        public void AsyncReadResponses(IHttpServer server, string path, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
        {
            int    pos1    = path.IndexOf("/");           // /ReadResponses
            int    pos2    = path.IndexOf("/", pos1 + 1); // /ReadResponses/
            int    pos3    = path.IndexOf("/", pos2 + 1); // /ReadResponses/<UUID>/
            int    len     = pos3 - pos2 - 1;
            string uri_tmp = path.Substring(pos2 + 1, len);

            UUID sessionID;

            if (UUID.TryParse(uri_tmp, out sessionID) == false)
            {
                return;
            }

            // Create the new request
            AsyncHttpRequest newRequest =
                new AsyncHttpRequest(server, httpRequest, httpResponse, sessionID, TimeoutHandler, 60 * 1000);
            AsyncHttpRequest currentRequest = null;

            lock (m_Connections)
            {
                ConsoleConnection connection = null;
                m_Connections.TryGetValue(sessionID, out connection);
                if (connection == null)
                {
                    return;
                }

                currentRequest     = connection.request;
                connection.request = newRequest;
            }

            // If there was a request already posted signal it
            if (currentRequest != null)
            {
                currentRequest.SendResponse(ProcessEvents(currentRequest));
            }
        }
Example #9
0
        // Send all pending output to the client.
        protected Hashtable GetEvents(UUID RequestID, UUID sessionID)
        {
            // Find the connection that goes with this client.
            ConsoleConnection c = null;

            lock (m_Connections)
            {
                if (!m_Connections.ContainsKey(sessionID))
                {
                    return(NoEvents(RequestID, UUID.Zero));
                }
                c = m_Connections[sessionID];
            }

            // If we have nothing to send, send the no events response.
            c.last = System.Environment.TickCount;
            if (c.lastLineSeen >= m_lineNumber)
            {
                return(NoEvents(RequestID, UUID.Zero));
            }

            Hashtable result = new Hashtable();

            // Create the response document.
            XmlDocument xmldoc  = new XmlDocument();
            XmlNode     xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
                                                    "", "");

            xmldoc.AppendChild(xmlnode);
            XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession",
                                                          "");

            //if (c.newConnection)
            //{
            //    c.newConnection = false;
            //    Output("+++" + DefaultPrompt);
            //}

            lock (m_Scrollback)
            {
                long startLine = m_lineNumber - m_Scrollback.Count;
                long sendStart = startLine;
                if (sendStart < c.lastLineSeen)
                {
                    sendStart = c.lastLineSeen;
                }

                for (long i = sendStart; i < m_lineNumber; i++)
                {
                    ScrollbackEntry e = m_Scrollback[(int)(i - startLine)];

                    XmlElement res = xmldoc.CreateElement("", "Line", "");
                    res.SetAttribute("Number", e.lineNumber.ToString());
                    res.SetAttribute("Level", e.level);
                    // Don't include these for the scrollback, we'll send the
                    // real state later.
                    if (!c.newConnection)
                    {
                        res.SetAttribute("Prompt", e.isPrompt ? "true" : "false");
                        res.SetAttribute("Command", e.isCommand ? "true" : "false");
                        res.SetAttribute("Input", e.isInput ? "true" : "false");
                    }
                    else if (i == m_lineNumber - 1) // Last line for a new connection
                    {
                        res.SetAttribute("Prompt", m_expectingInput ? "true" : "false");
                        res.SetAttribute("Command", m_expectingCommand ? "true" : "false");
                        res.SetAttribute("Input", (!m_expectingInput) ? "true" : "false");
                    }
                    else
                    {
                        res.SetAttribute("Input", e.isInput ? "true" : "false");
                    }

                    res.AppendChild(xmldoc.CreateTextNode(e.text));

                    rootElement.AppendChild(res);
                }
            }

            c.lastLineSeen  = m_lineNumber;
            c.newConnection = false;

            xmldoc.AppendChild(rootElement);

            result["str_response_string"] = xmldoc.InnerXml;
            result["int_response_code"]   = 200;
            result["content_type"]        = "application/xml";
            result["keepalive"]           = false;
            result = CheckOrigin(result);

            return(result);
        }
Example #10
0
        // Start a new session.
        protected Hashtable HandleHttpStartSession(Hashtable request)
        {
            // The login is in the form of a http form post
            Hashtable post  = DecodePostString(request["body"].ToString());
            Hashtable reply = new Hashtable();

            reply["str_response_string"] = "";
            reply["int_response_code"]   = 401;
            reply["content_type"]        = "text/plain";

            // Check user name and password
            if (m_UserName == String.Empty)
            {
                return(reply);
            }

            if (post["USER"] == null || post["PASS"] == null)
            {
                return(reply);
            }

            if (m_UserName != post["USER"].ToString() ||
                m_Password != post["PASS"].ToString())
            {
                return(reply);
            }

            // Set up the new console connection record
            ConsoleConnection c = new ConsoleConnection();

            c.last         = System.Environment.TickCount;
            c.lastLineSeen = 0;

            // Assign session ID
            UUID sessionID = UUID.Random();

            // Add connection to list.
            lock (m_Connections)
            {
                m_Connections[sessionID] = c;
            }

            // This call is a CAP. The URL is the authentication.
            string uri = "/ReadResponses/" + sessionID.ToString() + "/";

            m_Server.AddPollServiceHTTPHandler(
                uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, null, sessionID, 25000)); // 25 secs timeout

            // Our reply is an XML document.
            // TODO: Change this to Linq.Xml
            XmlDocument xmldoc  = new XmlDocument();
            XmlNode     xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
                                                    "", "");

            xmldoc.AppendChild(xmlnode);
            XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession",
                                                          "");

            xmldoc.AppendChild(rootElement);

            XmlElement id = xmldoc.CreateElement("", "SessionID", "");

            id.AppendChild(xmldoc.CreateTextNode(sessionID.ToString()));

            rootElement.AppendChild(id);

            XmlElement prompt = xmldoc.CreateElement("", "Prompt", "");

            prompt.AppendChild(xmldoc.CreateTextNode(m_lastPromptUsed));

            rootElement.AppendChild(prompt);

            rootElement.AppendChild(MainConsole.Instance.Commands.GetXml(xmldoc));

            // Set up the response and check origin
            reply["str_response_string"] = xmldoc.InnerXml;
            reply["int_response_code"]   = 200;
            reply["content_type"]        = "text/xml";
            reply = CheckOrigin(reply);

            return(reply);
        }
        private Hashtable HandleHttpStartSession(Hashtable request)
        {
            DoExpire();

            Hashtable post  = DecodePostString(request["body"].ToString());
            Hashtable reply = new Hashtable();

            reply["str_response_string"] = "";
            reply["int_response_code"]   = 401;
            reply["content_type"]        = "text/plain";

            if (m_UserName == String.Empty)
            {
                return(reply);
            }

            if (post["USER"] == null || post["PASS"] == null)
            {
                return(reply);
            }

            if (m_UserName != post["USER"].ToString() ||
                m_Password != post["PASS"].ToString())
            {
                return(reply);
            }

            ConsoleConnection c = new ConsoleConnection();

            c.last         = System.Environment.TickCount;
            c.lastLineSeen = 0;

            UUID sessionID = UUID.Random();

            lock (m_Connections)
            {
                m_Connections[sessionID] = c;
            }

            string uri = "/ReadResponses/" + sessionID.ToString() + "/";

            m_Server.AddPollServiceHTTPHandler(
                uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID, 25000)); // 25 secs timeout

            XmlDocument xmldoc  = new XmlDocument();
            XmlNode     xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
                                                    "", "");

            xmldoc.AppendChild(xmlnode);
            XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession",
                                                          "");

            xmldoc.AppendChild(rootElement);

            XmlElement id = xmldoc.CreateElement("", "SessionID", "");

            id.AppendChild(xmldoc.CreateTextNode(sessionID.ToString()));

            rootElement.AppendChild(id);

            XmlElement prompt = xmldoc.CreateElement("", "Prompt", "");

            prompt.AppendChild(xmldoc.CreateTextNode(DefaultPrompt));

            rootElement.AppendChild(prompt);

            rootElement.AppendChild(MainConsole.Instance.Commands.GetXml(xmldoc));

            reply["str_response_string"] = xmldoc.InnerXml;
            reply["int_response_code"]   = 200;
            reply["content_type"]        = "text/xml";
            reply = CheckOrigin(reply);

            return(reply);
        }
        private Hashtable GetEvents(UUID RequestID, UUID sessionID)
        {
            ConsoleConnection c = null;

            lock (m_Connections)
            {
                if (!m_Connections.ContainsKey(sessionID))
                {
                    return(NoEvents(RequestID, UUID.Zero));
                }
                c = m_Connections[sessionID];
            }
            c.last = System.Environment.TickCount;
            if (c.lastLineSeen >= m_LineNumber)
            {
                return(NoEvents(RequestID, UUID.Zero));
            }

            Hashtable result = new Hashtable();

            XmlDocument xmldoc  = new XmlDocument();
            XmlNode     xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
                                                    "", "");

            xmldoc.AppendChild(xmlnode);
            XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession",
                                                          "");

            if (c.newConnection)
            {
                c.newConnection = false;
                Output("+++" + DefaultPrompt);
            }

            lock (m_Scrollback)
            {
                long startLine = m_LineNumber - m_Scrollback.Count;
                long sendStart = startLine;
                if (sendStart < c.lastLineSeen)
                {
                    sendStart = c.lastLineSeen;
                }

                for (long i = sendStart; i < m_LineNumber; i++)
                {
                    XmlElement res  = xmldoc.CreateElement("", "Line", "");
                    long       line = i + 1;
                    res.SetAttribute("Number", line.ToString());
                    res.AppendChild(xmldoc.CreateTextNode(m_Scrollback[(int)(i - startLine)]));

                    rootElement.AppendChild(res);
                }
            }
            c.lastLineSeen = m_LineNumber;

            xmldoc.AppendChild(rootElement);

            result["str_response_string"] = xmldoc.InnerXml;
            result["int_response_code"]   = 200;
            result["content_type"]        = "application/xml";
            result["keepalive"]           = false;
            result["reusecontext"]        = false;
            result = CheckOrigin(result);

            return(result);
        }
Example #13
0
        private Hashtable HandleHttpStartSession(Hashtable request)
        {
            DoExpire();

            Hashtable post = DecodePostString(request["body"].ToString());
            Hashtable reply = new Hashtable();

            reply["str_response_string"] = "";
            reply["int_response_code"] = 401;
            reply["content_type"] = "text/plain";

            if (m_UserName == String.Empty)
                return reply;

            if (post["USER"] == null || post["PASS"] == null)
                return reply;

            if (m_UserName != post["USER"].ToString() ||
                m_Password != post["PASS"].ToString())
            {
                return reply;
            }

            ConsoleConnection c = new ConsoleConnection();
            c.last = System.Environment.TickCount;
            c.lastLineSeen = 0;

            UUID sessionID = UUID.Random();

            lock (m_Connections)
            {
                m_Connections[sessionID] = c;
            }

            string uri = "/ReadResponses/" + sessionID.ToString() + "/";

            m_Server.AddPollServiceHTTPHandler(uri, HandleHttpPoll,
                    new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents,
                    sessionID));

            XmlDocument xmldoc = new XmlDocument();
            XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
                    "", "");

            xmldoc.AppendChild(xmlnode);
            XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession",
                    "");

            xmldoc.AppendChild(rootElement);

            XmlElement id = xmldoc.CreateElement("", "SessionID", "");
            id.AppendChild(xmldoc.CreateTextNode(sessionID.ToString()));

            rootElement.AppendChild(id);

            XmlElement prompt = xmldoc.CreateElement("", "Prompt", "");
            prompt.AppendChild(xmldoc.CreateTextNode(DefaultPrompt));

            rootElement.AppendChild(prompt);

            rootElement.AppendChild(MainConsole.Instance.Commands.GetXml(xmldoc));

            reply["str_response_string"] = xmldoc.InnerXml;
            reply["int_response_code"] = 200;
            reply["content_type"] = "text/xml";
            reply = CheckOrigin(reply);

            return reply;
        }
Example #14
0
        private Hashtable HandleHttpStartSession(Hashtable request)
        {
            DoExpire();

            Hashtable post  = DecodePostString(request["body"].ToString());
            Hashtable reply = new Hashtable();

            reply["str_response_string"] = String.Empty;
            reply["int_response_code"]   = 401;
            reply["content_type"]        = "text/plain";

            var headers = (Hashtable)request["headers"];

            if (headers.ContainsKey("Authorization"))
            {
                var authHeader = headers["Authorization"].ToString();
                if (!authHeader.StartsWith("Bearer ", StringComparison.InvariantCultureIgnoreCase))
                {
                    m_log.Warn($"[REMOTECONSOLE] StartSession JWT Authorization header format failure from '{headers["remote_addr"]}'.");
                    return(reply);
                }

                try
                {
                    var token = new JWToken(authHeader.Substring(7), m_sigUtil);

                    // TODO: Make the scope strings come from some central list that can be registered into?
                    if (!(token.HasValidSignature && token.IsNotExpired && token.Payload.Scope == "remote-console"))
                    {
                        m_log.Warn($"[REMOTECONSOLE] StartSession invalid/expired/wrong scope JWToken from '{headers["remote_addr"]}'.");
                        return(reply);
                    }

                    m_log.Info($"[REMOTECONSOLE] StartSession access granted via JWT to '{token.Payload.Username}' from '{headers["remote_addr"]}'.");
                }
                catch (JWTokenException jte)
                {
                    m_log.Error($"[REMOTECONSOLE] Failure with JWToken in StartSession from '{headers["remote_addr"]}': {jte}");
                    return(reply);
                }
            }
            else if (request.ContainsKey("USER") && request.ContainsKey("PASS"))
            {
                string username = post["USER"].ToString();
                string password = post["PASS"].ToString();

                // Validate the username/password pair
                if (Util.AuthenticateAsSystemUser(username, password) == false)
                {
                    return(reply);
                }

                m_log.Warn($"[REMOTECONSOLE] StartSession access granted via legacy system username and password to '{username}' from '{headers["remote_addr"]}'.");
            }
            else
            {
                return(reply);
            }

            ConsoleConnection c = new ConsoleConnection();

            c.last         = System.Environment.TickCount;
            c.lastLineSeen = 0;

            UUID sessionID = UUID.Random();

            lock (m_Connections)
            {
                m_Connections[sessionID] = c;
            }

            string          uri     = "/ReadResponses/" + sessionID.ToString() + "/";
            IRequestHandler handler = new AsyncRequestHandler("POST", uri, AsyncReadResponses);

            m_Server.AddStreamHandler(handler);

            XmlDocument xmldoc  = new XmlDocument();
            XmlNode     xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, String.Empty, String.Empty);

            xmldoc.AppendChild(xmlnode);
            XmlElement rootElement = xmldoc.CreateElement(String.Empty, "ConsoleSession", String.Empty);

            xmldoc.AppendChild(rootElement);

            XmlElement id = xmldoc.CreateElement(String.Empty, "SessionID", String.Empty);

            id.AppendChild(xmldoc.CreateTextNode(sessionID.ToString()));

            rootElement.AppendChild(id);

            XmlElement prompt = xmldoc.CreateElement(String.Empty, "Prompt", String.Empty);

            prompt.AppendChild(xmldoc.CreateTextNode(DefaultPrompt));

            rootElement.AppendChild(prompt);

            rootElement.AppendChild(MainConsole.Instance.Commands.GetXml(xmldoc));

            reply["str_response_string"] = xmldoc.InnerXml;
            reply["int_response_code"]   = 200;
            reply["content_type"]        = "text/xml";
            reply = CheckOrigin(reply);

            return(reply);
        }
Example #15
0
        private Hashtable HandleHttpStartSession(Hashtable request)
        {
            DoExpire();

            Hashtable post  = DecodePostString(request["body"].ToString());
            Hashtable reply = new Hashtable();

            reply["str_response_string"] = "";
            reply["int_response_code"]   = 401;
            reply["content_type"]        = "text/plain";

            string username = post["USER"].ToString();
            string password = post["PASS"].ToString();

            // Validate the username/password pair
            if (Util.AuthenticateAsSystemUser(username, password) == false)
            {
                return(reply);
            }

            ConsoleConnection c = new ConsoleConnection();

            c.last         = System.Environment.TickCount;
            c.lastLineSeen = 0;

            UUID sessionID = UUID.Random();

            lock (m_Connections)
            {
                m_Connections[sessionID] = c;
            }

            string          uri     = "/ReadResponses/" + sessionID.ToString() + "/";
            IRequestHandler handler = new AsyncRequestHandler("POST", uri, AsyncReadResponses);

            m_Server.AddStreamHandler(handler);

            XmlDocument xmldoc  = new XmlDocument();
            XmlNode     xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, "", "");

            xmldoc.AppendChild(xmlnode);
            XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", "");

            xmldoc.AppendChild(rootElement);

            XmlElement id = xmldoc.CreateElement("", "SessionID", "");

            id.AppendChild(xmldoc.CreateTextNode(sessionID.ToString()));

            rootElement.AppendChild(id);

            XmlElement prompt = xmldoc.CreateElement("", "Prompt", "");

            prompt.AppendChild(xmldoc.CreateTextNode(DefaultPrompt));

            rootElement.AppendChild(prompt);

            rootElement.AppendChild(MainConsole.Instance.Commands.GetXml(xmldoc));

            reply["str_response_string"] = xmldoc.InnerXml;
            reply["int_response_code"]   = 200;
            reply["content_type"]        = "text/xml";
            reply = CheckOrigin(reply);

            return(reply);
        }
Example #16
0
        private Hashtable HandleHttpCloseSession(Hashtable request)
        {
            DoExpire();

            Hashtable post  = DecodePostString(request["body"].ToString());
            Hashtable reply = new Hashtable();

            reply["str_response_string"] = String.Empty;
            reply["int_response_code"]   = 404;
            reply["content_type"]        = "text/plain";

            JWToken token   = null;
            var     headers = (Hashtable)request["headers"];

            if (headers.ContainsKey("Authorization"))
            {
                var authHeader = headers["Authorization"].ToString();
                if (!authHeader.StartsWith("Bearer ", StringComparison.InvariantCultureIgnoreCase))
                {
                    m_log.Warn($"[REMOTECONSOLE] CloseSession JWT Authorization header format failure from '{headers["remote_addr"]}'.");
                    return(reply);
                }

                try
                {
                    token = new JWToken(authHeader.Substring(7), m_sigUtil);

                    // TODO: Make the scope strings come from some central list that can be registered into?
                    if (!(token.HasValidSignature && token.IsNotExpired && token.Payload.Scope == "remote-console"))
                    {
                        m_log.Warn($"[REMOTECONSOLE] CloseSession invalid/expired/wrong scope JWToken from '{headers["remote_addr"]}'.");
                        return(reply);
                    }

                    m_log.Info($"[REMOTECONSOLE] CloseSession for session '{post["ID"]}' accessed via JWT by '{token.Payload.Username}' from '{headers["remote_addr"]}'.");
                }
                catch (JWTokenException jte)
                {
                    m_log.Error($"[REMOTECONSOLE] Failure with JWToken in CloseSession from '{headers["remote_addr"]}': {jte}");
                    return(reply);
                }
            }
            else
            {
                m_log.Warn($"[REMOTECONSOLE] CloseSession for session '{post["ID"]}' from '{headers["remote_addr"]}' being accessed without Authorization header!");
            }
            // BUG: Longstanding issue: if someone gets ahold of, or guesses, the ID and/or JWT of another user they can close the console.
            // The only way I can think to close this bug is to associate each session with something the user cannot change. Not sure, but maybe the IP address of the connection would work?

            if (post["ID"] == null)
            {
                return(reply);
            }

            UUID id;

            if (!UUID.TryParse(post["ID"].ToString(), out id))
            {
                return(reply);
            }

            lock (m_Connections)
            {
                if (m_Connections.ContainsKey(id))
                {
                    ConsoleConnection connection = m_Connections[id];
                    m_Connections.Remove(id);
                    CloseConnection(id);
                    if (connection.request != null)
                    {
                        AsyncHttpRequest req = connection.request;
                        connection.request = null;
                        req.SendResponse(ProcessEvents(req));
                    }
                }
            }

            XmlDocument xmldoc  = new XmlDocument();
            XmlNode     xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, String.Empty, String.Empty);

            xmldoc.AppendChild(xmlnode);
            XmlElement rootElement = xmldoc.CreateElement(String.Empty, "ConsoleSession", String.Empty);

            xmldoc.AppendChild(rootElement);

            XmlElement res = xmldoc.CreateElement(String.Empty, "Result", String.Empty);

            res.AppendChild(xmldoc.CreateTextNode("OK"));

            rootElement.AppendChild(res);

            reply["str_response_string"] = xmldoc.InnerXml;
            reply["int_response_code"]   = 200;
            reply["content_type"]        = "text/xml";
            reply = CheckOrigin(reply);

            m_log.Info($"[REMOTECONSOLE] CloseSession successful for user '{token?.Payload.Username}' with session '{id}' from '{headers["remote_addr"]}'.");

            return(reply);
        }
Example #17
0
        public void AsyncReadResponses(IHttpServer server, string path, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
        {
            int    pos1    = path.IndexOf("/");           // /ReadResponses
            int    pos2    = path.IndexOf("/", pos1 + 1); // /ReadResponses/
            int    pos3    = path.IndexOf("/", pos2 + 1); // /ReadResponses/<UUID>/
            int    len     = pos3 - pos2 - 1;
            string uri_tmp = path.Substring(pos2 + 1, len);

            var authHeader = httpRequest.Headers.Get("Authorization");

            if (authHeader != null)
            {
                if (!authHeader.StartsWith("Bearer ", StringComparison.InvariantCultureIgnoreCase))
                {
                    m_log.Warn($"[REMOTECONSOLE] ReadResponses JWT Authorization header format failure from '{httpRequest.RemoteIPEndPoint}'.");
                    return;
                }

                try
                {
                    var token = new JWToken(authHeader.Substring(7), m_sigUtil);

                    // TODO: Make the scope strings come from some central list that can be registered into?
                    if (!(token.HasValidSignature && token.IsNotExpired && token.Payload.Scope == "remote-console"))
                    {
                        m_log.Warn($"[REMOTECONSOLE] ReadResponses invalid/expired/wrong scope JWToken from '{httpRequest.RemoteIPEndPoint}'.");
                        return;
                    }

                    m_log.Info($"[REMOTECONSOLE] ReadResponses for session '{uri_tmp}' accessed via JWT by '{token.Payload.Username}' from '{httpRequest.RemoteIPEndPoint}'.");
                }
                catch (JWTokenException jte)
                {
                    m_log.Error($"[REMOTECONSOLE] Failure with JWToken in ReadResponses from '{httpRequest.RemoteIPEndPoint}': {jte}");
                    return;
                }
            }
            else
            {
                m_log.Warn($"[REMOTECONSOLE] ReadResponses for session '{uri_tmp}' from '{httpRequest.RemoteIPEndPoint}' being accessed without Authorization header!");
            }
            // BUG: Longstanding issue: if someone gets ahold of, or guesses, the ID of another user they can send comamnds to the console.
            // The only way I can think to close this bug is to associate each session with something the user cannot change. Not sure, but maybe the IP address of the connection would work?

            UUID sessionID;

            if (UUID.TryParse(uri_tmp, out sessionID) == false)
            {
                return;
            }

            // Create the new request
            AsyncHttpRequest newRequest =
                new AsyncHttpRequest(server, httpRequest, httpResponse, sessionID, TimeoutHandler, 60 * 1000);
            AsyncHttpRequest currentRequest = null;

            lock (m_Connections)
            {
                ConsoleConnection connection = null;
                m_Connections.TryGetValue(sessionID, out connection);
                if (connection == null)
                {
                    return;
                }

                currentRequest     = connection.request;
                connection.request = newRequest;
            }

            // If there was a request already posted, signal it.
            if (currentRequest != null)
            {
                currentRequest.SendResponse(ProcessEvents(currentRequest));
            }
        }