loolwsd/FileServer.hpp | 2 loolwsd/LOOLWSD.cpp | 107 ++++++++++++++++++++++++++++++++++++++----------- loolwsd/LOOLWSD.hpp | 42 ++++++++++++++++--- loolwsd/Makefile.am | 4 - loolwsd/Storage.cpp | 45 ++++++++++---------- loolwsd/Util.hpp | 39 +++++++++++++++++ loolwsd/loolwsd.xml.in | 1 7 files changed, 184 insertions(+), 56 deletions(-)
New commits: commit 6e616b745f663898810de39141bdc65535c92601 Author: Marco Cecchetti <marco.cecche...@collabora.com> Date: Mon Jul 18 13:45:36 2016 +0200 loolwsd: SSL support can be enabled/disabled on server start SSL support is enabled by default, it can be disabled by passing the `--disable-ssl` switch on the command line or by setting `ssl.enable` property in loolwsd.xml config file. It is still possible to build loolwsd with no SSL support at all. Change-Id: I00f952edc64f87f61505af44fdc2a715780dc44c Reviewed-on: https://gerrit.libreoffice.org/27288 Reviewed-by: Jan Holesovsky <ke...@collabora.com> Tested-by: Jan Holesovsky <ke...@collabora.com> diff --git a/loolwsd/FileServer.hpp b/loolwsd/FileServer.hpp index 7c19e10..874db99 100644 --- a/loolwsd/FileServer.hpp +++ b/loolwsd/FileServer.hpp @@ -217,7 +217,7 @@ private: { HTMLForm form(request, request.stream()); - const auto host = (LOOLWSD::SSLEnabled ? "wss://" : "ws://") + (LOOLWSD::ServerName.empty() ? request.getHost() : LOOLWSD::ServerName); + const auto host = (LOOLWSD::isSSLEnabled() ? "wss://" : "ws://") + (LOOLWSD::ServerName.empty() ? request.getHost() : LOOLWSD::ServerName); const auto path = Poco::Path(LOOLWSD::FileServerRoot, getRequestPathname(request)); Log::debug("Preprocessing file: " + path.toString()); diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index 97851ab..ff36b76 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -10,6 +10,16 @@ #include "LOOLWSD.hpp" #include "config.h" +/* Default host used in the start test URI */ +#define LOOLWSD_TEST_HOST "localhost" + +/* Default loleaflet UI used in the start test URI */ +#define LOOLWSD_TEST_LOLEAFLET_UI "/loleaflet/" LOOLWSD_VERSION_HASH "/loleaflet.html" + +/* Default document used in the start test URI */ +#define LOOLWSD_TEST_DOCUMENT_RELATIVE_PATH "test/data/hello-world.odt" + + // This is the main source for the loolwsd program. LOOL uses several loolwsd processes: one main // parent process that listens on the TCP port and accepts connections from LOOL clients, and a // number of child processes, each which handles a viewing (editing) session for one document. @@ -787,7 +797,7 @@ private: const std::string urlsrc = "urlsrc"; const auto& config = Application::instance().config(); const std::string loleafletHtml = config.getString("loleaflet_html", "loleaflet.html"); - const std::string uriValue = (LOOLWSD::SSLEnabled ? "https://" : "http://") + + const std::string uriValue = (LOOLWSD::isSSLEnabled() ? "https://" : "http://") + (LOOLWSD::ServerName.empty() ? request.getHost() : LOOLWSD::ServerName) + "/loleaflet/" LOOLWSD_VERSION_HASH "/" + loleafletHtml + "?"; @@ -1207,6 +1217,35 @@ public: } }; +namespace { + +static inline +ServerSocket* lcl_getServerSocket(int nClientPortNumber) +{ + return (LOOLWSD::isSSLEnabled()) ? new SecureServerSocket(nClientPortNumber) + : new ServerSocket(nClientPortNumber); +} + +static inline +std::string lcl_getLaunchURI() +{ + std::string aAbsTopSrcDir = Poco::Path(Application::instance().commandPath()).parent().toString(); + aAbsTopSrcDir = Poco::Path(aAbsTopSrcDir).absolute().toString(); + + std::string aLaunchURI(" "); + aLaunchURI += ((LOOLWSD::isSSLEnabled()) ? "https://" : "http://"); + aLaunchURI += LOOLWSD_TEST_HOST ":"; + aLaunchURI += std::to_string(ClientPortNumber); + aLaunchURI += LOOLWSD_TEST_LOLEAFLET_UI; + aLaunchURI += "?file_path=file://"; + aLaunchURI += aAbsTopSrcDir; + aLaunchURI += LOOLWSD_TEST_DOCUMENT_RELATIVE_PATH; + + return aLaunchURI; +} + +} // anonymous namespace + std::atomic<unsigned> LOOLWSD::NextSessionId; int LOOLWSD::ForKitWritePipe = -1; std::string LOOLWSD::Cache = LOOLWSD_CACHEDIR; @@ -1216,12 +1255,8 @@ std::string LOOLWSD::ChildRoot; std::string LOOLWSD::ServerName; std::string LOOLWSD::FileServerRoot; std::string LOOLWSD::LOKitVersion; -bool LOOLWSD::SSLEnabled = -#if ENABLE_SSL - true; -#else - false; -#endif +Util::RuntimeCostant<bool> LOOLWSD::SSLEnabled; + static std::string UnitTestLibrary; unsigned int LOOLWSD::NumPreSpawnedChildren = 0; @@ -1279,6 +1314,7 @@ void LOOLWSD::initialize(Application& self) { "loleaflet_html", "loleaflet.html" }, { "logging.color", "true" }, { "logging.level", "trace" }, + { "ssl.enable", "true" }, { "ssl.cert_file_path", LOOLWSD_CONFIGDIR "/cert.pem" }, { "ssl.key_file_path", LOOLWSD_CONFIGDIR "/key.pem" }, { "ssl.ca_file_path", LOOLWSD_CONFIGDIR "/ca-chain.cert.pem" }, @@ -1309,20 +1345,38 @@ void LOOLWSD::initialize(Application& self) // Allow UT to manipulate before using configuration values. UnitWSD::get().configure(config()); +#if ENABLE_SSL + LOOLWSD::SSLEnabled.set(getConfigValue<bool>(conf, "ssl.enable", true)); +#else + LOOLWSD::SSLEnabled.set(false); +#endif + + if (LOOLWSD::isSSLEnabled()) + { + Log::info("SSL support: SSL is enabled."); + } + else + { + Log::warn("SSL support: SSL is disabled."); + } + Cache = getPathFromConfig("tile_cache_path"); SysTemplate = getPathFromConfig("sys_template_path"); LoTemplate = getPathFromConfig("lo_template_path"); ChildRoot = getPathFromConfig("child_root_path"); ServerName = config().getString("server_name"); FileServerRoot = getPathFromConfig("file_server_root_path"); - NumPreSpawnedChildren = getUIntConfigValue(conf, "num_prespawn_children", 1); + NumPreSpawnedChildren = getConfigValue<unsigned int>(conf, "num_prespawn_children", 1); - const auto maxConcurrency = getUIntConfigValue(conf, "per_document.max_concurrency", 4); + const auto maxConcurrency = getConfigValue<unsigned int>(conf, "per_document.max_concurrency", 4); if (maxConcurrency > 0) { setenv("MAX_CONCURRENCY", std::to_string(maxConcurrency).c_str(), 1); } + Log::warn("Launch this in your browser:"); + Log::warn(lcl_getLaunchURI()); + // In Trial Versions we might want to set some limits. LOOLWSD::NumDocBrokers = 0; LOOLWSD::NumConnections = 0; @@ -1339,9 +1393,13 @@ void LOOLWSD::initialize(Application& self) ServerApplication::initialize(self); } -#if ENABLE_SSL void LOOLWSD::initializeSSL() { + if (!LOOLWSD::isSSLEnabled()) + { + return; + } + const auto ssl_cert_file_path = getPathFromConfig("ssl.cert_file_path"); Log::info("SSL Cert file: " + ssl_cert_file_path); @@ -1378,7 +1436,6 @@ void LOOLWSD::initializeSSL() Poco::Net::Context::Ptr sslClientContext = new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, sslClientParams); Poco::Net::SSLManager::instance().initializeClient(consoleClientHandler, invalidClientCertHandler, sslClientContext); } -#endif void LOOLWSD::uninitialize() { @@ -1403,6 +1460,10 @@ void LOOLWSD::defineOptions(OptionSet& optionSet) .repeatable(false) .argument("port number")); + optionSet.addOption(Option("disable-ssl", "", "Disable SSL security layer.") + .required(false) + .repeatable(false)); + optionSet.addOption(Option("override", "o", "Override any setting by providing fullxmlpath=value.") .required(false) .repeatable(true) @@ -1439,6 +1500,8 @@ void LOOLWSD::handleOption(const std::string& optionName, DisplayVersion = true; else if (optionName == "port") ClientPortNumber = std::stoi(value); + else if (optionName == "disable-ssl") + _overrideSettings["ssl.enable"] = "false"; else if (optionName == "override") { std::string optName; @@ -1513,9 +1576,7 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) std::cout << "loolwsd " << version << " - " << hash << std::endl; } -#if ENABLE_SSL initializeSSL(); -#endif char *locale = setlocale(LC_ALL, nullptr); if (locale == nullptr || std::strcmp(locale, "C") == 0) @@ -1585,13 +1646,11 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) params2->setMaxThreads(MAX_SESSIONS); // Start a server listening on the port for clients -#if ENABLE_SSL - SecureServerSocket svs(ClientPortNumber); -#else - ServerSocket svs(ClientPortNumber); -#endif + + std::unique_ptr<ServerSocket> psvs(lcl_getServerSocket(ClientPortNumber)); + ThreadPool threadPool(NumPreSpawnedChildren*6, MAX_SESSIONS * 2); - HTTPServer srv(new ClientRequestHandlerFactory(fileServer), threadPool, svs, params1); + HTTPServer srv(new ClientRequestHandlerFactory(fileServer), threadPool, *psvs, params1); Log::info("Starting master server listening on " + std::to_string(ClientPortNumber)); srv.start(); @@ -1757,10 +1816,12 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) Util::removeFile(path, true); } -#if ENABLE_SSL - Poco::Net::uninitializeSSL(); - Poco::Crypto::uninitializeCrypto(); -#endif + if (LOOLWSD::isSSLEnabled()) + { + Poco::Net::uninitializeSSL(); + Poco::Crypto::uninitializeCrypto(); + } + Log::info("Process [loolwsd] finished."); diff --git a/loolwsd/LOOLWSD.hpp b/loolwsd/LOOLWSD.hpp index b750bda..3a0fda6 100644 --- a/loolwsd/LOOLWSD.hpp +++ b/loolwsd/LOOLWSD.hpp @@ -43,7 +43,6 @@ public: static std::string ServerName; static std::string FileServerRoot; static std::string LOKitVersion; - static bool SSLEnabled; static std::atomic<unsigned> NumDocBrokers; static std::atomic<unsigned> NumConnections; @@ -53,6 +52,12 @@ public: return Util::encodeId(++NextSessionId, 4); } + static + bool isSSLEnabled() + { + return LOOLWSD::SSLEnabled.get(); + } + protected: void initialize(Poco::Util::Application& self) override; void uninitialize() override; @@ -61,16 +66,37 @@ protected: int main(const std::vector<std::string>& args) override; private: + static Util::RuntimeCostant<bool> SSLEnabled; + void initializeSSL(); void displayHelp(); Poco::Process::PID createForKit(); + + class ConfigValueGetter + { + Poco::Util::LayeredConfiguration& mconfig; + const std::string& mname; + + public: + ConfigValueGetter(Poco::Util::LayeredConfiguration& config, + const std::string& name) + : mconfig(config) + , mname(name) + {} + + void operator()(unsigned int& value) { value = mconfig.getUInt(mname); } + void operator()(bool& value) { value = mconfig.getBool(mname); } + }; + + template<typename T> static - bool getSafeUIntConfig(Poco::Util::LayeredConfiguration& config, const std::string& name, unsigned int& value) + bool getSafeConfig(Poco::Util::LayeredConfiguration& config, + const std::string& name, T& value) { try { - value = config.getUInt(name); + ConfigValueGetter(config, name)(value); return true; } catch (Poco::SyntaxException) @@ -80,12 +106,14 @@ private: return false; } + template<typename T> static - unsigned int getUIntConfigValue(Poco::Util::LayeredConfiguration& config, const std::string& name, const unsigned int def) + T getConfigValue(Poco::Util::LayeredConfiguration& config, + const std::string& name, const T def) { - unsigned int value = def; - if (getSafeUIntConfig(config, name, value) || - getSafeUIntConfig(config, name + "[@default]", value)) + T value = def; + if (getSafeConfig(config, name, value) || + getSafeConfig(config, name + "[@default]", value)) { return value; } diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am index 5546181..5e7186d 100644 --- a/loolwsd/Makefile.am +++ b/loolwsd/Makefile.am @@ -138,10 +138,8 @@ clean-local: if test "z@SYSTEMPLATE_PATH@" != "z"; then rm -rf "@SYSTEMPLATE_PATH@"; fi run: all @JAILS_PATH@ @SYSTEMPLATE_PATH@/system_stamp - @echo "Launching loolwsd - launch this in your browser:" + @echo "Launching loolwsd" @cp $(abs_top_srcdir)/test/data/hello.odt $(abs_top_srcdir)/test/data/hello-world.odt - @PROTOCOL="http" ; if test "z@ENABLE_SSL@" != "z"; then PROTOCOL="https" ; fi ; \ - echo " $$PROTOCOL://localhost:9980/loleaflet/@LOOLWSD_VERSION_HASH@/loleaflet.html?file_path=file://$(abs_top_srcdir)/test/data/hello-world.odt" @echo ./loolwsd --o:sys_template_path="@SYSTEMPLATE_PATH@" --o:lo_template_path="@LO_PATH@" \ --o:child_root_path="@JAILS_PATH@" --o:storage.filesystem[@allow]=true \ diff --git a/loolwsd/Storage.cpp b/loolwsd/Storage.cpp index 372ea2f..0b8bfda 100644 --- a/loolwsd/Storage.cpp +++ b/loolwsd/Storage.cpp @@ -28,6 +28,7 @@ #include "Auth.hpp" #include "Common.hpp" #include "Exceptions.hpp" +#include "LOOLWSD.hpp" #include "Log.hpp" #include "Unit.hpp" #include "Util.hpp" @@ -236,6 +237,17 @@ bool LocalStorage::saveLocalFileToStorage() return true; } +namespace { + +static inline +Poco::Net::HTTPClientSession* lcl_getHTTPClientSession(const Poco::URI& uri) +{ + return (LOOLWSD::isSSLEnabled()) ? new Poco::Net::HTTPSClientSession(uri.getHost(), uri.getPort(), Poco::Net::SSLManager::instance().defaultClientContext()) + : new Poco::Net::HTTPClientSession(uri.getHost(), uri.getPort()); +} + +} // anonymous namespace + /////////////////// // WopiStorage Impl /////////////////// @@ -243,17 +255,14 @@ StorageBase::FileInfo WopiStorage::getFileInfo(const Poco::URI& uri) { Log::debug("Getting info for wopi uri [" + uri.toString() + "]."); -#if ENABLE_SSL - Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(), Poco::Net::SSLManager::instance().defaultClientContext()); -#else - Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort()); -#endif + std::unique_ptr<Poco::Net::HTTPClientSession> psession(lcl_getHTTPClientSession(uri)); + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, uri.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); request.set("User-Agent", "LOOLWSD WOPI Agent"); - session.sendRequest(request); + psession->sendRequest(request); Poco::Net::HTTPResponse response; - std::istream& rs = session.receiveResponse(response); + std::istream& rs = psession->receiveResponse(response); auto logger = Log::trace(); logger << "WOPI::CheckFileInfo header for URI [" << uri.toString() << "]:\n"; @@ -303,17 +312,14 @@ std::string WopiStorage::loadStorageFileToLocal() const auto url = uriObject.getPath() + "/contents?" + uriObject.getQuery(); Log::debug("Wopi requesting: " + url); -#if ENABLE_SSL - Poco::Net::HTTPSClientSession session(uriObject.getHost(), uriObject.getPort(), Poco::Net::SSLManager::instance().defaultClientContext()); -#else - Poco::Net::HTTPClientSession session(uriObject.getHost(), uriObject.getPort()); -#endif + std::unique_ptr<Poco::Net::HTTPClientSession> psession(lcl_getHTTPClientSession(uriObject)); + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, url, Poco::Net::HTTPMessage::HTTP_1_1); request.set("User-Agent", "LOOLWSD WOPI Agent"); - session.sendRequest(request); + psession->sendRequest(request); Poco::Net::HTTPResponse response; - std::istream& rs = session.receiveResponse(response); + std::istream& rs = psession->receiveResponse(response); auto logger = Log::trace(); logger << "WOPI::GetFile header for URI [" << _uri << "]:\n"; @@ -348,22 +354,19 @@ bool WopiStorage::saveLocalFileToStorage() const auto url = uriObject.getPath() + "/contents?" + uriObject.getQuery(); Log::debug("Wopi posting: " + url); -#if ENABLE_SSL - Poco::Net::HTTPSClientSession session(uriObject.getHost(), uriObject.getPort(), Poco::Net::SSLManager::instance().defaultClientContext()); -#else - Poco::Net::HTTPClientSession session(uriObject.getHost(), uriObject.getPort()); -#endif + std::unique_ptr<Poco::Net::HTTPClientSession> psession(lcl_getHTTPClientSession(uriObject)); + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, url, Poco::Net::HTTPMessage::HTTP_1_1); request.set("X-WOPIOverride", "PUT"); request.setContentType("application/octet-stream"); request.setContentLength(size); - std::ostream& os = session.sendRequest(request); + std::ostream& os = psession->sendRequest(request); std::ifstream ifs(_jailedFilePath); Poco::StreamCopier::copyStream(ifs, os); Poco::Net::HTTPResponse response; - std::istream& rs = session.receiveResponse(response); + std::istream& rs = psession->receiveResponse(response); std::ostringstream oss; Poco::StreamCopier::copyStream(rs, oss); diff --git a/loolwsd/Util.hpp b/loolwsd/Util.hpp index 138d791..8b866a3 100644 --- a/loolwsd/Util.hpp +++ b/loolwsd/Util.hpp @@ -185,7 +185,44 @@ namespace Util std::set<std::string> _denied; }; -}; + template<typename T> + class RuntimeCostant + { + T mValue; + bool mInitialized; + + public: + RuntimeCostant() + : mValue() + , mInitialized(false) + {} + + const T& get() + { + if(mInitialized) + { + return mValue; + } + else + { + throw std::runtime_error("RuntimeCostant instance read before being initialized."); + } + } + + void set(const T& value) + { + if(mInitialized) + { + throw std::runtime_error("RuntimeCostant instance already initialized."); + } + else + { + mInitialized = true; + mValue = value; + } + } + }; +} // end namespace Util #endif diff --git a/loolwsd/loolwsd.xml.in b/loolwsd/loolwsd.xml.in index b3251e4..6366dd6 100644 --- a/loolwsd/loolwsd.xml.in +++ b/loolwsd/loolwsd.xml.in @@ -26,6 +26,7 @@ </logging> <ssl desc="SSL settings"> + <enable type="bool" default="true">true</enable> <cert_file_path desc="Path to the cert file" relative="false">/etc/loolwsd/cert.pem</cert_file_path> <key_file_path desc="Path to the key file" relative="false">/etc/loolwsd/key.pem</key_file_path> <ca_file_path desc="Path to the ca file" relative="false">/etc/loolwsd/ca-chain.cert.pem</ca_file_path> _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits