aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLiam Mitchell <[email protected]>2026-03-09 19:45:28 -0700
committerGitHub Enterprise <[email protected]>2026-03-09 19:45:28 -0700
commit1cdea42adf7ade0e1950c69bdef2ebf6832fdc59 (patch)
treef49a67466d076930541c9d9e0fffeb4bc73a463f /src
parentMerge pull request #710 from ue-foundation/lm/oidctoken-exe-path (diff)
parentMerge branch 'main' into lm/restrict-content-type (diff)
downloadzen-1cdea42adf7ade0e1950c69bdef2ebf6832fdc59.tar.xz
zen-1cdea42adf7ade0e1950c69bdef2ebf6832fdc59.zip
Merge pull request #752 from ue-foundation/lm/restrict-content-type
Restrict content-type on POST requests to compact binary or JSON
Diffstat (limited to 'src')
-rw-r--r--src/zen/cmds/projectstore_cmd.cpp4
-rw-r--r--src/zenserver-test/projectstore-tests.cpp8
-rw-r--r--src/zenserver/storage/projectstore/httpprojectstore.cpp28
-rw-r--r--src/zenserver/storage/projectstore/httpprojectstore.h2
-rw-r--r--src/zenserver/storage/storageconfig.cpp7
-rw-r--r--src/zenserver/storage/storageconfig.h1
-rw-r--r--src/zenserver/storage/zenstorageserver.cpp1
7 files changed, 45 insertions, 6 deletions
diff --git a/src/zen/cmds/projectstore_cmd.cpp b/src/zen/cmds/projectstore_cmd.cpp
index 5ff591b54..db931e49a 100644
--- a/src/zen/cmds/projectstore_cmd.cpp
+++ b/src/zen/cmds/projectstore_cmd.cpp
@@ -811,6 +811,7 @@ CreateOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg
}
IoBuffer OplogPayload;
+ OplogPayload.SetContentType(ZenContentType::kCbObject);
if (!m_GcPath.empty())
{
OplogPayload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer.AddString("gcpath"sv, m_GcPath); });
@@ -1144,7 +1145,7 @@ ExportOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg
if (CreateOplog)
{
ZEN_CONSOLE_WARN("Creating zen remote oplog '{}/{}'", m_ZenProjectName, m_ZenOplogName);
- if (HttpClient::Response Result = TargetHttp.Post(Url); !Result)
+ if (HttpClient::Response Result = TargetHttp.Post(Url, IoBuffer(), ZenContentType::kCbObject); !Result)
{
Result.ThrowError("failed creating zen remote oplog"sv);
}
@@ -1633,6 +1634,7 @@ ImportOplogCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** arg
if (CreateOplog)
{
IoBuffer OplogPayload;
+ OplogPayload.SetContentType(ZenContentType::kCbObject);
if (!m_GcPath.empty())
{
OplogPayload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer.AddString("gcpath"sv, m_GcPath); });
diff --git a/src/zenserver-test/projectstore-tests.cpp b/src/zenserver-test/projectstore-tests.cpp
index c73910aaa..eb2e187d7 100644
--- a/src/zenserver-test/projectstore-tests.cpp
+++ b/src/zenserver-test/projectstore-tests.cpp
@@ -88,7 +88,7 @@ TEST_CASE("project.basic")
HttpClient Http{BaseUri};
{
- auto Response = Http.Post(""sv);
+ auto Response = Http.Post(""sv, IoBuffer{}, ZenContentType::kCbObject);
CHECK(Response.StatusCode == HttpResponseCode::Created);
}
@@ -443,7 +443,8 @@ TEST_CASE("project.remote")
auto MakeOplog = [](std::string_view UrlBase, std::string_view ProjectName, std::string_view OplogName) {
HttpClient Http{UrlBase};
- HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}", ProjectName, OplogName), IoBuffer{});
+ HttpClient::Response Response =
+ Http.Post(fmt::format("/prj/{}/oplog/{}", ProjectName, OplogName), IoBuffer{}, ZenContentType::kCbObject);
REQUIRE(Response);
};
@@ -893,7 +894,8 @@ TEST_CASE("project.rpcappendop")
};
auto MakeOplog = [](HttpClient& Client, std::string_view ProjectName, std::string_view OplogName) {
- HttpClient::Response Response = Client.Post(fmt::format("/prj/{}/oplog/{}", ProjectName, OplogName));
+ HttpClient::Response Response =
+ Client.Post(fmt::format("/prj/{}/oplog/{}", ProjectName, OplogName), IoBuffer{}, ZenContentType::kCbObject);
REQUIRE_MESSAGE(Response.IsSuccess(), Response.ErrorMessage(""));
};
auto GetOplog = [](HttpClient& Client, std::string_view ProjectName, std::string_view OplogName) {
diff --git a/src/zenserver/storage/projectstore/httpprojectstore.cpp b/src/zenserver/storage/projectstore/httpprojectstore.cpp
index 661eeef5c..2fa10a292 100644
--- a/src/zenserver/storage/projectstore/httpprojectstore.cpp
+++ b/src/zenserver/storage/projectstore/httpprojectstore.cpp
@@ -666,6 +666,7 @@ HttpProjectService::HttpProjectService(CidStore& Store,
AuthMgr& AuthMgr,
OpenProcessCache& InOpenProcessCache,
JobQueue& InJobQueue,
+ bool InRestrictContentTypes,
const std::filesystem::path& InOidcTokenExePath,
bool InAllowExternalOidcTokenExe)
: m_Log(logging::Get("project"))
@@ -676,6 +677,7 @@ HttpProjectService::HttpProjectService(CidStore& Store,
, m_AuthMgr(AuthMgr)
, m_OpenProcessCache(InOpenProcessCache)
, m_JobQueue(InJobQueue)
+, m_RestrictContentTypes(InRestrictContentTypes)
, m_OidcTokenExePath(InOidcTokenExePath)
, m_AllowExternalOidcTokenExe(InAllowExternalOidcTokenExe)
{
@@ -2006,6 +2008,14 @@ HttpProjectService::HandleOpLogRequest(HttpRouterRequest& Req)
{
return HttpReq.WriteResponse(HttpResponseCode::InsufficientStorage);
}
+
+ if (m_RestrictContentTypes && (HttpReq.RequestContentType() == HttpContentType::kText ||
+ HttpReq.RequestContentType() == HttpContentType::kUnknownContentType))
+ {
+ m_ProjectStats.BadRequestCount++;
+ return HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Invalid request content type");
+ }
+
std::filesystem::path OplogMarkerPath;
if (CbObject Params = HttpReq.ReadPayloadObject())
{
@@ -2296,6 +2306,13 @@ HttpProjectService::HandleProjectRequest(HttpRouterRequest& Req)
return HttpReq.WriteResponse(HttpResponseCode::InsufficientStorage);
}
+ if (m_RestrictContentTypes && (HttpReq.RequestContentType() == HttpContentType::kText ||
+ HttpReq.RequestContentType() == HttpContentType::kUnknownContentType))
+ {
+ m_ProjectStats.BadRequestCount++;
+ return HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Invalid request content type");
+ }
+
CbValidateError ValidateResult;
if (CbObject Params = ValidateAndReadCompactBinaryObject(HttpReq.ReadPayload(), ValidateResult);
ValidateResult == CbValidateError::None)
@@ -2711,10 +2728,17 @@ HttpProjectService::HandleRpcRequest(HttpRouterRequest& Req)
CbObject Cb;
switch (PayloadContentType)
{
- case HttpContentType::kJSON:
- case HttpContentType::kUnknownContentType:
case HttpContentType::kText:
+ case HttpContentType::kUnknownContentType:
+ case HttpContentType::kJSON:
{
+ if (m_RestrictContentTypes &&
+ (PayloadContentType == HttpContentType::kText || PayloadContentType == HttpContentType::kUnknownContentType))
+ {
+ m_ProjectStats.BadRequestCount++;
+ return HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "Invalid request content type");
+ }
+
std::string JsonText(reinterpret_cast<const char*>(Payload.GetData()), Payload.GetSize());
Cb = LoadCompactBinaryFromJson(JsonText).AsObject();
if (!Cb)
diff --git a/src/zenserver/storage/projectstore/httpprojectstore.h b/src/zenserver/storage/projectstore/httpprojectstore.h
index 8bf2162e1..917337324 100644
--- a/src/zenserver/storage/projectstore/httpprojectstore.h
+++ b/src/zenserver/storage/projectstore/httpprojectstore.h
@@ -45,6 +45,7 @@ public:
AuthMgr& AuthMgr,
OpenProcessCache& InOpenProcessCache,
JobQueue& InJobQueue,
+ bool InRestrictContentTypes,
const std::filesystem::path& InOidcTokenExePath,
bool AllowExternalOidcTokenExe);
~HttpProjectService();
@@ -112,6 +113,7 @@ private:
metrics::OperationTiming m_HttpRequests;
RwLock m_ThreadWorkersLock;
Ref<TransferThreadWorkers> m_ThreadWorkers;
+ bool m_RestrictContentTypes;
std::filesystem::path m_OidcTokenExePath;
bool m_AllowExternalOidcTokenExe;
diff --git a/src/zenserver/storage/storageconfig.cpp b/src/zenserver/storage/storageconfig.cpp
index 1554c9e51..e8ccb9097 100644
--- a/src/zenserver/storage/storageconfig.cpp
+++ b/src/zenserver/storage/storageconfig.cpp
@@ -496,6 +496,7 @@ ZenStorageServerConfigurator::AddConfigOptions(LuaConfig::Options& LuaOptions)
LuaOptions.AddOption("security.encryptionaeskey"sv, ServerOptions.EncryptionKey, "encryption-aes-key"sv);
LuaOptions.AddOption("security.encryptionaesiv"sv, ServerOptions.EncryptionIV, "encryption-aes-iv"sv);
LuaOptions.AddOption("security.openidproviders"sv, ServerOptions.AuthConfig);
+ LuaOptions.AddOption("security.restrictcontenttypes"sv, ServerOptions.RestrictContentTypes, "restrict-content-types"sv);
LuaOptions.AddOption("security.oidctokenexecutable"sv, ServerOptions.OidcTokenExecutable, "oidctoken-exe-path"sv);
LuaOptions.AddOption("security.allowexternaloidctokenexecutable"sv,
ServerOptions.AllowExternalOidcTokenExe,
@@ -655,6 +656,12 @@ ZenStorageServerCmdLineOptions::AddSecurityOptions(cxxopts::Options& options, Ze
options.add_option("security", "", "openid-client-id", "Open ID client ID", cxxopts::value<std::string>(OpenIdClientId), "");
options.add_option("security",
"",
+ "restrict-content-types",
+ "Restrict content-type in requests to content-types that are not allowed in CORS simple requests",
+ cxxopts::value<bool>(ServerOptions.RestrictContentTypes),
+ "");
+ options.add_option("security",
+ "",
"oidctoken-exe-path",
"Path to OidcToken executable",
cxxopts::value<std::string>(OidcTokenExecutable),
diff --git a/src/zenserver/storage/storageconfig.h b/src/zenserver/storage/storageconfig.h
index dd8c41041..128804d92 100644
--- a/src/zenserver/storage/storageconfig.h
+++ b/src/zenserver/storage/storageconfig.h
@@ -159,6 +159,7 @@ struct ZenStorageServerConfig : public ZenServerConfig
bool ObjectStoreEnabled = false;
bool ComputeEnabled = true;
std::string ScrubOptions;
+ bool RestrictContentTypes = false;
std::filesystem::path OidcTokenExecutable;
bool AllowExternalOidcTokenExe = true;
};
diff --git a/src/zenserver/storage/zenstorageserver.cpp b/src/zenserver/storage/zenstorageserver.cpp
index c5df78abc..d4b8e37ef 100644
--- a/src/zenserver/storage/zenstorageserver.cpp
+++ b/src/zenserver/storage/zenstorageserver.cpp
@@ -229,6 +229,7 @@ ZenStorageServer::InitializeServices(const ZenStorageServerConfig& ServerOptions
*m_AuthMgr,
*m_OpenProcessCache,
*m_JobQueue,
+ ServerOptions.RestrictContentTypes,
ServerOptions.OidcTokenExecutable,
ServerOptions.AllowExternalOidcTokenExe});