[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