Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ Bug Fixes
---------
*Changes expected to improve the state of the world and are unlikely to have negative effects*

* active http health checks: properly handles HTTP/2 GOAWAY frames from the upstream. Previously a GOAWAY frame due to a graceful listener drain could cause improper failed health checks due to streams being refused by the upstream on a connection that is going away. To revert to old GOAWAY handling behavior, set the runtime feature `envoy.reloadable_features.health_check.graceful_goaway_handling` to false.
* buffer: tighten network connection read and write buffer high watermarks in preparation to more careful enforcement of read limits. Buffer high-watermark is now set to the exact configured value; previously it was set to value + 1.
* fault injection: stop counting as active fault after delay elapsed. Previously fault injection filter continues to count the injected delay as an active fault even after it has elapsed. This produces incorrect output statistics and impacts the max number of consecutive faults allowed (e.g., for long-lived streams). This change decreases the active fault count when the delay fault is the only active and has gone finished.
* filter_chain: fix filter chain matching with the server name as the case-insensitive way.
* grpc-web: fix local reply and non-proto-encoded gRPC response handling for small response bodies. This fix can be temporarily reverted by setting `envoy.reloadable_features.grpc_web_fix_non_proto_encoded_response_handling` to false.
* grpc_http_bridge: the downstream HTTP status is now correctly set for trailers-only responses from the upstream.
* http: disallowing "host:" in request_headers_to_add for behavioral consistency with rejecting :authority header. This behavior can be temporarily reverted by setting `envoy.reloadable_features.treat_host_like_authority` to false.
* http: reverting a behavioral change where upstream connect timeouts were temporarily treated differently from other connection failures. The change back to the original behavior can be temporarily reverted by setting `envoy.reloadable_features.treat_upstream_connect_timeout_as_connect_failure` to false.
* jwt_authn: reject requests with a proper error if JWT has the wrong issuer when allow_missing is used. Before this change, the requests are accepted.
* listener: prevent crashing when an unknown listener config proto is received and debug logging is enabled.
* overload: fix a bug that can cause use-after-free when one scaled timer disables another one with the same duration.

Removed Config or Runtime
Expand Down
15 changes: 7 additions & 8 deletions source/extensions/filters/http/jwt_authn/verifier.cc
Original file line number Diff line number Diff line change
Expand Up @@ -301,17 +301,16 @@ class AnyVerifierImpl : public BaseGroupVerifierImpl {
// Then wait for all children to be done.
if (++completion_state.number_completed_children_ == verifiers_.size()) {
// Aggregate all children status into a final status.
// JwtMissing should be treated differently than other failure status
// since it simply means there is not Jwt token for the required provider.
// If there is a failure status other than JwtMissing in the children,
// it should be used as the final status.
// JwtMissed and JwtUnknownIssuer should be treated differently than other errors.
// JwtMissed means not Jwt token for the required provider.
// JwtUnknownIssuer means wrong issuer for the required provider.
Status final_status = Status::JwtMissed;
for (const auto& it : verifiers_) {
// If a Jwt is extracted from a location not specified by the required provider,
// the authenticator returns JwtUnknownIssuer. It should be treated the same as
// JwtMissed.
// Prefer errors which are not JwtMissed nor JwtUnknownIssuer.
// Prefer JwtUnknownIssuer between JwtMissed and JwtUnknownIssuer.
Status child_status = context.getCompletionState(it.get()).status_;
if (child_status != Status::JwtMissed && child_status != Status::JwtUnknownIssuer) {
if ((child_status != Status::JwtMissed && child_status != Status::JwtUnknownIssuer) ||
final_status == Status::JwtMissed) {
final_status = child_status;
}
}
Expand Down
13 changes: 11 additions & 2 deletions test/extensions/filters/http/jwt_authn/all_verifier_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ TEST_F(SingleAllowMissingInOrListTest, BadJwt) {
}

TEST_F(SingleAllowMissingInOrListTest, MissingIssToken) {
EXPECT_CALL(mock_cb_, onComplete(Status::Ok));
EXPECT_CALL(mock_cb_, onComplete(Status::JwtUnknownIssuer));
auto headers = Http::TestRequestHeaderMapImpl{{kExampleHeader, ES256WithoutIssToken}};
context_ = Verifier::createContext(headers, parent_span_, &mock_cb_);
verifier_->verify(context_);
Expand Down Expand Up @@ -471,6 +471,15 @@ TEST_F(AllowMissingInOrListTest, OtherGoodJwt) {
EXPECT_THAT(headers, JwtOutputFailedOrIgnore(kOtherHeader));
}

TEST_F(AllowMissingInOrListTest, WrongIssuer) {
EXPECT_CALL(mock_cb_, onComplete(Status::JwtUnknownIssuer));
auto headers = Http::TestRequestHeaderMapImpl{{kExampleHeader, OtherGoodToken}};
context_ = Verifier::createContext(headers, parent_span_, &mock_cb_);
verifier_->verify(context_);
// x-other JWT should be ignored.
EXPECT_THAT(headers, JwtOutputFailedOrIgnore(kOtherHeader));
}

TEST_F(AllowMissingInOrListTest, BadAndGoodJwts) {
EXPECT_CALL(mock_cb_, onComplete(Status::JwtVerificationFail));
auto headers = Http::TestRequestHeaderMapImpl{{kExampleHeader, NonExistKidToken},
Expand Down Expand Up @@ -589,7 +598,7 @@ TEST_F(AllowMissingInAndOfOrListTest, TwoGoodJwts) {
}

TEST_F(AllowMissingInAndOfOrListTest, GoodAndBadJwts) {
EXPECT_CALL(mock_cb_, onComplete(Status::Ok));
EXPECT_CALL(mock_cb_, onComplete(Status::JwtUnknownIssuer));
// Use the token with example.com issuer for x-other.
auto headers =
Http::TestRequestHeaderMapImpl{{kExampleHeader, GoodToken}, {kOtherHeader, GoodToken}};
Expand Down
6 changes: 3 additions & 3 deletions test/extensions/filters/http/jwt_authn/group_verifier_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -582,8 +582,8 @@ TEST_F(GroupVerifierTest, TestRequiresAnyWithAllowMissingButFailed) {
callbacks_["other_provider"](Status::JwtExpired);
}

// Test RequiresAny with two providers and allow_missing, but OK
TEST_F(GroupVerifierTest, TestRequiresAnyWithAllowMissingButOk) {
// Test RequiresAny with two providers and allow_missing, but one returns JwtUnknownIssuer
TEST_F(GroupVerifierTest, TestRequiresAnyWithAllowMissingButUnknownIssuer) {
TestUtility::loadFromYaml(RequiresAnyConfig, proto_config_);
proto_config_.mutable_rules(0)
->mutable_requires()
Expand All @@ -592,7 +592,7 @@ TEST_F(GroupVerifierTest, TestRequiresAnyWithAllowMissingButOk) {
->mutable_allow_missing();

createAsyncMockAuthsAndVerifier(std::vector<std::string>{"example_provider", "other_provider"});
EXPECT_CALL(mock_cb_, onComplete(Status::Ok));
EXPECT_CALL(mock_cb_, onComplete(Status::JwtUnknownIssuer));

auto headers = Http::TestRequestHeaderMapImpl{};
context_ = Verifier::createContext(headers, parent_span_, &mock_cb_);
Expand Down