Beispiel #1
0
        private Hashtable HandleHttpSessionCommand(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";

            var headers = (Hashtable)request["headers"];
            if (headers.ContainsKey("Authorization"))
            {
                var authHeader = headers["Authorization"].ToString();
                if (!authHeader.StartsWith("Bearer ", StringComparison.InvariantCultureIgnoreCase))
                {
                    m_log.Warn($"[REMOTECONSOLE] SessionCommand 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] SessionCommand invalid/expired/wrong scope JWToken from '{headers["remote_addr"]}'.");
                        return reply;
                    }

                    m_log.Info($"[REMOTECONSOLE] SessionCommand for session '{post["ID"]}' accessed via JWT by '{token.Payload.Username}' from '{headers["remote_addr"]}' with command '{post["COMMAND"]}'.");
                }
                catch (JWTokenException jte)
                {
                    m_log.Error($"[REMOTECONSOLE] Failure with JWToken in SessionCommand from '{headers["remote_addr"]}': {jte}");
                    return reply;
                }
            }
            else
            {
                m_log.Warn($"[REMOTECONSOLE] SessionCommand 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 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?

            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))
                    return reply;
            }

            if (post["COMMAND"] == null)
                return reply;

            lock (m_InputData)
            {
                m_DataEvent.Set();
                m_InputData.Add(post["COMMAND"].ToString());
            }

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

            return reply;
        }
Beispiel #2
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));
            }
        }
Beispiel #3
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;
        }