mirror of
https://github.com/alibaba/higress.git
synced 2026-03-05 17:10:55 +08:00
Update extensions & release 1.0.0-rc (#281)
This commit is contained in:
@@ -1,3 +1,17 @@
|
||||
# Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
|
||||
load("//bazel:wasm.bzl", "declare_wasm_image_targets")
|
||||
|
||||
@@ -31,7 +45,7 @@ cc_library(
|
||||
visibility = ["//visibility:public"],
|
||||
alwayslink = 1,
|
||||
deps = [
|
||||
"//common:rule_util",
|
||||
"//common:rule_util_nullvm",
|
||||
"//common:json_util",
|
||||
"//common:crypto_util",
|
||||
"@com_google_absl//absl/strings",
|
||||
|
||||
@@ -308,8 +308,7 @@ bool PluginRootContext::onConfigure(size_t size) {
|
||||
// Parse configuration JSON string.
|
||||
if (size > 0 && !configure(size)) {
|
||||
LOG_WARN("configuration has errors initialization will not continue.");
|
||||
setInvalidConfig();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -909,7 +909,8 @@ TEST_F(BasicAuthTest, GlobalDeny) {
|
||||
}
|
||||
|
||||
TEST_F(BasicAuthTest, GlobalWithConsumerDeny) {
|
||||
std::string configuration = R"(
|
||||
{
|
||||
std::string configuration = R"(
|
||||
{
|
||||
"consumers" : [
|
||||
{"credential" : "ok:test", "name" : "consumer_ok"},
|
||||
@@ -932,36 +933,171 @@ TEST_F(BasicAuthTest, GlobalWithConsumerDeny) {
|
||||
}
|
||||
]
|
||||
})";
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
|
||||
cred_ = "wrong-cred";
|
||||
route_name_ = "config";
|
||||
authorization_header_ = "Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
cred_ = "wrong-cred";
|
||||
route_name_ = "not match";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::Continue);
|
||||
|
||||
authority_ = "www.example.com";
|
||||
cred_ = "admin2:admin2";
|
||||
authorization_header_ = "Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
cred_ = "wrong-cred";
|
||||
route_name_ = "config";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
|
||||
route_name_ = "config";
|
||||
cred_ = "admin4:admin4";
|
||||
authorization_header_ = "Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
authority_ = "www.example.com";
|
||||
cred_ = "admin2:admin2";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
|
||||
route_name_ = "config";
|
||||
cred_ = "admin4:admin4";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
}
|
||||
{
|
||||
std::string configuration = R"(
|
||||
{
|
||||
"global_auth": true,
|
||||
"consumers" : [
|
||||
{"credential" : "ok:test", "name" : "consumer_ok"},
|
||||
{"credential" : "admin2:admin2", "name" : "consumer2"},
|
||||
{"credential" : "admin:admin", "name" : "consumer"}
|
||||
],
|
||||
"_rules_" : [
|
||||
{
|
||||
"_match_route_" : ["test", "config"],
|
||||
"consumers" : [
|
||||
{"credential" : "admin3:admin3", "name" : "consumer3"},
|
||||
{"credential" : "YWRtaW41OmFkbWluNQ==", "name" : "consumer5"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"_match_domain_" : ["test.com", "*.example.com"],
|
||||
"consumers" : [
|
||||
{"credential" : "admin4:admin4", "name" : "consumer4"}
|
||||
]
|
||||
}
|
||||
]
|
||||
})";
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
|
||||
cred_ = "wrong-cred";
|
||||
route_name_ = "not match";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
|
||||
cred_ = "wrong-cred";
|
||||
route_name_ = "config";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
|
||||
authority_ = "www.example.com";
|
||||
cred_ = "admin2:admin2";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
|
||||
route_name_ = "config";
|
||||
cred_ = "admin4:admin4";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BasicAuthTest, OnConfigureNoRulesAuth) {
|
||||
// enable global auth
|
||||
{
|
||||
std::string configuration = R"(
|
||||
{
|
||||
"consumers" : [
|
||||
{"credential" : "getuser1:123456", "name" : "consumer1"}
|
||||
]
|
||||
})";
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
cred_ = "admin:admin";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(401, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
cred_ = "getuser1:123456";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::Continue);
|
||||
}
|
||||
// disable global auth
|
||||
{
|
||||
std::string configuration = R"(
|
||||
{
|
||||
"consumers" : [
|
||||
{"credential" : "getuser1:123456", "name" : "consumer1"}
|
||||
],
|
||||
"global_auth": false
|
||||
})";
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
cred_ = "admin:admin";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::Continue);
|
||||
cred_ = "getuser1:123456";
|
||||
authorization_header_ =
|
||||
"Basic " + Base64::encode(cred_.data(), cred_.size());
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::Continue);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace basic_auth
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
|
||||
load("//bazel:wasm.bzl", "declare_wasm_image_targets")
|
||||
|
||||
@@ -11,10 +25,10 @@ wasm_cc_binary(
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/time",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
"//common:http_util",
|
||||
"//common:regex_util",
|
||||
"//common:rule_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -31,9 +45,9 @@ cc_library(
|
||||
"@com_google_absl//absl/strings",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_host//:lib",
|
||||
"//common:http_util",
|
||||
"//common:http_util_nullvm",
|
||||
"//common:regex_util",
|
||||
"//common:rule_util",
|
||||
"//common:rule_util_nullvm",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -78,13 +78,13 @@ bool PluginRootContext::parsePluginConfig(const json& configuration,
|
||||
LOG_WARN("cannot parse allow");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
rule.allow.push_back(
|
||||
std::make_unique<ReMatcher>(regex.first.value()));
|
||||
} catch (const std::runtime_error& e) {
|
||||
LOG_WARN(e.what());
|
||||
auto re = std::make_unique<ReMatcher>(regex.first.value());
|
||||
if (!re->error().empty()) {
|
||||
LOG_WARN(re->error());
|
||||
return false;
|
||||
}
|
||||
rule.allow.push_back(std::move(re));
|
||||
|
||||
return true;
|
||||
})) {
|
||||
LOG_WARN("failed to parse configuration for allow.");
|
||||
@@ -96,12 +96,13 @@ bool PluginRootContext::parsePluginConfig(const json& configuration,
|
||||
LOG_WARN("cannot parse deny");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
rule.deny.push_back(std::make_unique<ReMatcher>(regex.first.value()));
|
||||
} catch (const std::runtime_error& e) {
|
||||
LOG_WARN(e.what());
|
||||
auto re = std::make_unique<ReMatcher>(regex.first.value());
|
||||
if (!re->error().empty()) {
|
||||
LOG_WARN(re->error());
|
||||
return false;
|
||||
}
|
||||
rule.deny.push_back(std::move(re));
|
||||
|
||||
return true;
|
||||
})) {
|
||||
LOG_WARN("failed to parse configuration for deny.");
|
||||
@@ -114,8 +115,7 @@ bool PluginRootContext::onConfigure(size_t size) {
|
||||
// Parse configuration JSON string.
|
||||
if (size > 0 && !configure(size)) {
|
||||
LOG_WARN("configuration has errors initialization will not continue.");
|
||||
setInvalidConfig();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (size == 0) {
|
||||
// support empty config
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
|
||||
load("//bazel:wasm.bzl", "declare_wasm_image_targets")
|
||||
|
||||
@@ -11,9 +25,9 @@ wasm_cc_binary(
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/time",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
"//common:http_util",
|
||||
"//common:rule_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -149,8 +149,7 @@ bool PluginRootContext::onConfigure(size_t size) {
|
||||
// Parse configuration JSON string.
|
||||
if (size > 0 && !configure(size)) {
|
||||
LOG_WARN("configuration has errors initialization will not continue.");
|
||||
setInvalidConfig();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
|
||||
load("//bazel:wasm.bzl", "declare_wasm_image_targets")
|
||||
|
||||
@@ -13,10 +27,10 @@ wasm_cc_binary(
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
"@com_google_absl//absl/time",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
"//common:crypto_util",
|
||||
"//common:http_util",
|
||||
"//common:rule_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -37,8 +51,8 @@ cc_library(
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_host//:lib",
|
||||
"//common:crypto_util",
|
||||
"//common:http_util",
|
||||
"//common:rule_util",
|
||||
"//common:http_util_nullvm",
|
||||
"//common:rule_util_nullvm",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -389,8 +389,7 @@ bool PluginRootContext::onConfigure(size_t size) {
|
||||
// Parse configuration JSON string.
|
||||
if (size > 0 && !configure(size)) {
|
||||
LOG_WARN("configuration has errors initialization will not continue.");
|
||||
setInvalidConfig();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
|
||||
load("//bazel:wasm.bzl", "declare_wasm_image_targets")
|
||||
|
||||
@@ -17,9 +31,9 @@ wasm_cc_binary(
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
"@com_google_absl//absl/time",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
"//common:http_util",
|
||||
"//common:rule_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -135,11 +135,16 @@ bool PluginRootContext::parsePluginConfig(const json& configuration,
|
||||
[&](const json& from_header) -> bool {
|
||||
JSON_FIND_FIELD(from_header, name);
|
||||
JSON_FIELD_VALUE_AS(std::string, from_header, name);
|
||||
JSON_FIND_FIELD(from_header, value_prefix);
|
||||
JSON_FIELD_VALUE_AS(std::string, from_header,
|
||||
value_prefix);
|
||||
from_headers.push_back(FromHeader{
|
||||
from_header_name, from_header_value_prefix});
|
||||
std::string header_value_prefix;
|
||||
auto from_header_value_prefix_json =
|
||||
from_header.find("value_prefix");
|
||||
if (from_header_value_prefix_json != from_header.end()) {
|
||||
JSON_FIELD_VALUE_AS(std::string, from_header,
|
||||
value_prefix);
|
||||
header_value_prefix = from_header_value_prefix;
|
||||
}
|
||||
from_headers.push_back(
|
||||
FromHeader{from_header_name, header_value_prefix});
|
||||
return true;
|
||||
})) {
|
||||
LOG_WARN("failed to parse 'from_headers' in consumer: " +
|
||||
@@ -229,6 +234,18 @@ bool PluginRootContext::parsePluginConfig(const json& configuration,
|
||||
LOG_INFO("at least one consumer has to be configured for a rule.");
|
||||
return false;
|
||||
}
|
||||
std::vector<std::string> enable_headers;
|
||||
if (!JsonArrayIterate(configuration, "enable_headers",
|
||||
[&](const json& enable_header_json) -> bool {
|
||||
JSON_VALUE_AS(std::string, enable_header_json,
|
||||
enable_header, "invalid item");
|
||||
enable_headers.push_back(enable_header);
|
||||
return true;
|
||||
})) {
|
||||
LOG_WARN("failed to parse 'enable_headers'");
|
||||
return false;
|
||||
}
|
||||
rule.enable_headers = std::move(enable_headers);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -307,6 +324,20 @@ Status PluginRootContext::consumerVerify(
|
||||
bool PluginRootContext::checkPlugin(
|
||||
const JwtAuthConfigRule& rule,
|
||||
const std::optional<std::unordered_set<std::string>>& allow_set) {
|
||||
if (!rule.enable_headers.empty()) {
|
||||
bool skip_auth = true;
|
||||
for (const auto& enable_header : rule.enable_headers) {
|
||||
auto header_ptr = getRequestHeader(enable_header);
|
||||
if (header_ptr->size() > 0) {
|
||||
LOG_DEBUG("enable by header: " + header_ptr->toString());
|
||||
skip_auth = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip_auth) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
std::optional<Status> err_status;
|
||||
bool verified = false;
|
||||
uint64_t now = getCurrentTimeNanoseconds() / 1e9;
|
||||
@@ -354,8 +385,7 @@ bool PluginRootContext::onConfigure(size_t size) {
|
||||
// Parse configuration JSON string.
|
||||
if (size > 0 && !configure(size)) {
|
||||
LOG_WARN("configuration has errors initialization will not continue.");
|
||||
setInvalidConfig();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ struct Consumer {
|
||||
|
||||
struct JwtAuthConfigRule {
|
||||
std::vector<Consumer> consumers;
|
||||
std::vector<std::string> enable_headers;
|
||||
};
|
||||
|
||||
// PluginRootContext is the root context for all streams processed by the
|
||||
|
||||
@@ -84,6 +84,9 @@ class JwtAuthTest : public ::testing::Test {
|
||||
if (header == "Authorization") {
|
||||
*result = jwt_header_;
|
||||
}
|
||||
if (header == "x-custom-header") {
|
||||
*result = custom_header_;
|
||||
}
|
||||
return WasmResult::Ok;
|
||||
});
|
||||
ON_CALL(*mock_context_, addHeaderMapValue(WasmHeaderMapType::RequestHeaders,
|
||||
@@ -118,6 +121,7 @@ class JwtAuthTest : public ::testing::Test {
|
||||
std::string authority_;
|
||||
std::string route_name_;
|
||||
std::string jwt_header_;
|
||||
std::string custom_header_;
|
||||
uint64_t current_time_;
|
||||
};
|
||||
|
||||
@@ -146,7 +150,8 @@ TEST_F(JwtAuthTest, RSA) {
|
||||
}
|
||||
|
||||
TEST_F(JwtAuthTest, OCT) {
|
||||
std::string configuration = R"(
|
||||
{
|
||||
std::string configuration = R"(
|
||||
{
|
||||
"consumers": [
|
||||
{
|
||||
@@ -156,17 +161,65 @@ TEST_F(JwtAuthTest, OCT) {
|
||||
}
|
||||
]
|
||||
})";
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
current_time_ = 1665673819 * 1e9;
|
||||
jwt_header_ =
|
||||
R"(Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxNjY1NjczODE5fQ.7BVJOAobz_xYjsenu_CsYhYbgF1gMcqZSpaeQ8HwKmc)";
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::Continue);
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
current_time_ = 1665673819 * 1e9;
|
||||
jwt_header_ =
|
||||
R"(Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxNjY1NjczODE5fQ.7BVJOAobz_xYjsenu_CsYhYbgF1gMcqZSpaeQ8HwKmc)";
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::Continue);
|
||||
}
|
||||
{
|
||||
std::string configuration = R"(
|
||||
{
|
||||
"consumers": [
|
||||
{
|
||||
"name": "consumer-2",
|
||||
"issuer": "abcd",
|
||||
"jwks": "{\"keys\":[{\"kty\":\"oct\",\"kid\":\"123\",\"k\":\"hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew\",\"alg\":\"HS256\"}]}"
|
||||
}
|
||||
]
|
||||
})";
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
current_time_ = 1665673819 * 1e9;
|
||||
jwt_header_ =
|
||||
R"(Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxNjY1NjczODE5fQ.7BVJOAobz_xYjsenu_CsYhYbgF1gMcqZSpaeQ8HwKm1)";
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
}
|
||||
{
|
||||
std::string configuration = R"(
|
||||
{
|
||||
"consumers": [
|
||||
{
|
||||
"name": "consumer-2",
|
||||
"issuer": "abcd",
|
||||
"jwks": "{\"keys\":[{\"kty\":\"oct\",\"kid\":\"123\",\"k\":\"hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew\",\"alg\":\"HS256\"}]}"
|
||||
}
|
||||
],
|
||||
"global_auth": false
|
||||
})";
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
current_time_ = 1665673819 * 1e9;
|
||||
jwt_header_ =
|
||||
R"(Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxNjY1NjczODE5fQ.7BVJOAobz_xYjsenu_CsYhYbgF1gMcqZSpaeQ8HwKm1)";
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::Continue);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(JwtAuthTest, AuthZ) {
|
||||
@@ -264,6 +317,97 @@ TEST_F(JwtAuthTest, ClaimToHeader) {
|
||||
FilterHeadersStatus::Continue);
|
||||
}
|
||||
|
||||
TEST_F(JwtAuthTest, CustomHeader) {
|
||||
std::string configuration = R"(
|
||||
{
|
||||
"consumers": [
|
||||
{
|
||||
"name": "consumer-2",
|
||||
"issuer": "abcd",
|
||||
"from_headers": [
|
||||
{
|
||||
"name": "x-custom-header",
|
||||
"value_prefix": "token "
|
||||
},
|
||||
{
|
||||
"name": "Authorization"
|
||||
}
|
||||
],
|
||||
"jwks": "{\"keys\":[{\"kty\":\"oct\",\"kid\":\"123\",\"k\":\"hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew\",\"alg\":\"HS256\"}]}"
|
||||
}
|
||||
]
|
||||
})";
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
custom_header_ =
|
||||
R"(token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxNjY1NjczODE5fQ.7BVJOAobz_xYjsenu_CsYhYbgF1gMcqZSpaeQ8HwKmc)";
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::Continue);
|
||||
custom_header_.clear();
|
||||
jwt_header_ =
|
||||
R"(eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxNjY1NjczODE5fQ.7BVJOAobz_xYjsenu_CsYhYbgF1gMcqZSpaeQ8HwKmc)";
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::Continue);
|
||||
}
|
||||
|
||||
TEST_F(JwtAuthTest, SkipAuthHeader) {
|
||||
std::string configuration = R"(
|
||||
{
|
||||
"consumers": [
|
||||
{
|
||||
"name": "consumer-1",
|
||||
"issuer": "abc",
|
||||
"jwks": "{\"keys\":[{\"kty\":\"RSA\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"123\",\"alg\":\"RS256\",\"n\":\"i0B67f1jggT9QJlZ_8QL9QQ56LfurrqDhpuu8BxtVcfxrYmaXaCtqTn7OfCuca7cGHdrJIjq99rz890NmYFZuvhaZ-LMt2iyiSb9LZJAeJmHf7ecguXS_-4x3hvbsrgUDi9tlg7xxbqGYcrco3anmalAFxsbswtu2PAXLtTnUo6aYwZsWA6ksq4FL3-anPNL5oZUgIp3HGyhhLTLdlQcC83jzxbguOim-0OEz-N4fniTYRivK7MlibHKrJfO3xa_6whBS07HW4Ydc37ZN3Rx9Ov3ZyV0idFblU519nUdqp_inXj1eEpynlxH60Ys_aTU2POGZh_25KXGdF_ZC_MSRw\"}]}"
|
||||
},
|
||||
{
|
||||
"name": "consumer-2",
|
||||
"issuer": "abcd",
|
||||
"jwks": "{\"keys\":[{\"kty\":\"oct\",\"kid\":\"123\",\"k\":\"hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew\",\"alg\":\"HS256\"}]}"
|
||||
}
|
||||
],
|
||||
"enable_headers": ["x-custom-header"],
|
||||
"_rules_": [{
|
||||
"_match_route_": [
|
||||
"test1"
|
||||
],
|
||||
"allow": [
|
||||
"consumer-1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"_match_route_": [
|
||||
"test2"
|
||||
],
|
||||
"allow": [
|
||||
"consumer-2"
|
||||
]
|
||||
}
|
||||
]
|
||||
})";
|
||||
BufferBase buffer;
|
||||
buffer.set({configuration.data(), configuration.size()});
|
||||
|
||||
EXPECT_CALL(*mock_context_, getBuffer(WasmBufferType::PluginConfiguration))
|
||||
.WillOnce([&buffer](WasmBufferType) { return &buffer; });
|
||||
EXPECT_TRUE(root_context_->configure(configuration.size()));
|
||||
current_time_ = 1665673819 * 1e9;
|
||||
jwt_header_ =
|
||||
R"(Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxNjY1NjczODE5fQ.7BVJOAobz_xYjsenu_CsYhYbgF1gMcqZSpaeQ8HwKmc)";
|
||||
route_name_ = "test1";
|
||||
custom_header_ = "123";
|
||||
EXPECT_CALL(*mock_context_, sendLocalResponse(403, testing::_, testing::_,
|
||||
testing::_, testing::_));
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::StopIteration);
|
||||
custom_header_ = "";
|
||||
EXPECT_EQ(context_->onRequestHeaders(0, false),
|
||||
FilterHeadersStatus::Continue);
|
||||
}
|
||||
|
||||
} // namespace jwt_auth
|
||||
} // namespace null_plugin
|
||||
} // namespace proxy_wasm
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
|
||||
load("//bazel:wasm.bzl", "declare_wasm_image_targets")
|
||||
|
||||
@@ -12,9 +26,9 @@ wasm_cc_binary(
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/time",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
"//common:http_util",
|
||||
"//common:rule_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -33,8 +47,8 @@ cc_library(
|
||||
"@com_google_absl//absl/time",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_host//:lib",
|
||||
"//common:http_util",
|
||||
"//common:rule_util",
|
||||
"//common:http_util_nullvm",
|
||||
"//common:rule_util_nullvm",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -211,8 +211,7 @@ bool PluginRootContext::onConfigure(size_t size) {
|
||||
// Parse configuration JSON string.
|
||||
if (size > 0 && !configure(size)) {
|
||||
LOG_WARN("configuration has errors initialization will not continue.");
|
||||
setInvalidConfig();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
|
||||
load("//bazel:wasm.bzl", "declare_wasm_image_targets")
|
||||
|
||||
@@ -13,9 +27,9 @@ wasm_cc_binary(
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/time",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
"//common:http_util",
|
||||
"//common:rule_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -34,8 +48,8 @@ cc_library(
|
||||
"@com_google_absl//absl/strings",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_host//:lib",
|
||||
"//common:http_util",
|
||||
"//common:rule_util",
|
||||
"//common:http_util_nullvm",
|
||||
"//common:rule_util_nullvm",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
|
||||
namespace {
|
||||
@@ -40,11 +41,16 @@ bool getToken(int rule_id, const std::string &key) {
|
||||
for (int i = 0; i < maxGetTokenRetry; i++) {
|
||||
if (WasmResult::Ok !=
|
||||
getSharedData(tokenBucketKey, &token_bucket_data, &cas)) {
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
uint64_t token_left =
|
||||
*reinterpret_cast<const uint64_t *>(token_bucket_data->data());
|
||||
LOG_DEBUG(absl::StrFormat(
|
||||
"ratelimit get token: id:%d, tokenBucketKey:%s, token left:%u", rule_id,
|
||||
tokenBucketKey, token_left));
|
||||
if (token_left == 0) {
|
||||
LOG_DEBUG(absl::StrFormat("get token failed, id:%d, tokenBucketKey:%s",
|
||||
rule_id, tokenBucketKey));
|
||||
return false;
|
||||
}
|
||||
token_left -= 1;
|
||||
@@ -52,12 +58,18 @@ bool getToken(int rule_id, const std::string &key) {
|
||||
tokenBucketKey,
|
||||
{reinterpret_cast<const char *>(&token_left), sizeof(token_left)}, cas);
|
||||
if (res == WasmResult::Ok) {
|
||||
LOG_DEBUG(
|
||||
absl::StrFormat("ratelimit token update success: id:%d, "
|
||||
"tokenBucketKey:%s, token left:%u",
|
||||
rule_id, tokenBucketKey, token_left));
|
||||
return true;
|
||||
}
|
||||
if (res == WasmResult::CasMismatch) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
LOG_WARN(absl::StrFormat("got invalid result:%d, id:%d, tokenBucketKey:%s",
|
||||
res, rule_id, tokenBucketKey));
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_WARN("get token failed with cas mismatch");
|
||||
@@ -86,12 +98,21 @@ void refillToken(const std::vector<std::pair<int, LimitItem>> &rules) {
|
||||
if (now - last_update < rule.second.refill_interval_nanosec) {
|
||||
continue;
|
||||
}
|
||||
LOG_DEBUG(
|
||||
absl::StrFormat("ratelimit rule need refilled, id:%s, "
|
||||
"lastRefilledKey:%s, now:%u, last_update:%u",
|
||||
id, lastRefilledKey, now, last_update));
|
||||
// Otherwise, try set last updated time. If updated failed because of cas
|
||||
// mismatch, the bucket is going to be refilled by other VMs.
|
||||
auto res = setSharedData(
|
||||
lastRefilledKey, {reinterpret_cast<const char *>(&now), sizeof(now)},
|
||||
last_update_cas);
|
||||
if (res == WasmResult::CasMismatch) {
|
||||
LOG_DEBUG(
|
||||
absl::StrFormat("ratelimit update lastRefilledKey casmismatch, the "
|
||||
"bucket is going to be refilled by other VMs, id:%s, "
|
||||
"lastRefilledKey:%s",
|
||||
id, lastRefilledKey));
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
@@ -115,6 +136,10 @@ void refillToken(const std::vector<std::pair<int, LimitItem>> &rules) {
|
||||
last_update_cas)) {
|
||||
continue;
|
||||
}
|
||||
LOG_DEBUG(
|
||||
absl::StrFormat("ratelimit token refilled: id:%s, "
|
||||
"tokenBucketKey:%s, token left:%u",
|
||||
id, tokenBucketKey, token_left));
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
@@ -138,6 +163,10 @@ bool initializeTokenBucket(
|
||||
setSharedData(tokenBucketKey,
|
||||
{reinterpret_cast<const char *>(&rule.second.max_tokens),
|
||||
sizeof(uint64_t)});
|
||||
LOG_INFO(absl::StrFormat(
|
||||
"ratelimit rule created: id:%s, lastRefilledKey:%s, "
|
||||
"tokenBucketKey:%s, max_tokens:%u",
|
||||
id, lastRefilledKey, tokenBucketKey, rule.second.max_tokens));
|
||||
continue;
|
||||
}
|
||||
// reconfigure
|
||||
@@ -172,6 +201,10 @@ bool initializeTokenBucket(
|
||||
}
|
||||
break;
|
||||
} while (true);
|
||||
LOG_INFO(absl::StrFormat(
|
||||
"ratelimit rule reconfigured: id:%s, lastRefilledKey:%s, "
|
||||
"tokenBucketKey:%s, max_tokens:%u",
|
||||
id, lastRefilledKey, tokenBucketKey, rule.second.max_tokens));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -169,6 +169,7 @@ bool PluginRootContext::checkPlugin(int rule_id,
|
||||
return true;
|
||||
}
|
||||
if (!getToken(rule_id, key)) {
|
||||
LOG_INFO(absl::StrCat("request rate limited by key: ", key));
|
||||
tooManyRequest();
|
||||
return false;
|
||||
}
|
||||
@@ -181,8 +182,7 @@ bool PluginRootContext::onConfigure(size_t size) {
|
||||
// Parse configuration JSON string.
|
||||
if (size > 0 && !configure(size)) {
|
||||
LOG_WARN("configuration has errors initialization will not continue.");
|
||||
setInvalidConfig();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
const auto& rules = getRules();
|
||||
for (const auto& rule : rules) {
|
||||
@@ -191,7 +191,7 @@ bool PluginRootContext::onConfigure(size_t size) {
|
||||
}
|
||||
}
|
||||
initializeTokenBucket(limits_);
|
||||
proxy_set_tick_period_milliseconds(1000);
|
||||
proxy_set_tick_period_milliseconds(500);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
|
||||
load("//bazel:wasm.bzl", "declare_wasm_image_targets")
|
||||
|
||||
@@ -11,9 +25,9 @@ wasm_cc_binary(
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/time",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
"//common:http_util",
|
||||
"//common:rule_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -30,8 +44,8 @@ cc_library(
|
||||
"@com_google_absl//absl/strings",
|
||||
"//common:json_util",
|
||||
"@proxy_wasm_cpp_host//:lib",
|
||||
"//common:http_util",
|
||||
"//common:rule_util",
|
||||
"//common:http_util_nullvm",
|
||||
"//common:rule_util_nullvm",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -108,24 +108,24 @@ bool PluginRootContext::parsePluginConfig(const json& configuration,
|
||||
return false;
|
||||
}
|
||||
if (!JsonArrayIterate(
|
||||
configuration, "block_bodies", [&](const json& item) -> bool {
|
||||
configuration, "block_bodys", [&](const json& item) -> bool {
|
||||
auto body = JsonValueAs<std::string>(item);
|
||||
if (body.second != Wasm::Common::JsonParserResultDetail::OK) {
|
||||
LOG_WARN("cannot parse block_bodies");
|
||||
LOG_WARN("cannot parse block_bodys");
|
||||
return false;
|
||||
}
|
||||
if (rule.case_sensitive) {
|
||||
rule.block_bodies.push_back(std::move(body.first.value()));
|
||||
rule.block_bodys.push_back(std::move(body.first.value()));
|
||||
} else {
|
||||
rule.block_bodies.push_back(
|
||||
rule.block_bodys.push_back(
|
||||
absl::AsciiStrToLower(body.first.value()));
|
||||
}
|
||||
return true;
|
||||
})) {
|
||||
LOG_WARN("failed to parse configuration for block_bodies.");
|
||||
LOG_WARN("failed to parse configuration for block_bodys.");
|
||||
return false;
|
||||
}
|
||||
if (rule.block_bodies.empty() && rule.block_headers.empty() &&
|
||||
if (rule.block_bodys.empty() && rule.block_headers.empty() &&
|
||||
rule.block_urls.empty()) {
|
||||
LOG_WARN("there is no block rules");
|
||||
return false;
|
||||
@@ -137,8 +137,7 @@ bool PluginRootContext::onConfigure(size_t size) {
|
||||
// Parse configuration JSON string.
|
||||
if (size > 0 && !configure(size)) {
|
||||
LOG_WARN("configuration has errors initialization will not continue.");
|
||||
setInvalidConfig();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -197,7 +196,7 @@ bool PluginRootContext::checkHeader(const RequestBlockConfigRule& rule,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!rule.block_bodies.empty()) {
|
||||
if (!rule.block_bodys.empty()) {
|
||||
check_body = true;
|
||||
}
|
||||
return true;
|
||||
@@ -212,7 +211,7 @@ bool PluginRootContext::checkBody(const RequestBlockConfigRule& rule,
|
||||
bodystr = absl::AsciiStrToLower(request_body);
|
||||
body = bodystr;
|
||||
}
|
||||
for (const auto& block_body : rule.block_bodies) {
|
||||
for (const auto& block_body : rule.block_bodys) {
|
||||
if (absl::StrContains(body, block_body)) {
|
||||
sendLocalResponse(rule.blocked_code, "", rule.blocked_message, {});
|
||||
return false;
|
||||
|
||||
@@ -45,7 +45,7 @@ struct RequestBlockConfigRule {
|
||||
bool case_sensitive = true;
|
||||
std::vector<std::string> block_urls;
|
||||
std::vector<std::string> block_headers;
|
||||
std::vector<std::string> block_bodies;
|
||||
std::vector<std::string> block_bodys;
|
||||
};
|
||||
|
||||
// PluginRootContext is the root context for all streams processed by the
|
||||
|
||||
@@ -128,7 +128,7 @@ TEST_F(RequestBlockTest, CaseSensitive) {
|
||||
{
|
||||
"block_urls": ["?foo=bar", "swagger.html"],
|
||||
"block_headers": ["headerKey", "headerValue"],
|
||||
"block_bodies": ["Hello World"]
|
||||
"block_bodys": ["Hello World"]
|
||||
})";
|
||||
|
||||
config_.set({configuration.data(), configuration.size()});
|
||||
@@ -188,7 +188,7 @@ TEST_F(RequestBlockTest, CaseInsensitive) {
|
||||
"blocked_code": 404,
|
||||
"block_urls": ["?foo=bar", "swagger.html"],
|
||||
"block_headers": ["headerKey", "headerValue"],
|
||||
"block_bodies": ["Hello World"]
|
||||
"block_bodys": ["Hello World"]
|
||||
})";
|
||||
|
||||
config_.set({configuration.data(), configuration.size()});
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# Copyright (c) 2022 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("@proxy_wasm_cpp_sdk//bazel/wasm:wasm.bzl", "wasm_cc_binary")
|
||||
load("//bazel:wasm.bzl", "declare_wasm_image_targets")
|
||||
|
||||
@@ -10,8 +24,8 @@ wasm_cc_binary(
|
||||
deps = [
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
"//common:http_util",
|
||||
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -30,7 +44,7 @@ cc_library(
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@proxy_wasm_cpp_host//:lib",
|
||||
"//common:http_util",
|
||||
"//common:http_util_nullvm",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user