From ca9d200ef79f13748768ea0295db8980515cf86d Mon Sep 17 00:00:00 2001 From: Antonio Leonti Date: Mon, 1 Apr 2024 16:51:29 +0000 Subject: [PATCH 1/2] add authz response to ext_authz fuzzer input Signed-off-by: Antonio Leonti --- test/extensions/filters/http/ext_authz/BUILD | 6 +- .../ext_authz/ext_authz_corpus/bad_config | 34 -------- .../ext_authz/ext_authz_corpus/custom_status | 22 ----- .../ext_authz_corpus/error_fail_close | 29 ------- .../http/ext_authz/ext_authz_corpus/example | 7 -- .../ext_authz_corpus/metadata_context | 84 ------------------ .../ext_authz_corpus/no_regex_engine | 21 ----- .../ext_authz/ext_authz_corpus/request_data | 33 ------- .../http/ext_authz/ext_authz_fuzz.proto | 37 +++++--- .../http/ext_authz/ext_authz_fuzz_lib.cc | 8 +- .../http/ext_authz/ext_authz_fuzz_lib.h | 2 +- .../ext_authz_grpc_corpus/bad_config | 35 ++++++++ .../ext_authz_grpc_corpus/custom_status | 24 ++++++ .../ext_authz_grpc_corpus/denied_response | 49 +++++++++++ .../ext_authz_grpc_corpus/error_fail_close | 31 +++++++ .../ext_authz/ext_authz_grpc_corpus/example | 10 +++ .../invalid_headers_to_remove | 11 +++ .../invalid_query_parameters_to_set | 35 ++++++++ .../ext_authz_grpc_corpus/metadata_context | 85 +++++++++++++++++++ .../ext_authz_grpc_corpus/no_regex_engine | 23 +++++ .../ext_authz_grpc_corpus/ok_response | 59 +++++++++++++ .../ext_authz_grpc_corpus/request_data | 35 ++++++++ .../ext_authz/ext_authz_grpc_fuzz_test.cc | 84 +++++++++--------- .../ext_authz_http_corpus/bad_config | 35 ++++++++ .../ext_authz_http_corpus/custom_status | 24 ++++++ .../ext_authz_http_corpus/denied_response | 31 +++++++ .../ext_authz_http_corpus/error_fail_close | 31 +++++++ .../ext_authz/ext_authz_http_corpus/example | 9 ++ .../ext_authz_http_corpus/metadata_context | 85 +++++++++++++++++++ .../ext_authz_http_corpus/no_regex_engine | 23 +++++ .../ext_authz_http_corpus/ok_response | 31 +++++++ .../ext_authz_http_corpus/request_data | 35 ++++++++ .../ext_authz/ext_authz_http_fuzz_test.cc | 29 +++++-- 33 files changed, 794 insertions(+), 303 deletions(-) delete mode 100644 test/extensions/filters/http/ext_authz/ext_authz_corpus/bad_config delete mode 100644 test/extensions/filters/http/ext_authz/ext_authz_corpus/custom_status delete mode 100644 test/extensions/filters/http/ext_authz/ext_authz_corpus/error_fail_close delete mode 100644 test/extensions/filters/http/ext_authz/ext_authz_corpus/example delete mode 100644 test/extensions/filters/http/ext_authz/ext_authz_corpus/metadata_context delete mode 100644 test/extensions/filters/http/ext_authz/ext_authz_corpus/no_regex_engine delete mode 100644 test/extensions/filters/http/ext_authz/ext_authz_corpus/request_data create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/bad_config create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/custom_status create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/denied_response create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/error_fail_close create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/example create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/invalid_headers_to_remove create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/invalid_query_parameters_to_set create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/metadata_context create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/no_regex_engine create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/ok_response create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/request_data create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_http_corpus/bad_config create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_http_corpus/custom_status create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_http_corpus/denied_response create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_http_corpus/error_fail_close create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_http_corpus/example create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_http_corpus/metadata_context create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_http_corpus/no_regex_engine create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_http_corpus/ok_response create mode 100644 test/extensions/filters/http/ext_authz/ext_authz_http_corpus/request_data diff --git a/test/extensions/filters/http/ext_authz/BUILD b/test/extensions/filters/http/ext_authz/BUILD index e216f5f6d63f..a282dc215474 100644 --- a/test/extensions/filters/http/ext_authz/BUILD +++ b/test/extensions/filters/http/ext_authz/BUILD @@ -95,13 +95,14 @@ envoy_proto_library( "//test/fuzz:common_proto", "@envoy_api//envoy/config/core/v3:pkg", "@envoy_api//envoy/extensions/filters/http/ext_authz/v3:pkg", + "@envoy_api//envoy/service/auth/v3:pkg", ], ) envoy_cc_fuzz_test( name = "ext_authz_grpc_fuzz_test", srcs = ["ext_authz_grpc_fuzz_test.cc"], - corpus = "ext_authz_corpus", + corpus = "ext_authz_grpc_corpus", deps = [ ":ext_authz_fuzz_lib", ":ext_authz_fuzz_proto_cc_proto", @@ -110,6 +111,7 @@ envoy_cc_fuzz_test( "//test/extensions/filters/common/ext_authz:ext_authz_test_common", "//test/extensions/filters/http/common/fuzz:http_filter_fuzzer_lib", "//test/mocks/grpc:grpc_mocks", + "@envoy_api//envoy/extensions/filters/http/ext_authz/v3:pkg_cc_proto", "@envoy_api//envoy/service/auth/v3:pkg_cc_proto", ], ) @@ -117,7 +119,7 @@ envoy_cc_fuzz_test( envoy_cc_fuzz_test( name = "ext_authz_http_fuzz_test", srcs = ["ext_authz_http_fuzz_test.cc"], - corpus = "ext_authz_corpus", + corpus = "ext_authz_http_corpus", deps = [ ":ext_authz_fuzz_lib", ":ext_authz_fuzz_proto_cc_proto", diff --git a/test/extensions/filters/http/ext_authz/ext_authz_corpus/bad_config b/test/extensions/filters/http/ext_authz/ext_authz_corpus/bad_config deleted file mode 100644 index c4cf684b3521..000000000000 --- a/test/extensions/filters/http/ext_authz/ext_authz_corpus/bad_config +++ /dev/null @@ -1,34 +0,0 @@ -config { - status_on_error { - code: Continue - } - metadata_context_namespaces: "=" - stat_prefix: "r" - filter_enabled_metadata { - filter: "\177\177\177\177\177\177\177\177" - path { - key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - } - value { - string_match { - safe_regex { - google_re2 { - } - regex: "z" - } - ignore_case: true - } - } - } - bootstrap_metadata_labels_key: "r" -} -request_data { -} -filter_metadata { - typed_filter_metadata { - key: ":=" - value { - } - } -} - diff --git a/test/extensions/filters/http/ext_authz/ext_authz_corpus/custom_status b/test/extensions/filters/http/ext_authz/ext_authz_corpus/custom_status deleted file mode 100644 index 6a9192e46ab3..000000000000 --- a/test/extensions/filters/http/ext_authz/ext_authz_corpus/custom_status +++ /dev/null @@ -1,22 +0,0 @@ -config { - grpc_service { - envoy_grpc { - cluster_name: "ext_authz_server" - } - } - status_on_error { - code: ServiceUnavilable - } -} -request_data { - headers { - headers { - key: ":host" - value: "example.com" - } - headers { - key: ":method" - value: "GET" - } - } -} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_corpus/error_fail_close b/test/extensions/filters/http/ext_authz/ext_authz_corpus/error_fail_close deleted file mode 100644 index 82d08abfa9cb..000000000000 --- a/test/extensions/filters/http/ext_authz/ext_authz_corpus/error_fail_close +++ /dev/null @@ -1,29 +0,0 @@ -config { - grpc_service { - envoy_grpc { - cluster_name: "ext_authz_server" - } - } - stat_prefix: "with_stat_prefix" -} -request_data { - headers { - headers { - key: ":host" - value: "example.com" - } - headers { - key: ":method" - value: "GET" - } - headers { - key: ":path" - value: "/users" - } - headers { - key: ":scheme" - value: "https" - } - } -} -result: ERROR diff --git a/test/extensions/filters/http/ext_authz/ext_authz_corpus/example b/test/extensions/filters/http/ext_authz/ext_authz_corpus/example deleted file mode 100644 index 48b7bf01c193..000000000000 --- a/test/extensions/filters/http/ext_authz/ext_authz_corpus/example +++ /dev/null @@ -1,7 +0,0 @@ -config { -} -request_data { - - -} -result: ERROR diff --git a/test/extensions/filters/http/ext_authz/ext_authz_corpus/metadata_context b/test/extensions/filters/http/ext_authz/ext_authz_corpus/metadata_context deleted file mode 100644 index 403ad1070239..000000000000 --- a/test/extensions/filters/http/ext_authz/ext_authz_corpus/metadata_context +++ /dev/null @@ -1,84 +0,0 @@ -config { - grpc_service { - envoy_grpc { - cluster_name: "ext_authz_server" - } - } - metadata_context_namespaces: "jazz.sax" - metadata_context_namespaces: "rock.guitar" - metadata_context_namespaces: "hiphop.drums" -} -filter_metadata { -filter_metadata { - key: "jazz.piano" - value { - fields { - key: "hancock" - value { - string_value: "herbie" - } - } - fields { - key: "monk" - value { - string_value: "thelonious" - } - } - } -} -filter_metadata { - key: "jazz.sax" - value { - fields { - key: "coltrane" - value { - string_value: "john" - } - } - fields { - key: "parker" - value { - string_value: "charlie" - } - } - } -} -filter_metadata { - key: "rock.guitar" - value { - fields { - key: "hendrix" - value { - string_value: "jimi" - } - } - fields { - key: "richards" - value { - string_value: "keith" - } - } - } -} -} -result: OK -request_data { - headers { - headers { - key: ":host" - value: "example.com" - } - headers { - key: ":method" - value: "GET" - } - headers { - key: ":path" - value: "/users" - } - headers { - key: ":scheme" - value: "https" - } - } -} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_corpus/no_regex_engine b/test/extensions/filters/http/ext_authz/ext_authz_corpus/no_regex_engine deleted file mode 100644 index d6953254b178..000000000000 --- a/test/extensions/filters/http/ext_authz/ext_authz_corpus/no_regex_engine +++ /dev/null @@ -1,21 +0,0 @@ -config { - clear_route_cache: true - include_peer_certificate: true - stat_prefix: "C" - filter_enabled_metadata { - filter: ";" - path { - key: "V" - } - value { - string_match { - safe_regex { - regex: "/envoy.config.route.v3.Route" - } - } - } - } - bootstrap_metadata_labels_key: "\000\000\000\000\000\000\000\000\000\000\000\000\000" -} -request_data { -} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_corpus/request_data b/test/extensions/filters/http/ext_authz/ext_authz_corpus/request_data deleted file mode 100644 index e578bd966943..000000000000 --- a/test/extensions/filters/http/ext_authz/ext_authz_corpus/request_data +++ /dev/null @@ -1,33 +0,0 @@ -config { - grpc_service { - envoy_grpc { - cluster_name: "ext_authz_server" - } - } - with_request_body { - max_request_bytes: 10 - } -} -request_data { - headers { - headers { - key: ":host" - value: "example.com" - } - headers { - key: ":method" - value: "GET" - } - headers { - key: ":path" - value: "/users" - } - headers { - key: ":scheme" - value: "https" - } - } - http_body { - data: "foobarbaz" - } -} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_fuzz.proto b/test/extensions/filters/http/ext_authz/ext_authz_fuzz.proto index 3f32b9afad1e..ef05bb1c8731 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_fuzz.proto +++ b/test/extensions/filters/http/ext_authz/ext_authz_fuzz.proto @@ -1,13 +1,37 @@ syntax = "proto3"; package envoy.extensions.filters.http.ext_authz; +import "envoy/config/core/v3/base.proto"; import "envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto"; +import "envoy/service/auth/v3/external_auth.proto"; import "test/fuzz/common.proto"; -import "envoy/config/core/v3/base.proto"; import "validate/validate.proto"; // We only fuzz a single request per iteration. -message ExtAuthzTestCase { +message ExtAuthzTestCaseBase { + envoy.extensions.filters.http.ext_authz.v3.ExtAuthz config = 1 + [(validate.rules).message = {required: true}]; + // HTTP request data. + test.fuzz.HttpData request_data = 2 [(validate.rules).message = {required: true}]; + // Filter metadata. + envoy.config.core.v3.Metadata filter_metadata = 4; +} + +message ExtAuthzTestCaseGrpc { + ExtAuthzTestCaseBase base = 1 [(validate.rules).message = {required: true}]; + + oneof response_or_failure_reason { + // Full auth check result. Note it is not validated to simulate an untrusted authz server (i.e. + // it can contain garbage mutations). + envoy.service.auth.v3.CheckResponse response = 2 [(validate.rules).message.skip = true]; + // If this is set onFailure will be called instead of onSuccess. + string failure_reason = 3; + } +} + +message ExtAuthzTestCaseHttp { + ExtAuthzTestCaseBase base = 1 [(validate.rules).message = {required: true}]; + enum AuthResult { // Possible results for a check call. Taken from // https://github.com/envoyproxy/envoy/blob/945b5833f094dee31d2971cee8d40553bb0fe714/source/extensions/filters/common/ext_authz/ext_authz.h#L65 @@ -15,15 +39,6 @@ message ExtAuthzTestCase { DENIED = 1; ERROR = 2; } - - envoy.extensions.filters.http.ext_authz.v3.ExtAuthz config = 1 - [(validate.rules).message = {required: true}]; - // HTTP request data. - test.fuzz.HttpData request_data = 2 [(validate.rules).message = {required: true}]; // Set default auth check result. AuthResult result = 3 [(validate.rules).enum.defined_only = true]; - // Filter metadata. - envoy.config.core.v3.Metadata filter_metadata = 4; - // TODO: Add headers and data to ExtAuthz::Response and check that the request headers and data - // were updated. } diff --git a/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.cc b/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.cc index 4568ac600e4c..0e3cc06cf890 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.cc @@ -43,14 +43,8 @@ ReusableFilterFactory::newFilter(FilterConfigSharedPtr config, } absl::StatusOr> ReusableFuzzerUtil::setup( - const envoy::extensions::filters::http::ext_authz::ExtAuthzTestCase& input, + const envoy::extensions::filters::http::ext_authz::ExtAuthzTestCaseBase& input, Filters::Common::ExtAuthz::ClientPtr client) { - try { - TestUtility::validate(input); - } catch (const EnvoyException& e) { - ENVOY_LOG_MISC(debug, "EnvoyException during validation: {}", e.what()); - return absl::InvalidArgumentError(absl::StrCat("EnvoyException during validation: ", e.what())); - } // Prepare filter. const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz proto_config = input.config(); diff --git a/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.h b/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.h index 1fc346df16e1..1aa876843347 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.h +++ b/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.h @@ -43,7 +43,7 @@ class ReusableFuzzerUtil { public: // Validate input, then create a filter using the input.config() & the provided client. absl::StatusOr> - setup(const envoy::extensions::filters::http::ext_authz::ExtAuthzTestCase& input, + setup(const envoy::extensions::filters::http::ext_authz::ExtAuthzTestCaseBase& input, Filters::Common::ExtAuthz::ClientPtr client); private: diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/bad_config b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/bad_config new file mode 100644 index 000000000000..fe2875d5c4a1 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/bad_config @@ -0,0 +1,35 @@ +base { + config { + status_on_error { + code: Continue + } + metadata_context_namespaces: "=" + stat_prefix: "r" + filter_enabled_metadata { + filter: "\177\177\177\177\177\177\177\177" + path { + key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + value { + string_match { + safe_regex { + google_re2 { + } + regex: "z" + } + ignore_case: true + } + } + } + bootstrap_metadata_labels_key: "r" + } + request_data { + } + filter_metadata { + typed_filter_metadata { + key: ":=" + value { + } + } + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/custom_status b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/custom_status new file mode 100644 index 000000000000..8a78a99a1395 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/custom_status @@ -0,0 +1,24 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + status_on_error { + code: ServiceUnavilable + } + } + request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + } + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/denied_response b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/denied_response new file mode 100644 index 000000000000..8cb3cda0e2d4 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/denied_response @@ -0,0 +1,49 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + stat_prefix: "with_stat_prefix" + } + request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + headers { + key: ":path" + value: "/users" + } + headers { + key: ":scheme" + value: "https" + } + } + } +} +response { + status { + code: 7 + message: "PERMISSION DENIED" + } + denied_response { + status { + code: Forbidden + } + headers { + header { + key: "added-upstream-request-header" + value: "this should be added by ext_authz to the upstream request!" + } + append_action: APPEND_IF_EXISTS_OR_ADD + } + body: "this is the response body" + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/error_fail_close b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/error_fail_close new file mode 100644 index 000000000000..f6ecf0006c86 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/error_fail_close @@ -0,0 +1,31 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + stat_prefix: "with_stat_prefix" + } + request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + headers { + key: ":path" + value: "/users" + } + headers { + key: ":scheme" + value: "https" + } + } + } +} +failure_reason: "this will trigger onFailure!" diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/example b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/example new file mode 100644 index 000000000000..edfafb97436f --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/example @@ -0,0 +1,10 @@ +base { + config { + } + request_data { + + + } +} +response { +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/invalid_headers_to_remove b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/invalid_headers_to_remove new file mode 100644 index 000000000000..de00cab63c9f --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/invalid_headers_to_remove @@ -0,0 +1,11 @@ +base { + config { + } + request_data { + } +} +response { + ok_response { + headers_to_remove: "*\000\000\000\000\000\000\000" + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/invalid_query_parameters_to_set b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/invalid_query_parameters_to_set new file mode 100644 index 000000000000..811aa67cd858 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/invalid_query_parameters_to_set @@ -0,0 +1,35 @@ +base { + config { + } + request_data { + } +} +response { + ok_response { + query_parameters_to_set { + } + query_parameters_to_set { + key: " " + } + query_parameters_to_set { + value: " " + } + query_parameters_to_set { + key: "???" + value: "&&&&" + } + query_parameters_to_set { + key: "\005\000" + value: "blah blah" + } + + query_parameters_to_set { + key: "no more query params!" + value: "#" + } + query_parameters_to_set { + key: "test" + value: "testval" + } + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/metadata_context b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/metadata_context new file mode 100644 index 000000000000..b09d8aa248de --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/metadata_context @@ -0,0 +1,85 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + metadata_context_namespaces: "jazz.sax" + metadata_context_namespaces: "rock.guitar" + metadata_context_namespaces: "hiphop.drums" + } + filter_metadata { + filter_metadata { + key: "jazz.piano" + value { + fields { + key: "hancock" + value { + string_value: "herbie" + } + } + fields { + key: "monk" + value { + string_value: "thelonious" + } + } + } + } + filter_metadata { + key: "jazz.sax" + value { + fields { + key: "coltrane" + value { + string_value: "john" + } + } + fields { + key: "parker" + value { + string_value: "charlie" + } + } + } + } + filter_metadata { + key: "rock.guitar" + value { + fields { + key: "hendrix" + value { + string_value: "jimi" + } + } + fields { + key: "richards" + value { + string_value: "keith" + } + } + } + } + } +} +request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + headers { + key: ":path" + value: "/users" + } + headers { + key: ":scheme" + value: "https" + } + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/no_regex_engine b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/no_regex_engine new file mode 100644 index 000000000000..f51597e40ac5 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/no_regex_engine @@ -0,0 +1,23 @@ +base { + config { + clear_route_cache: true + include_peer_certificate: true + stat_prefix: "C" + filter_enabled_metadata { + filter: ";" + path { + key: "V" + } + value { + string_match { + safe_regex { + regex: "/envoy.config.route.v3.Route" + } + } + } + } + bootstrap_metadata_labels_key: "\000\000\000\000\000\000\000\000\000\000\000\000\000" + } +} +request_data { +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/ok_response b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/ok_response new file mode 100644 index 000000000000..dacc95dbc1ce --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/ok_response @@ -0,0 +1,59 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + stat_prefix: "with_stat_prefix" + } + request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + headers { + key: ":path" + value: "/users" + } + headers { + key: ":scheme" + value: "https" + } + } + } +} +response { + status { + code: 0 + message: "LGTM!" + } + ok_response { + headers { + header { + key: "added-upstream-request-header" + value: "this should be added by ext_authz to the upstream request!" + } + append_action: APPEND_IF_EXISTS_OR_ADD + } + headers_to_remove: "blah" + headers_to_remove: "bleh" + response_headers_to_add { + header { + key: "added-downstream-response-header" + value: "this should be added by ext_authz to the downstream response!" + } + append_action: APPEND_IF_EXISTS_OR_ADD + } + query_parameters_to_set { + key: "new-query-param-key" + value: "query param value" + } + query_parameters_to_remove: "query-param-key-remove-me" + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/request_data b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/request_data new file mode 100644 index 000000000000..21b1204f5adf --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_corpus/request_data @@ -0,0 +1,35 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + with_request_body { + max_request_bytes: 10 + } + } + request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + headers { + key: ":path" + value: "/users" + } + headers { + key: ":scheme" + value: "https" + } + } + http_body { + data: "foobarbaz" + } + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_grpc_fuzz_test.cc b/test/extensions/filters/http/ext_authz/ext_authz_grpc_fuzz_test.cc index 300e093f402c..8af3534d9b2b 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_grpc_fuzz_test.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_grpc_fuzz_test.cc @@ -1,12 +1,17 @@ +#include + +#include "envoy/extensions/filters/http/ext_authz/v3/ext_authz.pb.validate.h" #include "envoy/grpc/status.h" #include "envoy/service/auth/v3/external_auth.pb.h" #include "source/common/common/assert.h" -#include "source/extensions/filters/common/ext_authz/ext_authz_http_impl.h" +#include "source/extensions/filters/common/ext_authz/ext_authz_grpc_impl.h" +#include "source/extensions/filters/http/ext_authz/ext_authz.h" #include "test/extensions/filters/common/ext_authz/test_common.h" #include "test/extensions/filters/http/common/fuzz/http_filter_fuzzer.h" #include "test/extensions/filters/http/ext_authz/ext_authz_fuzz.pb.h" +#include "test/extensions/filters/http/ext_authz/ext_authz_fuzz.pb.validate.h" #include "test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.h" #include "test/fuzz/fuzz_runner.h" #include "test/mocks/grpc/mocks.h" @@ -14,8 +19,7 @@ #include "gmock/gmock.h" using Envoy::Extensions::Filters::Common::ExtAuthz::TestCommon; -using envoy::extensions::filters::http::ext_authz::ExtAuthzTestCase; -using testing::Return; +using envoy::extensions::filters::http::ext_authz::ExtAuthzTestCaseGrpc; namespace Envoy { namespace Extensions { @@ -23,29 +27,6 @@ namespace HttpFilters { namespace ExtAuthz { namespace { -std::unique_ptr -makeGrpcCheckResponse(const Grpc::Status::WellKnownGrpcStatus status) { - auto response = std::make_unique(); - response->mutable_status()->set_code(status); - // TODO: We only add the response status. - // Add fuzzed inputs for headers_to_(set/append/add), body, status_code to the Response. - return response; -} - -Grpc::Status::WellKnownGrpcStatus -resultCaseToGrpcStatus(const ExtAuthzTestCase::AuthResult result) { - switch (result) { - PANIC_ON_PROTO_ENUM_SENTINEL_VALUES; - case ExtAuthzTestCase::OK: - return Grpc::Status::WellKnownGrpcStatus::Ok; - case ExtAuthzTestCase::ERROR: - return Grpc::Status::WellKnownGrpcStatus::Internal; - case ExtAuthzTestCase::DENIED: - return Grpc::Status::WellKnownGrpcStatus::PermissionDenied; - } - PANIC_DUE_TO_CORRUPT_ENUM; -} - class ReusableGrpcClientFactory { public: ReusableGrpcClientFactory() @@ -59,25 +40,31 @@ class ReusableGrpcClientFactory { EXPECT_TRUE(check_request.ParseFromString(serialized_req->toString())) << "Could not parse serialized check request"; - // TODO: Query the request header map in HttpFilterFuzzer to test - // headers_to_(add/remove/append). - // TODO: Test check request attributes against config - // and filter metadata. - ENVOY_LOG_MISC(trace, "Check Request attributes {}", + ENVOY_LOG_MISC(trace, "Check Request attributes:\n{}", check_request.attributes().DebugString()); - if (status_ == Grpc::Status::WellKnownGrpcStatus::Ok) { - grpc_client_->onSuccess(makeGrpcCheckResponse(status_), mock_span_); + if (failure_reason_) { + grpc_client_->onFailure(Envoy::Grpc::Status::WellKnownGrpcStatus::Unknown, + *failure_reason_, mock_span_); } else { - grpc_client_->onFailure(status_, "Fuzz input status was not ok!", mock_span_); + grpc_client_->onSuccess(std::move(response_), mock_span_); } return &grpc_async_request_; })); } std::unique_ptr - newGrpcClientImpl(const ExtAuthzTestCase::AuthResult result) { - status_ = resultCaseToGrpcStatus(result); + newGrpcClientImpl(const ExtAuthzTestCaseGrpc& input) { + if (input.has_failure_reason()) { + failure_reason_ = input.failure_reason(); + response_ = nullptr; + ENVOY_LOG_MISC(trace, "Failure reason: {}", *failure_reason_); + } else { + failure_reason_ = std::nullopt; + response_ = std::make_unique(input.response()); + ENVOY_LOG_MISC(trace, "Check Response:\n{}", response_->DebugString()); + } + grpc_client_ = new Filters::Common::ExtAuthz::GrpcClientImpl(internal_grpc_mock_client_, std::chrono::milliseconds(1000)); return std::unique_ptr{grpc_client_}; @@ -88,24 +75,35 @@ class ReusableGrpcClientFactory { Envoy::Tracing::MockSpan mock_span_; NiceMock grpc_async_request_; - // Set by calling newGrpcClientImpl - Grpc::Status::WellKnownGrpcStatus status_; + // Set by calling newGrpcClientImpl. Only one of response_ or failure_reason_ will be set. + std::unique_ptr response_; + absl::optional failure_reason_; Filters::Common::ExtAuthz::GrpcClientImpl* grpc_client_; }; -DEFINE_PROTO_FUZZER(const ExtAuthzTestCase& input) { +DEFINE_PROTO_FUZZER(ExtAuthzTestCaseGrpc& input) { static ReusableFuzzerUtil fuzzer_util; static ReusableGrpcClientFactory grpc_client_factory; - auto grpc_client = grpc_client_factory.newGrpcClientImpl(input.result()); - absl::StatusOr> filter = fuzzer_util.setup(input, std::move(grpc_client)); + + try { + TestUtility::validate(input); + } catch (const EnvoyException& e) { + ENVOY_LOG_MISC(debug, "EnvoyException during validation: {}", e.what()); + return; + } + + auto grpc_client = grpc_client_factory.newGrpcClientImpl(input); + // Force this to be true so that the filter can handle invalid mutations gracefully. + input.mutable_base()->mutable_config()->set_validate_mutations(true); + absl::StatusOr> filter = + fuzzer_util.setup(input.base(), std::move(grpc_client)); if (!filter.ok()) { return; } - // TODO: Add response headers. static Envoy::Extensions::HttpFilters::HttpFilterFuzzer fuzzer; fuzzer.runData(static_cast(filter->get()), - input.request_data()); + input.base().request_data()); } } // namespace diff --git a/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/bad_config b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/bad_config new file mode 100644 index 000000000000..fe2875d5c4a1 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/bad_config @@ -0,0 +1,35 @@ +base { + config { + status_on_error { + code: Continue + } + metadata_context_namespaces: "=" + stat_prefix: "r" + filter_enabled_metadata { + filter: "\177\177\177\177\177\177\177\177" + path { + key: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + value { + string_match { + safe_regex { + google_re2 { + } + regex: "z" + } + ignore_case: true + } + } + } + bootstrap_metadata_labels_key: "r" + } + request_data { + } + filter_metadata { + typed_filter_metadata { + key: ":=" + value { + } + } + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/custom_status b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/custom_status new file mode 100644 index 000000000000..8a78a99a1395 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/custom_status @@ -0,0 +1,24 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + status_on_error { + code: ServiceUnavilable + } + } + request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + } + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/denied_response b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/denied_response new file mode 100644 index 000000000000..9a887d459c36 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/denied_response @@ -0,0 +1,31 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + stat_prefix: "with_stat_prefix" + } + request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + headers { + key: ":path" + value: "/users" + } + headers { + key: ":scheme" + value: "https" + } + } + } +} +result: DENIED diff --git a/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/error_fail_close b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/error_fail_close new file mode 100644 index 000000000000..07e50ec30093 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/error_fail_close @@ -0,0 +1,31 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + stat_prefix: "with_stat_prefix" + } + request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + headers { + key: ":path" + value: "/users" + } + headers { + key: ":scheme" + value: "https" + } + } + } +} +result: ERROR diff --git a/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/example b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/example new file mode 100644 index 000000000000..b4ae79db12b0 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/example @@ -0,0 +1,9 @@ +base { + config { + } + request_data { + + + } +} +result: ERROR diff --git a/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/metadata_context b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/metadata_context new file mode 100644 index 000000000000..b09d8aa248de --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/metadata_context @@ -0,0 +1,85 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + metadata_context_namespaces: "jazz.sax" + metadata_context_namespaces: "rock.guitar" + metadata_context_namespaces: "hiphop.drums" + } + filter_metadata { + filter_metadata { + key: "jazz.piano" + value { + fields { + key: "hancock" + value { + string_value: "herbie" + } + } + fields { + key: "monk" + value { + string_value: "thelonious" + } + } + } + } + filter_metadata { + key: "jazz.sax" + value { + fields { + key: "coltrane" + value { + string_value: "john" + } + } + fields { + key: "parker" + value { + string_value: "charlie" + } + } + } + } + filter_metadata { + key: "rock.guitar" + value { + fields { + key: "hendrix" + value { + string_value: "jimi" + } + } + fields { + key: "richards" + value { + string_value: "keith" + } + } + } + } + } +} +request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + headers { + key: ":path" + value: "/users" + } + headers { + key: ":scheme" + value: "https" + } + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/no_regex_engine b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/no_regex_engine new file mode 100644 index 000000000000..f51597e40ac5 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/no_regex_engine @@ -0,0 +1,23 @@ +base { + config { + clear_route_cache: true + include_peer_certificate: true + stat_prefix: "C" + filter_enabled_metadata { + filter: ";" + path { + key: "V" + } + value { + string_match { + safe_regex { + regex: "/envoy.config.route.v3.Route" + } + } + } + } + bootstrap_metadata_labels_key: "\000\000\000\000\000\000\000\000\000\000\000\000\000" + } +} +request_data { +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/ok_response b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/ok_response new file mode 100644 index 000000000000..de04802385a6 --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/ok_response @@ -0,0 +1,31 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + stat_prefix: "with_stat_prefix" + } + request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + headers { + key: ":path" + value: "/users" + } + headers { + key: ":scheme" + value: "https" + } + } + } +} +result: OK diff --git a/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/request_data b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/request_data new file mode 100644 index 000000000000..21b1204f5adf --- /dev/null +++ b/test/extensions/filters/http/ext_authz/ext_authz_http_corpus/request_data @@ -0,0 +1,35 @@ +base { + config { + grpc_service { + envoy_grpc { + cluster_name: "ext_authz_server" + } + } + with_request_body { + max_request_bytes: 10 + } + } + request_data { + headers { + headers { + key: ":host" + value: "example.com" + } + headers { + key: ":method" + value: "GET" + } + headers { + key: ":path" + value: "/users" + } + headers { + key: ":scheme" + value: "https" + } + } + http_body { + data: "foobarbaz" + } + } +} diff --git a/test/extensions/filters/http/ext_authz/ext_authz_http_fuzz_test.cc b/test/extensions/filters/http/ext_authz/ext_authz_http_fuzz_test.cc index 3a881cfca27c..4b4309b7452d 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_http_fuzz_test.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_http_fuzz_test.cc @@ -1,6 +1,7 @@ #include #include +#include "envoy/extensions/filters/http/ext_authz/v3/ext_authz.pb.validate.h" #include "envoy/service/auth/v3/external_auth.pb.h" #include "source/common/common/assert.h" @@ -9,6 +10,7 @@ #include "test/extensions/filters/common/ext_authz/test_common.h" #include "test/extensions/filters/http/common/fuzz/http_filter_fuzzer.h" #include "test/extensions/filters/http/ext_authz/ext_authz_fuzz.pb.h" +#include "test/extensions/filters/http/ext_authz/ext_authz_fuzz.pb.validate.h" #include "test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.h" #include "test/fuzz/fuzz_runner.h" #include "test/mocks/server/server_factory_context.h" @@ -17,7 +19,7 @@ #include "gmock/gmock.h" using Envoy::Extensions::Filters::Common::ExtAuthz::TestCommon; -using envoy::extensions::filters::http::ext_authz::ExtAuthzTestCase; +using envoy::extensions::filters::http::ext_authz::ExtAuthzTestCaseHttp; namespace Envoy { namespace Extensions { @@ -25,14 +27,14 @@ namespace HttpFilters { namespace ExtAuthz { namespace { -std::string resultCaseToHttpStatus(const ExtAuthzTestCase::AuthResult result) { +std::string resultCaseToHttpStatus(const ExtAuthzTestCaseHttp::AuthResult result) { switch (result) { PANIC_ON_PROTO_ENUM_SENTINEL_VALUES; - case ExtAuthzTestCase::OK: + case ExtAuthzTestCaseHttp::OK: return "200"; - case ExtAuthzTestCase::ERROR: + case ExtAuthzTestCaseHttp::ERROR: return "500"; - case ExtAuthzTestCase::DENIED: + case ExtAuthzTestCaseHttp::DENIED: return "403"; } PANIC_DUE_TO_CORRUPT_ENUM; @@ -60,7 +62,7 @@ class ReusableHttpClientFactory { } std::unique_ptr - newRawHttpClientImpl(const ExtAuthzTestCase::AuthResult result) { + newRawHttpClientImpl(const ExtAuthzTestCaseHttp::AuthResult result) { http_client_ = new Filters::Common::ExtAuthz::RawHttpClientImpl(cm_, createConfig()); status_ = resultCaseToHttpStatus(result); return std::unique_ptr(http_client_); @@ -121,11 +123,20 @@ class ReusableHttpClientFactory { Filters::Common::ExtAuthz::RawHttpClientImpl* http_client_; }; -DEFINE_PROTO_FUZZER(const ExtAuthzTestCase& input) { +DEFINE_PROTO_FUZZER(const ExtAuthzTestCaseHttp& input) { static ReusableFuzzerUtil fuzzer_util; static ReusableHttpClientFactory http_client_factory; + + try { + TestUtility::validate(input); + } catch (const EnvoyException& e) { + ENVOY_LOG_MISC(debug, "EnvoyException during validation: {}", e.what()); + return; + } + auto http_client = http_client_factory.newRawHttpClientImpl(input.result()); - absl::StatusOr> filter = fuzzer_util.setup(input, std::move(http_client)); + absl::StatusOr> filter = + fuzzer_util.setup(input.base(), std::move(http_client)); if (!filter.ok()) { return; } @@ -133,7 +144,7 @@ DEFINE_PROTO_FUZZER(const ExtAuthzTestCase& input) { // TODO: Add response headers. static Envoy::Extensions::HttpFilters::HttpFilterFuzzer fuzzer; fuzzer.runData(static_cast(filter->get()), - input.request_data()); + input.base().request_data()); } } // namespace From c22ec28678f97bd2a9101eb198478988bedfa32f Mon Sep 17 00:00:00 2001 From: antoniovleonti Date: Thu, 9 May 2024 14:34:29 +0000 Subject: [PATCH 2/2] fix dependencies Signed-off-by: antoniovleonti --- test/extensions/filters/http/ext_authz/BUILD | 2 +- test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.cc | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/test/extensions/filters/http/ext_authz/BUILD b/test/extensions/filters/http/ext_authz/BUILD index a282dc215474..07b68c449a1e 100644 --- a/test/extensions/filters/http/ext_authz/BUILD +++ b/test/extensions/filters/http/ext_authz/BUILD @@ -130,6 +130,7 @@ envoy_cc_fuzz_test( "//test/mocks/network:network_mocks", "//test/mocks/server:server_factory_context_mocks", "//test/mocks/upstream:cluster_manager_mocks", + "@envoy_api//envoy/extensions/filters/http/ext_authz/v3:pkg_cc_proto", "@envoy_api//envoy/service/auth/v3:pkg_cc_proto", ], ) @@ -146,6 +147,5 @@ envoy_cc_test_library( "//test/mocks/network:network_mocks", "//test/mocks/server:server_factory_context_mocks", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", - "@envoy_api//envoy/extensions/filters/http/ext_authz/v3:pkg_cc_proto", ], ) diff --git a/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.cc b/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.cc index 0e3cc06cf890..166b98132c2e 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.cc @@ -1,13 +1,11 @@ #include "test/extensions/filters/http/ext_authz/ext_authz_fuzz_lib.h" #include "envoy/config/core/v3/base.pb.h" -#include "envoy/extensions/filters/http/ext_authz/v3/ext_authz.pb.validate.h" #include "source/common/network/address_impl.h" #include "source/extensions/filters/http/ext_authz/ext_authz.h" #include "test/extensions/filters/http/ext_authz/ext_authz_fuzz.pb.h" -#include "test/extensions/filters/http/ext_authz/ext_authz_fuzz.pb.validate.h" #include "test/mocks/network/mocks.h" #include "gmock/gmock.h"