diff --git a/plugins/wasm-cpp/common/route_rule_matcher.h b/plugins/wasm-cpp/common/route_rule_matcher.h index 506af4b4b..b07c95fd6 100644 --- a/plugins/wasm-cpp/common/route_rule_matcher.h +++ b/plugins/wasm-cpp/common/route_rule_matcher.h @@ -387,6 +387,8 @@ class RouteRuleMatcher { return true; } + request_host = Wasm::Common::Http::stripPortFromHost(request_host); + for (const auto& host_match : rule.hosts) { const auto& host = host_match.second; switch (host_match.first) { diff --git a/plugins/wasm-cpp/extensions/basic_auth/plugin_test.cc b/plugins/wasm-cpp/extensions/basic_auth/plugin_test.cc index def1fdb2b..dcfb652ef 100644 --- a/plugins/wasm-cpp/extensions/basic_auth/plugin_test.cc +++ b/plugins/wasm-cpp/extensions/basic_auth/plugin_test.cc @@ -584,6 +584,48 @@ TEST_F(BasicAuthTest, RuleWithConsumerAllow) { FilterHeadersStatus::Continue); } +TEST_F(BasicAuthTest, GlobalAuthRuleWithDomainPort) { + std::string configuration = R"( +{ + "global_auth": true, + "consumers" : [ + {"credential" : "ok:test", "name" : "consumer_ok"}, + {"credential" : "admin2:admin2", "name" : "consumer2"}, + {"credential" : "YWRtaW4zOmFkbWluMw==", "name" : "consumer3"}, + {"credential" : "admin:admin", "name" : "consumer"} + ], + "_rules_" : [ + { + "_match_domain_" : ["test.com", "*.example.com"], + "allow" : [ "consumer" ] + } + ] +})"; + + 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())); + + authority_ = "www.example.com:8080"; + cred_ = "admin:admin"; + authorization_header_ = "Basic " + Base64::encode(cred_.data(), cred_.size()); + EXPECT_EQ(context_->onRequestHeaders(0, false), + FilterHeadersStatus::Continue); + + cred_ = "admin2:admin2"; + authorization_header_ = "Basic " + Base64::encode(cred_.data(), cred_.size()); + EXPECT_EQ(context_->onRequestHeaders(0, false), + FilterHeadersStatus::StopIteration); + + authority_ = "abc.com"; + authorization_header_ = "Basic " + Base64::encode(cred_.data(), cred_.size()); + EXPECT_EQ(context_->onRequestHeaders(0, false), + FilterHeadersStatus::Continue); +} + TEST_F(BasicAuthTest, RuleWithEncryptedConsumerAllow) { std::string configuration = R"( { diff --git a/plugins/wasm-go/pkg/matcher/rule_matcher.go b/plugins/wasm-go/pkg/matcher/rule_matcher.go index f1b6c5cf0..ad6d93744 100644 --- a/plugins/wasm-go/pkg/matcher/rule_matcher.go +++ b/plugins/wasm-go/pkg/matcher/rule_matcher.go @@ -109,7 +109,6 @@ func (m *RuleMatcher[PluginConfig]) ParseRuleConfig(config gjson.Result, if keyCount > 0 { err := parsePluginConfig(config, &pluginConfig) if err != nil { - proxywasm.LogWarnf("parse global config failed, err:%v", err) globalConfigError = err } else { m.globalConfig = pluginConfig @@ -185,7 +184,25 @@ func (m RuleMatcher[PluginConfig]) parseHostMatchConfig(config gjson.Result) []H return hostMatchers } +func stripPortFromHost(reqHost string) string { + // Port removing code is inspired by + // https://github.com/envoyproxy/envoy/blob/v1.17.0/source/common/http/header_utility.cc#L219 + portStart := strings.LastIndexByte(reqHost, ':') + if portStart != -1 { + // According to RFC3986 v6 address is always enclosed in "[]". + // section 3.2.2. + v6EndIndex := strings.LastIndexByte(reqHost, ']') + if v6EndIndex == -1 || v6EndIndex < portStart { + if portStart+1 <= len(reqHost) { + return reqHost[:portStart] + } + } + } + return reqHost +} + func (m RuleMatcher[PluginConfig]) hostMatch(rule RuleConfig[PluginConfig], reqHost string) bool { + reqHost = stripPortFromHost(reqHost) for _, hostMatch := range rule.hosts { switch hostMatch.matchType { case Suffix: diff --git a/plugins/wasm-go/pkg/matcher/rule_matcher_test.go b/plugins/wasm-go/pkg/matcher/rule_matcher_test.go index 7d8e70151..a475f441b 100644 --- a/plugins/wasm-go/pkg/matcher/rule_matcher_test.go +++ b/plugins/wasm-go/pkg/matcher/rule_matcher_test.go @@ -118,6 +118,19 @@ func TestHostMatch(t *testing.T) { host: "example.com", result: false, }, + { + name: "exact port", + config: RuleConfig[customConfig]{ + hosts: []HostMatcher{ + { + matchType: Exact, + host: "www.example.com", + }, + }, + }, + host: "www.example.com:8080", + result: true, + }, { name: "any", config: RuleConfig[customConfig]{