wsd: cleanup: moved all parsing related static methods and containers to HostUtil.cpp

Signed-off-by: Rash419 <rashesh.padia@collabora.com>
Change-Id: I8555522c6216f893b90ba4c27747314830f7abd2
pull/4495/head
Rash419 2022-03-24 15:53:34 +05:30 committed by Jan Holesovsky
parent 8d9317daa8
commit 31d8822758
9 changed files with 260 additions and 223 deletions

View File

@ -130,6 +130,7 @@ coolwsd_sources = common/Crypto.cpp \
wsd/FileServerUtil.cpp \
wsd/RequestDetails.cpp \
wsd/Storage.cpp \
wsd/HostUtil.cpp \
wsd/TileCache.cpp \
wsd/ProofKey.cpp \
wsd/QuarantineUtil.cpp
@ -263,7 +264,8 @@ wsd_headers = wsd/Admin.hpp \
wsd/TileDesc.hpp \
wsd/TraceFile.hpp \
wsd/UserMessages.hpp \
wsd/QuarantineUtil.hpp
wsd/QuarantineUtil.hpp \
wsd/HostUtil.hpp
shared_headers = common/Common.hpp \
common/Clipboard.hpp \

View File

@ -1139,7 +1139,7 @@ namespace Util
}
template <class Type, typename Getter>
static bool matchRegex(const Type& set, const std::string& subject, Getter& getter)
static bool matchRegex(const Type& set, const std::string& subject, const Getter& getter)
{
if (set.find(subject) != set.end())
{

View File

@ -102,7 +102,7 @@ wsd_sources = \
../common/Authorization.cpp \
../kit/Kit.cpp \
../kit/TestStubs.cpp \
../wsd/Storage.cpp \
../wsd/HostUtil.cpp \
../wsd/FileServerUtil.cpp \
../wsd/RequestDetails.cpp \
../wsd/TileCache.cpp \

View File

@ -10,6 +10,7 @@
#include "COOLWSD.hpp"
#include "ProofKey.hpp"
#include "CommandControl.hpp"
#include "HostUtil.hpp"
/* Default host used in the start test URI */
#define COOLWSD_TEST_HOST "localhost"
@ -1149,13 +1150,13 @@ public:
AutoPtr<AppConfigMap> newConfig(new AppConfigMap(newAppConfig));
conf.addWriteable(newConfig, PRIO_JSON);
StorageBase::parseWopiHost(conf);
StorageBase::parseAliases(conf);
HostUtil::parseWopiHost(conf);
#ifdef ENABLE_FEATURE_LOCK
CommandControl::LockManager::parseLockedHost(conf);
#endif
HostUtil::parseAliases(conf);
}
void fetchWopiHostPatterns(std::map<std::string, std::string>& newAppConfig,
@ -2982,7 +2983,7 @@ public:
{
std::string addressToCheck = address;
std::string hostToCheck = request.getHost();
bool allow = allowPostFrom(addressToCheck) || StorageBase::allowedWopiHost(hostToCheck);
bool allow = allowPostFrom(addressToCheck) || HostUtil::allowedWopiHost(hostToCheck);
if(!allow)
{
@ -3008,7 +3009,7 @@ public:
if (!allowPostFrom(addressToCheck))
{
hostToCheck = Poco::Net::DNS::resolve(addressToCheck).name();
allow &= StorageBase::allowedWopiHost(hostToCheck);
allow &= HostUtil::allowedWopiHost(hostToCheck);
}
}
catch (const Poco::Exception& exc)

186
wsd/HostUtil.cpp 100644
View File

@ -0,0 +1,186 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "HostUtil.hpp"
#include <common/ConfigUtil.hpp>
#include <common/Log.hpp>
Util::RegexListMatcher HostUtil::WopiHosts;
std::map<std::string, std::string> HostUtil::AliasHosts;
std::set<std::string> HostUtil::AllHosts;
std::string HostUtil::FirstHost;
bool HostUtil::WopiEnabled;
void HostUtil::parseWopiHost(Poco::Util::LayeredConfiguration& conf)
{
// Parse the WOPI settings.
WopiHosts.clear();
WopiEnabled = conf.getBool("storage.wopi[@allow]", false);
if (WopiEnabled)
{
for (size_t i = 0;; ++i)
{
const std::string path = "storage.wopi.host[" + std::to_string(i) + ']';
if (!conf.has(path))
{
break;
}
HostUtil::addWopiHost(conf.getString(path, ""),
conf.getBool(path + "[@allow]", false));
}
}
}
void HostUtil::addWopiHost(std::string host, bool allow)
{
if (!host.empty())
{
if (allow)
{
LOG_INF("Adding trusted WOPI host: [" << host << "].");
WopiHosts.allow(host);
}
else
{
LOG_INF("Adding blocked WOPI host: [" << host << "].");
WopiHosts.deny(host);
}
}
}
bool HostUtil::allowedWopiHost(const std::string& host)
{
return WopiEnabled && WopiHosts.match(host);
}
bool HostUtil::allowedAlias(const Poco::URI& uri)
{
if (Util::iequal(config::getString("storage.wopi.alias_groups[@mode]", "first"), "compat"))
{
return true;
}
if (AllHosts.empty())
{
if (FirstHost.empty())
{
FirstHost = uri.getAuthority();
}
else if (FirstHost != uri.getAuthority())
{
LOG_ERR("Only allowed host is: " << FirstHost);
return false;
}
}
else if (!Util::matchRegex(AllHosts, uri.getAuthority()))
{
LOG_ERR("Host: " << uri.getAuthority()
<< " is not allowed, It is not part of alias_groups configuration");
return false;
}
return true;
}
void HostUtil::parseAliases(Poco::Util::LayeredConfiguration& conf)
{
//set alias_groups mode to compat
if (!conf.has("storage.wopi.alias_groups"))
{
conf.setString("storage.wopi.alias_groups[@mode]", "compat");
}
else if (conf.has("storage.wopi.alias_groups.group[0]"))
{
// group defined in alias_groups
if (Util::iequal(config::getString("storage.wopi.alias_groups[@mode]", "first"), "first"))
{
LOG_ERR("Admins didnot set the alias_groups mode to 'groups'");
AliasHosts.clear();
AllHosts.clear();
return;
}
}
AliasHosts.clear();
AllHosts.clear();
for (size_t i = 0;; i++)
{
const std::string path = "storage.wopi.alias_groups.group[" + std::to_string(i) + ']';
if (!conf.has(path + ".host"))
{
break;
}
const std::string uri = conf.getString(path + ".host", "");
if (uri.empty())
{
continue;
}
bool allow = conf.getBool(path + ".host[@allow]", false);
try
{
const Poco::URI realUri(uri);
HostUtil::addWopiHost(realUri.getHost(), allow);
AllHosts.insert(realUri.getAuthority());
}
catch (const Poco::Exception& exc)
{
LOG_WRN("parseAliases: " << exc.displayText());
}
for (size_t j = 0;; j++)
{
const std::string aliasPath = path + ".alias[" + std::to_string(j) + ']';
if (!conf.has(aliasPath))
{
break;
}
try
{
const Poco::URI aliasUri(conf.getString(aliasPath, ""));
if (aliasUri.empty())
{
continue;
}
const Poco::URI realUri(uri);
AliasHosts.insert({ aliasUri.getAuthority(), realUri.getAuthority() });
AllHosts.insert(aliasUri.getAuthority());
HostUtil::addWopiHost(aliasUri.getHost(), allow);
}
catch (const Poco::Exception& exc)
{
LOG_WRN("parseAliases: " << exc.displayText());
}
}
}
}
std::string HostUtil::getNewUri(const Poco::URI& uri)
{
if (Util::iequal(config::getString("storage.wopi.alias_groups[@mode]", "first"), "compat"))
{
return uri.getPath();
}
Poco::URI newUri(uri);
const std::string key = newUri.getAuthority();
if (Util::matchRegex(AliasHosts, key))
{
newUri.setAuthority(AliasHosts[key]);
}
if (newUri.getAuthority().empty())
{
return newUri.getPath();
}
return newUri.getScheme() + "://" + newUri.getHost() + ':' + std::to_string(newUri.getPort()) +
newUri.getPath();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

52
wsd/HostUtil.hpp 100644
View File

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <Util.hpp>
#include <Poco/URI.h>
#include <Poco/Util/Application.h>
/// This class contains static methods to parse alias_groups and WOPI host and static containers to store the data from the coolwsd.xml
class HostUtil
{
private:
/// Allowed/denied WOPI hosts, if any and if WOPI is enabled.
static Util::RegexListMatcher WopiHosts;
/// mapping of alias host and port to real host and port
static std::map<std::string, std::string> AliasHosts;
/// When group configuration is not defined only the firstHost gets access
static std::string FirstHost;
/// This contains all real and aliases host from group configuration
static std::set<std::string> AllHosts;
static bool WopiEnabled;
public:
/// parse wopi.storage.host
static void parseWopiHost(Poco::Util::LayeredConfiguration& conf);
/// parse wopi.storage.alias_groups.group
static void parseAliases(Poco::Util::LayeredConfiguration& conf);
/// if request uri is an alias, replace request uri host and port with
/// original hostname and port defined by group tag from coolwsd.xml
/// to avoid possibility of opening the same file as two if the WOPI host
/// is accessed using different aliases
static std::string getNewUri(const Poco::URI& uri);
/// add host to WopiHosts
static void addWopiHost(std::string host, bool allow);
static bool allowedAlias(const Poco::URI& uri);
static bool allowedWopiHost(const std::string& host);
static bool isWopiEnabled() { return WopiEnabled; }
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -10,7 +10,7 @@
#include "COOLWSD.hpp"
#include "RequestDetails.hpp"
#include "common/Log.hpp"
#include "Storage.hpp"
#include "HostUtil.hpp"
#include <Poco/URI.h>
#include "Exceptions.hpp"
@ -282,7 +282,6 @@ Poco::URI RequestDetails::sanitizeURI(const std::string& uri)
return uriPublic;
}
#if !defined(BUILDING_TESTS)
std::string RequestDetails::getDocKey(const Poco::URI& uri)
{
std::string docKey;
@ -290,13 +289,12 @@ std::string RequestDetails::getDocKey(const Poco::URI& uri)
// resolve aliases
#if !MOBILEAPP
newUri = StorageBase::getNewUri(uri);
newUri = HostUtil::getNewUri(uri);
#endif
Poco::URI::encode(newUri, "", docKey);
LOG_INF("DocKey from URI [" << uri.toString() << "] => [" << docKey << ']');
return docKey;
}
#endif // !defined(BUILDING_TESTS)
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -53,6 +53,7 @@
#include <common/TraceEvent.hpp>
#include <NetUtil.hpp>
#include <CommandControl.hpp>
#include "HostUtil.hpp"
#ifdef IOS
#include <ios.h>
@ -60,16 +61,9 @@
#include "androidapp.hpp"
#endif
#if !defined(BUILDING_TESTS)
bool StorageBase::FilesystemEnabled;
bool StorageBase::WopiEnabled;
bool StorageBase::SSLAsScheme = true;
bool StorageBase::SSLEnabled = false;
Util::RegexListMatcher StorageBase::WopiHosts;
std::map<std::string, std::string> StorageBase::AliasHosts;
std::set<std::string> StorageBase::AllHosts;
std::string StorageBase::FirstHost;
#endif // !defined(BUILDING_TESTS)
#if !MOBILEAPP
@ -88,160 +82,22 @@ std::string StorageBase::getLocalRootPath() const
return rootPath.toString();
}
#if !defined(BUILDING_TESTS)
void StorageBase::parseWopiHost(Poco::Util::LayeredConfiguration& conf)
{
// Parse the WOPI settings.
WopiHosts.clear();
WopiEnabled = conf.getBool("storage.wopi[@allow]", false);
if (WopiEnabled)
{
for (size_t i = 0;; ++i)
{
const std::string path = "storage.wopi.host[" + std::to_string(i) + ']';
if (!conf.has(path))
{
break;
}
StorageBase::addWopiHost(conf.getString(path, ""), conf.getBool(path + "[@allow]", false));
}
}
}
void StorageBase::addWopiHost(std::string host, bool allow)
{
if (!host.empty())
{
if (allow)
{
LOG_INF("Adding trusted WOPI host: [" << host << "].");
WopiHosts.allow(host);
}
else
{
LOG_INF("Adding blocked WOPI host: [" << host << "].");
WopiHosts.deny(host);
}
}
}
void StorageBase::parseAliases(Poco::Util::LayeredConfiguration& conf)
{
//set alias_groups mode to compat
if (!conf.has("storage.wopi.alias_groups"))
{
conf.setString("storage.wopi.alias_groups[@mode]", "compat");
}
else if (conf.has("storage.wopi.alias_groups.group[0]"))
{
// group defined in alias_groups
if (Util::iequal(config::getString("storage.wopi.alias_groups[@mode]", "first"), "first"))
{
LOG_ERR("Admins didnot set the alias_groups mode to 'groups'");
AliasHosts.clear();
AllHosts.clear();
return;
}
}
AliasHosts.clear();
AllHosts.clear();
for (size_t i = 0;; i++)
{
const std::string path = "storage.wopi.alias_groups.group[" + std::to_string(i) + ']';
if (!conf.has(path + ".host"))
{
break;
}
const std::string uri = conf.getString(path + ".host", "");
if (uri.empty())
{
continue;
}
bool allow = conf.getBool(path + ".host[@allow]", false);
try
{
const Poco::URI realUri(uri);
StorageBase::addWopiHost(realUri.getHost(), allow);
AllHosts.insert(realUri.getAuthority());
}
catch (const Poco::Exception& exc)
{
LOG_WRN("parseAliases: " << exc.displayText());
}
for (size_t j = 0;; j++)
{
const std::string aliasPath = path + ".alias[" + std::to_string(j) + ']';
if (!conf.has(aliasPath))
{
break;
}
try
{
const Poco::URI aliasUri(conf.getString(aliasPath, ""));
if (aliasUri.empty())
{
continue;
}
const Poco::URI realUri(uri);
AliasHosts.insert({ aliasUri.getAuthority(), realUri.getAuthority() });
AllHosts.insert(aliasUri.getAuthority());
StorageBase::addWopiHost(aliasUri.getHost(), allow);
}
catch (const Poco::Exception& exc)
{
LOG_WRN("parseAliases: " << exc.displayText());
}
}
}
}
std::string StorageBase::getNewUri(const Poco::URI& uri)
{
if (Util::iequal(config::getString("storage.wopi.alias_groups[@mode]", "first"), "compat"))
{
return uri.getPath();
}
Poco::URI newUri(uri);
const std::string key = newUri.getAuthority();
if (Util::matchRegex(AliasHosts, key))
{
newUri.setAuthority(AliasHosts[key]);
}
if (newUri.getAuthority().empty())
{
return newUri.getPath();
}
return newUri.getScheme() + "://" + newUri.getHost() + ':' + std::to_string(newUri.getPort()) +
newUri.getPath();
}
#endif // !defined(BUILDING_TESTS)
#endif
#if !defined(BUILDING_TESTS)
void StorageBase::initialize()
{
#if !MOBILEAPP
const auto& app = Poco::Util::Application::instance();
FilesystemEnabled = app.config().getBool("storage.filesystem[@allow]", false);
parseWopiHost(app.config());
parseAliases(app.config());
HostUtil::parseWopiHost(app.config());
#ifdef ENABLE_FEATURE_LOCK
CommandControl::LockManager::parseLockedHost(app.config());
#endif
HostUtil::parseAliases(app.config());
#if ENABLE_SSL
// FIXME: should use our own SSL socket implementation here.
Poco::Crypto::initializeCrypto();
@ -307,39 +163,6 @@ void StorageBase::initialize()
#endif
}
bool StorageBase::allowedWopiHost(const std::string& host)
{
return WopiEnabled && WopiHosts.match(host);
}
bool StorageBase::allowedAlias(const Poco::URI& uri)
{
if (Util::iequal(config::getString("storage.wopi.alias_groups[@mode]", "first"), "compat"))
{
return true;
}
if (AllHosts.empty())
{
if (FirstHost.empty())
{
FirstHost = uri.getAuthority();
}
else if (FirstHost != uri.getAuthority())
{
LOG_ERR("Only allowed host is: " << FirstHost);
return false;
}
}
else if (!Util::matchRegex(AllHosts, uri.getAuthority()))
{
LOG_ERR("Host: " << uri.getAuthority()
<< " is not allowed, It is not part of alias_groups configuration");
return false;
}
return true;
}
#if !MOBILEAPP
bool isLocalhost(const std::string& targetHost)
@ -407,12 +230,12 @@ std::unique_ptr<StorageBase> StorageBase::create(const Poco::URI& uri, const std
LOG_ERR("Local Storage is disabled by default. Enable in the config file or on the command-line to enable.");
}
#if !MOBILEAPP
else if (WopiEnabled)
else if (HostUtil::isWopiEnabled())
{
LOG_INF("Public URI [" << COOLWSD::anonymizeUrl(uri.toString()) << "] considered WOPI.");
const auto& targetHost = uri.getHost();
bool allowed(false);
if ((StorageBase::allowedWopiHost(targetHost) && StorageBase::allowedAlias(uri)) ||
if ((HostUtil::allowedWopiHost(targetHost) && HostUtil::allowedAlias(uri)) ||
isLocalhost(targetHost))
{
allowed = true;
@ -423,8 +246,8 @@ std::unique_ptr<StorageBase> StorageBase::create(const Poco::URI& uri, const std
const auto hostAddresses(Poco::Net::DNS::resolve(targetHost));
for (auto &address : hostAddresses.addresses())
{
if (StorageBase::allowedWopiHost(address.toString()) &&
StorageBase::allowedAlias(uri))
if (HostUtil::allowedWopiHost(address.toString()) &&
HostUtil::allowedAlias(uri))
{
allowed = true;
break;
@ -1051,7 +874,7 @@ WopiStorage::WOPIFileInfo::WOPIFileInfo(const FileInfo &fileInfo,
}
else
{
LOG_INF("Could not find matching locked host so applying fallback settings");
LOG_INF("Could not find matching locked_host: " << host << ",applying fallback settings");
isReadOnly = config::getBool("feature_lock.locked_hosts.fallback[@read_only]", false);
isUserLocked =
config::getBool("feature_lock.locked_hosts.fallback[@disabled_commands]", false);
@ -1691,5 +1514,4 @@ WopiStorage::handleUploadToStorageResponse(const WopiUploadDetails& details,
#endif // !MOBILEAPP
#endif // !defined(BUILDING_TESTS)
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -324,24 +324,9 @@ public:
static std::unique_ptr<StorageBase> create(const Poco::URI& uri, const std::string& jailRoot,
const std::string& jailPath, bool takeOwnership);
static bool allowedWopiHost(const std::string& host);
static Poco::Net::HTTPClientSession* getHTTPClientSession(const Poco::URI& uri);
static std::shared_ptr<http::Session> getHttpSession(const Poco::URI& uri);
static void parseWopiHost(Poco::Util::LayeredConfiguration& conf);
static void parseAliases(Poco::Util::LayeredConfiguration& conf);
/// if request uri is an alias, replace request uri host and port with
/// original hostname and port defined by group tag from coolwsd.xml
/// to avoid possibility of opening the same file as two if the WOPI host
/// is accessed using different aliases
static std::string getNewUri(const Poco::URI& uri);
static bool allowedAlias(const Poco::URI& uri);
static void addWopiHost(std::string host, bool allow);
protected:
/// Sanitize a URI by removing authorization tokens.
@ -395,19 +380,10 @@ private:
std::string _extendedData;
static bool FilesystemEnabled;
static bool WopiEnabled;
/// If true, use only the WOPI URL for whether to use SSL to talk to storage server
static bool SSLAsScheme;
/// If true, force SSL communication with storage server
static bool SSLEnabled;
/// Allowed/denied WOPI hosts, if any and if WOPI is enabled.
static Util::RegexListMatcher WopiHosts;
/// mapping of alias host and port to real host and port
static std::map<std::string, std::string> AliasHosts;
/// When group configuration is not defined only the firstHost gets access
static std::string FirstHost;
/// This contains all real and aliases host from group configuration
static std::set<std::string> AllHosts;
};
/// Trivial implementation of local storage that does not need do anything.