[Libreoffice-commits] online.git: test/integration-http-server.cpp wsd/LOOLWSD.cpp

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Wed Oct 24 11:06:30 UTC 2018


 test/integration-http-server.cpp |   87 +++++++++++++++++++++++++++++++++++++++
 wsd/LOOLWSD.cpp                  |   33 +++++++++++++-
 2 files changed, 116 insertions(+), 4 deletions(-)

New commits:
commit 318f0629bbf94c38bce42589937f46a1f8fd79ee
Author:     Tamás Zolnai <tamas.zolnai at collabora.com>
AuthorDate: Wed Oct 24 12:37:58 2018 +0200
Commit:     Tamás Zolnai <tamas.zolnai at collabora.com>
CommitDate: Wed Oct 24 12:50:03 2018 +0200

    Handle X-Forwarded-For header for convert-to feature
    
    Extract the client IP from the X-Forwarded-For value
    and use that one to allow / deny the usage of convert-to
    feature.
    
    Change-Id: I363c0931df5a0538236cae12f943fffd65086ee6

diff --git a/test/integration-http-server.cpp b/test/integration-http-server.cpp
index f9d100e2f..ec25653c0 100644
--- a/test/integration-http-server.cpp
+++ b/test/integration-http-server.cpp
@@ -51,6 +51,7 @@ class HTTPServerTest : public CPPUNIT_NS::TestFixture
     CPPUNIT_TEST(testScriptsAndLinksGet);
     CPPUNIT_TEST(testScriptsAndLinksPost);
     CPPUNIT_TEST(testConvertTo);
+    CPPUNIT_TEST(testConvertToWithForwardedClientIP);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -61,6 +62,7 @@ class HTTPServerTest : public CPPUNIT_NS::TestFixture
     void testScriptsAndLinksGet();
     void testScriptsAndLinksPost();
     void testConvertTo();
+    void testConvertToWithForwardedClientIP();
 
 public:
     HTTPServerTest()
@@ -96,8 +98,25 @@ public:
         testNoExtraLoolKitsLeft();
         helpers::resetTestStartTime();
     }
+
+    // A server URI which was not added to loolwsd.xml as post_allow IP or a wopi storage host
+    Poco::URI getNotAllowedTestServerURI()
+    {
+        static const char* clientPort = std::getenv("LOOL_TEST_CLIENT_PORT");
+
+        static std::string serverURI(
+#if ENABLE_SSL
+        "https://165.227.162.232:"
+#else
+        "http://165.227.162.232:"
+#endif
+            + (clientPort? std::string(clientPort) : std::to_string(DEFAULT_CLIENT_PORT_NUMBER)));
+
+        return Poco::URI(serverURI);
+    }
 };
 
+
 void HTTPServerTest::testDiscovery()
 {
     std::unique_ptr<Poco::Net::HTTPClientSession> session(helpers::createSession(_uri));
@@ -339,6 +358,74 @@ void HTTPServerTest::testConvertTo()
     CPPUNIT_ASSERT_EQUAL(expectedStream.str(), actualString);
 }
 
+
+void HTTPServerTest::testConvertToWithForwardedClientIP()
+{
+    // Test a forwarded IP which is not allowed to use convert-to feature
+    {
+        const std::string srcPath = FileUtil::getTempFilePath(TDOC, "hello.odt", "testConvertToWithForwardedClientIP_");
+        std::unique_ptr<Poco::Net::HTTPClientSession> session(helpers::createSession(_uri));
+        session->setTimeout(Poco::Timespan(2, 0)); // 2 seconds.
+
+        Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/lool/convert-to");
+        CPPUNIT_ASSERT(!request.has("X-Forwarded-For"));
+        request.add("X-Forwarded-For", getNotAllowedTestServerURI().getHost() + ", " + _uri.getHost());
+        Poco::Net::HTMLForm form;
+        form.setEncoding(Poco::Net::HTMLForm::ENCODING_MULTIPART);
+        form.set("format", "txt");
+        form.addPart("data", new Poco::Net::FilePartSource(srcPath));
+        form.prepareSubmit(request);
+        form.write(session->sendRequest(request));
+
+        Poco::Net::HTTPResponse response;
+        std::stringstream actualStream;
+        std::istream& responseStream = session->receiveResponse(response);
+        Poco::StreamCopier::copyStream(responseStream, actualStream);
+
+        // Remove the temp files.
+        FileUtil::removeFile(srcPath);
+
+        std::string actualString = actualStream.str();
+        CPPUNIT_ASSERT(actualString.empty()); // <- we did not get the converted file
+    }
+
+    // Test a forwarded IP which is allowed to use convert-to feature
+    {
+        const std::string srcPath = FileUtil::getTempFilePath(TDOC, "hello.odt", "testConvertToWithForwardedClientIP_");
+        std::unique_ptr<Poco::Net::HTTPClientSession> session(helpers::createSession(_uri));
+        session->setTimeout(Poco::Timespan(2, 0)); // 2 seconds.
+
+        Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/lool/convert-to");
+        CPPUNIT_ASSERT(!request.has("X-Forwarded-For"));
+        request.add("X-Forwarded-For", _uri.getHost() + ", " + _uri.getHost());
+        Poco::Net::HTMLForm form;
+        form.setEncoding(Poco::Net::HTMLForm::ENCODING_MULTIPART);
+        form.set("format", "txt");
+        form.addPart("data", new Poco::Net::FilePartSource(srcPath));
+        form.prepareSubmit(request);
+        form.write(session->sendRequest(request));
+
+        Poco::Net::HTTPResponse response;
+        std::stringstream actualStream;
+        std::istream& responseStream = session->receiveResponse(response);
+        Poco::StreamCopier::copyStream(responseStream, actualStream);
+
+        std::ifstream fileStream(TDOC "/hello.txt");
+        std::stringstream expectedStream;
+        expectedStream << fileStream.rdbuf();
+
+        // Remove the temp files.
+        FileUtil::removeFile(srcPath);
+
+        // In some cases the result is prefixed with (the UTF-8 encoding of) the Unicode BOM
+        // (U+FEFF). Skip that.
+        std::string actualString = actualStream.str();
+        if (actualString.size() > 3 && actualString[0] == '\xEF' && actualString[1] == '\xBB' && actualString[2] == '\xBF')
+            actualString = actualString.substr(3);
+        CPPUNIT_ASSERT_EQUAL(expectedStream.str(), actualString); // <- we got the converted file
+    }
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(HTTPServerTest);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 95d362547..0b6ee1a61 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -80,6 +80,8 @@ using Poco::Net::PartHandler;
 #include <Poco/File.h>
 #include <Poco/FileStream.h>
 #include <Poco/MemoryStream.h>
+#include <Poco/Net/DNS.h>
+#include <Poco/Net/HostEntry.h>
 #include <Poco/Path.h>
 #include <Poco/Pipe.h>
 #include <Poco/Process.h>
@@ -1938,6 +1940,29 @@ public:
         }
         return hosts.match(address);
     }
+    bool allowConvertTo(const std::string &address, const Poco::Net::HTTPRequest& request)
+    {
+        std::string clientAddress = address;
+        std::string clientHost = request.getHost();
+        if(request.has("X-Forwarded-For"))
+        {
+            std::string fowardedData = request.get("X-Forwarded-For");
+            size_t sepPos = fowardedData.find_first_of(',');
+            if(sepPos != std::string::npos)
+            {
+                clientAddress = fowardedData.substr(0, sepPos);
+                try
+                {
+                    clientHost = Poco::Net::DNS::resolve(clientAddress).name();
+                }
+                catch (const Poco::Exception& exc)
+                {
+                    LOG_WRN("Poco::Net::DNS::resolve(\"" << clientAddress << "\") failed: " << exc.displayText());
+                }
+            }
+        }
+        return allowPostFrom(clientAddress) || StorageBase::allowedWopiHost(request.getHost());
+    }
 
 private:
 
@@ -2170,7 +2195,7 @@ private:
     {
         LOG_DBG("Wopi capabilities request: " << request.getURI());
 
-        std::string capabilities = getCapabilitiesJson(request.getHost());
+        std::string capabilities = getCapabilitiesJson(request);
 
         std::ostringstream oss;
         oss << "HTTP/1.1 200 OK\r\n"
@@ -2256,7 +2281,7 @@ private:
 
             std::string format = (form.has("format") ? form.get("format") : "");
 
-            if (!allowPostFrom(socket->clientAddress()) && !StorageBase::allowedWopiHost(request.getHost()) )
+            if (!allowConvertTo(socket->clientAddress(), request))
             {
                 LOG_ERR("client address DENY: " << socket->clientAddress());
 
@@ -2693,7 +2718,7 @@ private:
     }
 
     /// Process the capabilities.json file and return as string.
-    std::string getCapabilitiesJson(const std::string& host)
+    std::string getCapabilitiesJson(const Poco::Net::HTTPRequest& request)
     {
         std::shared_ptr<StreamSocket> socket = _socket.lock();
 
@@ -2717,7 +2742,7 @@ private:
         Poco::JSON::Object::Ptr features = jsonFile.extract<Poco::JSON::Object::Ptr>();
         Poco::JSON::Object::Ptr convert_to = features->get("convert-to").extract<Poco::JSON::Object::Ptr>();
 
-        Poco::Dynamic::Var available = allowPostFrom(socket->clientAddress()) || StorageBase::allowedWopiHost(host);
+        Poco::Dynamic::Var available = allowConvertTo(socket->clientAddress(), request);
         convert_to->set("available", available);
 
         std::ostringstream ostrJSON;


More information about the Libreoffice-commits mailing list