diff --git a/doc/admin-guide/files/remap.config.en.rst b/doc/admin-guide/files/remap.config.en.rst index 407e4fde033..8215b6795df 100644 --- a/doc/admin-guide/files/remap.config.en.rst +++ b/doc/admin-guide/files/remap.config.en.rst @@ -459,6 +459,9 @@ Note that these Acl filters will return a 403 response if the resource is restri The difference between ``@src_ip`` and ``@in_ip`` is that the ``@src_ip`` is the client ip and the ``in_ip`` is the ip address the client is connecting to (the incoming address). +If no IP address is specified for either ``@src_ip`` or ``@in_ip``, the filter will +implicitly apply to all incoming IP addresses. This can be explicitly stated with +``@src_ip=all``. Named Filters ============= diff --git a/include/proxy/http/HttpTransact.h b/include/proxy/http/HttpTransact.h index c089dde2ce5..88f114a23c9 100644 --- a/include/proxy/http/HttpTransact.h +++ b/include/proxy/http/HttpTransact.h @@ -682,7 +682,7 @@ class HttpTransact bool is_upgrade_request = false; bool is_websocket = false; bool did_upgrade_succeed = false; - bool client_connection_enabled = true; + bool client_connection_allowed = true; bool acl_filtering_performed = false; bool api_cleanup_cache_read = false; bool api_server_response_no_store = false; diff --git a/include/proxy/http/remap/AclFiltering.h b/include/proxy/http/remap/AclFiltering.h index 53d2a91e636..b7ff143e0fa 100644 --- a/include/proxy/http/remap/AclFiltering.h +++ b/include/proxy/http/remap/AclFiltering.h @@ -37,22 +37,27 @@ static int const ACL_FILTER_MAX_IN_IP = 8; static int const ACL_FILTER_MAX_ARGV = 512; struct src_ip_info_t { - IpAddr start; ///< Minimum value in range. - IpAddr end; ///< Maximum value in range. - bool invert; ///< Should we "invert" the meaning of this IP range ("not in range") + IpAddr start; ///< Minimum value in range. + IpAddr end; ///< Maximum value in range. + bool invert; ///< Should we "invert" the meaning of this IP range ("not in range") + bool match_all_addresses; ///< This rule should match all IP addresses. void reset() { start.invalidate(); end.invalidate(); - invert = false; + invert = false; + match_all_addresses = false; } /// @return @c true if @a ip is inside @a this range. bool contains(IpEndpoint const &ip) { + if (match_all_addresses) { + return true; + } IpAddr addr{ip}; return addr.cmp(start) >= 0 && addr.cmp(end) <= 0; } @@ -70,10 +75,10 @@ class acl_filter_rule acl_filter_rule *next = nullptr; char *filter_name = nullptr; // optional filter name unsigned int allow_flag : 1, // action allow deny - src_ip_valid : 1, // src_ip range valid - in_ip_valid : 1, - active_queue_flag : 1, // filter is in active state (used by .useflt directive) - internal : 1; // filter internal HTTP requests + src_ip_valid : 1, // src_ip (client's src IP) range is specified and valid + in_ip_valid : 1, // in_ip (client's dest IP) range is specified and valid + active_queue_flag : 1, // filter is in active state (used by .useflt directive) + internal : 1; // filter internal HTTP requests // we need arguments as string array for directive processing int argc = 0; // argument counter (only for filter defs) diff --git a/include/proxy/http/remap/UrlMapping.h b/include/proxy/http/remap/UrlMapping.h index 511e949f424..2779ac9563d 100644 --- a/include/proxy/http/remap/UrlMapping.h +++ b/include/proxy/http/remap/UrlMapping.h @@ -116,7 +116,7 @@ class url_mapping referer_info *referer_list = nullptr; redirect_tag_str *redir_chunk_list = nullptr; bool ip_allow_check_enabled_p = false; - acl_filter_rule *filter = nullptr; // acl filtering (list of rules) + acl_filter_rule *filter = nullptr; // acl filtering (linked list of rules) LINK(url_mapping, link); // For use with the main Queue linked list holding all the mapping std::shared_ptr strategy = nullptr; std::string remapKey; diff --git a/src/proxy/http/HttpSM.cc b/src/proxy/http/HttpSM.cc index 2fbacdacdf1..c4eadf0ccb7 100644 --- a/src/proxy/http/HttpSM.cc +++ b/src/proxy/http/HttpSM.cc @@ -4301,7 +4301,7 @@ HttpSM::check_sni_host() swoc::bwprint(error_bw_buffer, "No SNI for TLS request: connecting to {} for host='{}', returning a 403", t_state.client_info.dst_addr, std::string_view{host_name, static_cast(host_len)}); Log::error("%s", error_bw_buffer.c_str()); - this->t_state.client_connection_enabled = false; + this->t_state.client_connection_allowed = false; } } else if (strncasecmp(host_name, sni_value, host_len) != 0) { // Name mismatch Warning("SNI/hostname mismatch sni=%s host=%.*s action=%s", sni_value, host_len, host_name, action_value); @@ -4310,7 +4310,7 @@ HttpSM::check_sni_host() swoc::bwprint(error_bw_buffer, "SNI/hostname mismatch: connecting to {} for host='{}' sni='{}', returning a 403", t_state.client_info.dst_addr, std::string_view{host_name, static_cast(host_len)}, sni_value); Log::error("%s", error_bw_buffer.c_str()); - this->t_state.client_connection_enabled = false; + this->t_state.client_connection_allowed = false; } } else { SMDbg(dbg_ctl_ssl_sni, "SNI/hostname successfully match sni=%s host=%.*s", sni_value, host_len, host_name); diff --git a/src/proxy/http/HttpTransact.cc b/src/proxy/http/HttpTransact.cc index f4723134873..5a520587f60 100644 --- a/src/proxy/http/HttpTransact.cc +++ b/src/proxy/http/HttpTransact.cc @@ -1106,7 +1106,7 @@ HttpTransact::EndRemapRequest(State *s) ///////////////////////////////////////////////////////////////////////// // We must close this connection if client_connection_enabled == false // ///////////////////////////////////////////////////////////////////////// - if (!s->client_connection_enabled) { + if (!s->client_connection_allowed) { build_error_response(s, HTTP_STATUS_FORBIDDEN, "Access Denied", "access#denied"); s->reverse_proxy = false; goto done; @@ -6491,7 +6491,7 @@ void HttpTransact::process_quick_http_filter(State *s, int method) { // connection already disabled by previous ACL filtering, don't modify it. - if (!s->client_connection_enabled) { + if (!s->client_connection_allowed) { return; } @@ -6527,7 +6527,7 @@ HttpTransact::process_quick_http_filter(State *s, int method) TxnDbg(dbg_ctl_ip_allow, "Line %d denial for '%.*s' from %s", acl.source_line(), method_str_len, method_str, ats_ip_ntop(&s->client_info.src_addr.sa, ipb, sizeof(ipb))); } - s->client_connection_enabled = false; + s->client_connection_allowed = false; } } } diff --git a/src/proxy/http/remap/RemapConfig.cc b/src/proxy/http/remap/RemapConfig.cc index e76dd7dca6f..a958284acc1 100644 --- a/src/proxy/http/remap/RemapConfig.cc +++ b/src/proxy/http/remap/RemapConfig.cc @@ -21,6 +21,7 @@ * limitations under the License. */ +#include "proxy/http/remap/AclFiltering.h" #include "swoc/swoc_file.h" #include "proxy/http/remap/RemapConfig.h" @@ -450,6 +451,7 @@ remap_validate_filter_args(acl_filter_rule **rule_pp, const char **argv, int arg Debug("url_rewrite", "[validate_filter_args] new acl_filter_rule class was created during remap rule processing"); } + bool ip_is_listed = false; for (i = 0; i < argc; i++) { unsigned long ul; bool hasarg; @@ -509,7 +511,10 @@ remap_validate_filter_args(acl_filter_rule **rule_pp, const char **argv, int arg if (ul & REMAP_OPTFLG_INVERT) { ipi->invert = true; } - if (ats_ip_range_parse(argptr, ipi->start, ipi->end) != 0) { + std::string_view arg{argptr}; + if (arg == "all") { + ipi->match_all_addresses = true; + } else if (ats_ip_range_parse(argptr, ipi->start, ipi->end) != 0) { Debug("url_rewrite", "[validate_filter_args] Unable to parse IP value in %s", argv[i]); snprintf(errStrBuf, errStrBufSize, "Unable to parse IP value in %s", argv[i]); errStrBuf[errStrBufSize - 1] = 0; @@ -529,6 +534,7 @@ remap_validate_filter_args(acl_filter_rule **rule_pp, const char **argv, int arg if (ipi) { rule->src_ip_cnt++; rule->src_ip_valid = 1; + ip_is_listed = true; } } @@ -568,6 +574,7 @@ remap_validate_filter_args(acl_filter_rule **rule_pp, const char **argv, int arg if (ipi) { rule->in_ip_cnt++; rule->in_ip_valid = 1; + ip_is_listed = true; } } @@ -593,6 +600,15 @@ remap_validate_filter_args(acl_filter_rule **rule_pp, const char **argv, int arg } } + if (!ip_is_listed) { + // If no IP addresses are listed, treat that like `@src_ip=all`. + ink_release_assert(rule->src_ip_valid == 0 && rule->src_ip_cnt == 0); + src_ip_info_t *ipi = &rule->src_ip_array[rule->src_ip_cnt]; + ipi->match_all_addresses = true; + rule->src_ip_cnt++; + rule->src_ip_valid = 1; + } + if (is_debug_tag_set("url_rewrite")) { rule->print(); } diff --git a/src/proxy/http/remap/UrlRewrite.cc b/src/proxy/http/remap/UrlRewrite.cc index 79645ae19cc..63fd302002a 100644 --- a/src/proxy/http/remap/UrlRewrite.cc +++ b/src/proxy/http/remap/UrlRewrite.cc @@ -399,7 +399,7 @@ UrlRewrite::ReverseMap(HTTPHdr *response_header) void UrlRewrite::PerformACLFiltering(HttpTransact::State *s, url_mapping *map) { - if (unlikely(!s || s->acl_filtering_performed || !s->client_connection_enabled)) { + if (unlikely(!s || s->acl_filtering_performed || !s->client_connection_allowed)) { return; } @@ -411,43 +411,50 @@ UrlRewrite::PerformACLFiltering(HttpTransact::State *s, url_mapping *map) ink_release_assert(ats_is_ip(&s->client_info.src_addr)); - s->client_connection_enabled = true; // Default is that we allow things unless some filter matches + s->client_connection_allowed = true; // Default is that we allow things unless some filter matches - for (acl_filter_rule *rp = map->filter; rp; rp = rp->next) { - bool match = true; + int rule_index = 0; + for (acl_filter_rule *rp = map->filter; rp; rp = rp->next, ++rule_index) { + bool method_matches = true; if (rp->method_restriction_enabled) { if (method_wksidx >= 0 && method_wksidx < HTTP_WKSIDX_METHODS_CNT) { - match = rp->standard_method_lookup[method_wksidx]; + method_matches = rp->standard_method_lookup[method_wksidx]; } else if (!rp->nonstandard_methods.empty()) { - match = false; + method_matches = false; } else { int method_str_len; const char *method_str = s->hdr_info.client_request.method_get(&method_str_len); - match = rp->nonstandard_methods.count(std::string(method_str, method_str_len)); + method_matches = rp->nonstandard_methods.count(std::string(method_str, method_str_len)); } + } else { + // No method specified, therefore all match. + method_matches = true; } - if (match && rp->src_ip_valid) { - match = false; - for (int j = 0; j < rp->src_ip_cnt && !match; j++) { + // Is there a @src_ip specified? If so, check it. + bool ip_matches = false; + if (rp->src_ip_valid) { + ip_matches = false; + for (int j = 0; j < rp->src_ip_cnt && !ip_matches; j++) { bool in_range = rp->src_ip_array[j].contains(s->client_info.src_addr); if (rp->src_ip_array[j].invert) { if (!in_range) { - match = true; + ip_matches = true; } } else { if (in_range) { - match = true; + ip_matches = true; } } } } - if (match && rp->in_ip_valid) { - Debug("url_rewrite", "match was true and we have specified a in_ip field"); - match = false; - for (int j = 0; j < rp->in_ip_cnt && !match; j++) { + // Is there an @in_ip specified? If so, check it. + if (ip_matches && rp->in_ip_valid) { + Debug("url_rewrite", "src_ip match was true, checking the specified in_ip range."); + ip_matches = false; + for (int j = 0; j < rp->in_ip_cnt && !ip_matches; j++) { IpEndpoint incoming_addr; incoming_addr.assign(s->state_machine->get_ua_txn()->get_netvc()->get_local_addr()); if (is_debug_tag_set("url_rewrite")) { @@ -460,28 +467,36 @@ UrlRewrite::PerformACLFiltering(HttpTransact::State *s, url_mapping *map) bool in_range = rp->in_ip_array[j].contains(incoming_addr); if (rp->in_ip_array[j].invert) { if (!in_range) { - match = true; + ip_matches = true; } } else { if (in_range) { - match = true; + ip_matches = true; } } } } if (rp->internal) { - match = s->state_machine->get_ua_txn()->get_netvc()->get_is_internal_request(); - Debug("url_rewrite", "%s an internal request", match ? "matched" : "didn't match"); + ip_matches = s->state_machine->get_ua_txn()->get_netvc()->get_is_internal_request(); + Debug("url_rewrite", "%s an internal request", ip_matches ? "matched" : "didn't match"); } - if (match) { - // We have a match, stop evaluating filters - Debug("url_rewrite", "matched ACL filter rule, %s request", rp->allow_flag ? "allowing" : "denying"); - s->client_connection_enabled = rp->allow_flag; + Debug("url_rewrite", "%d: ACL filter %s rule matches by ip: %s, by method: %s", rule_index, + (rp->allow_flag ? "allow" : "deny"), (ip_matches ? "true" : "false"), (method_matches ? "true" : "false")); + + if (ip_matches) { + // The rule matches. Handle the method according to the rule. + if (method_matches) { + // Did they specify allowing the listed methods, or denying them? + Debug("url_rewrite", "matched ACL filter rule, %s request", rp->allow_flag ? "allowing" : "denying"); + s->client_connection_allowed = rp->allow_flag; + } else { + Debug("url_rewrite", "ACL rule matched on IP but not on method, action: %s, %s the request", + (rp->allow_flag ? "allow" : "deny"), (rp->allow_flag ? "denying" : "allowing")); + s->client_connection_allowed = !rp->allow_flag; + } break; - } else { - Debug("url_rewrite", "did NOT match ACL filter rule, %s request", rp->allow_flag ? "denying" : "allowing"); } } } /* end of for(rp = map->filter;rp;rp = rp->next) */ diff --git a/tests/gold_tests/remap/remap_acl.test.py b/tests/gold_tests/remap/remap_acl.test.py new file mode 100644 index 00000000000..3da753eb8e1 --- /dev/null +++ b/tests/gold_tests/remap/remap_acl.test.py @@ -0,0 +1,169 @@ +''' +Verify remap.config acl behavior. +''' +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +import os +import re +from typing import List, Tuple + +Test.Summary = ''' +Verify remap.config acl behavior. +''' + + +class Test_remap_acl: + """Configure a test to verify remap.config acl behavior.""" + + _ts_counter: int = 0 + _server_counter: int = 0 + _client_counter: int = 0 + + def __init__( + self, name: str, replay_file: str, ip_allow_content: str, deactivate_ip_allow: bool, acl_configuration: str, + named_acls: List[Tuple[str, str]], expected_responses: list[int]): + """Initialize the test. + + :param name: The name of the test. + :param replay_file: The replay file to be used. + :param ip_allow_content: The ip_allow configuration to be used. + :param deactivate_ip_allow: Whether to deactivate the ip_allow filter. + :param acl_configuration: The ACL configuration to be used. + :param named_acls: The set of named ACLs to configure and use. + :param expect_responses: The in-order expected responses from the proxy. + """ + self._replay_file = replay_file + self._ip_allow_content = ip_allow_content + self._deactivate_ip_allow = deactivate_ip_allow + self._acl_configuration = acl_configuration + self._named_acls = named_acls + self._expected_responses = expected_responses + + tr = Test.AddTestRun(name) + self._configure_server(tr) + self._configure_traffic_server(tr) + self._configure_client(tr) + + def _configure_server(self, tr: 'TestRun') -> None: + """Configure the server. + + :param tr: The TestRun object to associate the server process with. + """ + name = f"server-{Test_remap_acl._server_counter}" + server = tr.AddVerifierServerProcess(name, self._replay_file) + Test_remap_acl._server_counter += 1 + self._server = server + + def _configure_traffic_server(self, tr: 'TestRun') -> None: + """Configure Traffic Server. + + :param tr: The TestRun object to associate the Traffic Server process with. + """ + + name = f"ts-{Test_remap_acl._ts_counter}" + ts = tr.MakeATSProcess(name, enable_cache=False, enable_tls=True) + Test_remap_acl._ts_counter += 1 + self._ts = ts + + ts.addDefaultSSLFiles() + ts.Disk.ssl_multicert_config.AddLine('dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key') + ts.Disk.records_config.update( + { + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http|url|remap', + 'proxy.config.http.push_method_enabled': 1, + 'proxy.config.ssl.server.cert.path': ts.Variables.SSLDir, + 'proxy.config.quic.no_activity_timeout_in': 0, + 'proxy.config.ssl.server.private_key.path': ts.Variables.SSLDir, + 'proxy.config.ssl.client.verify.server.policy': 'PERMISSIVE', + 'proxy.config.http.connect_ports': self._server.Variables.http_port, + }) + + remap_config_lines = [] + if self._deactivate_ip_allow: + remap_config_lines.append('.deactivatefilter ip_allow') + + # First, define the name ACLs (filters). + for name, definition in self._named_acls: + remap_config_lines.append(f'.definefilter {name} {definition}') + # Now activate them. + for name, _ in self._named_acls: + remap_config_lines.append(f'.activatefilter {name}') + + remap_config_lines.append(f'map / http://127.0.0.1:{self._server.Variables.http_port} {self._acl_configuration}') + ts.Disk.remap_config.AddLines(remap_config_lines) + ts.Disk.ip_allow_yaml.AddLines(self._ip_allow_content.split("\n")) + + def _configure_client(self, tr: 'TestRun') -> None: + """Run the test. + + :param tr: The TestRun object to associate the client process with. + """ + + name = f"client-{Test_remap_acl._client_counter}" + p = tr.AddVerifierClientProcess(name, self._replay_file, https_ports=[self._ts.Variables.ssl_port]) + Test_remap_acl._client_counter += 1 + p.StartBefore(self._server) + p.StartBefore(self._ts) + + codes = [str(code) for code in self._expected_responses] + p.Streams.stdout += Testers.ContainsExpression( + '.*'.join(codes), "Verifying the expected order of responses", reflags=re.DOTALL | re.MULTILINE) + + +IP_ALLOW_CONTENT = f''' +ip_allow: + - apply: in + ip_addrs: 0/0 + action: allow +''' + +test_ip_allow_optional_methods = Test_remap_acl( + "Verify non-allowed methods are blocked.", + replay_file='remap_acl_get_post_allowed.replay.yaml', + ip_allow_content=IP_ALLOW_CONTENT, + deactivate_ip_allow=True, + acl_configuration='@action=allow @src_ip=127.0.0.1 @method=GET @method=POST', + named_acls=[], + expected_responses=[200, 200, 403, 403, 403]) + +test_ip_allow_optional_methods = Test_remap_acl( + "Verify denied methods are blocked.", + replay_file='remap_acl_get_post_denied.replay.yaml', + ip_allow_content=IP_ALLOW_CONTENT, + deactivate_ip_allow=True, + acl_configuration='@action=deny @src_ip=127.0.0.1 @method=GET @method=POST', + named_acls=[], + expected_responses=[403, 403, 200, 200, 400]) + +test_ip_allow_optional_methods = Test_remap_acl( + "Verify defined filters are evaluated before remap lines.", + replay_file='remap_acl_all_denied.replay.yaml', + ip_allow_content=IP_ALLOW_CONTENT, + deactivate_ip_allow=True, + acl_configuration='@action=allow @src_ip=127.0.0.1 @method=GET @method=POST', + named_acls=[('deny', '@action=deny @src_ip=0.0.0.0-255.255.255.255')], + expected_responses=[403, 403, 403, 403, 403]) + +test_ip_allow_optional_methods = Test_remap_acl( + "Verify a default deny filter rule works.", + replay_file='remap_acl_all_denied.replay.yaml', + ip_allow_content=IP_ALLOW_CONTENT, + deactivate_ip_allow=True, + acl_configuration='@action=allow @src_ip=1.2.3.4 @method=GET @method=POST', + named_acls=[('deny', '@action=deny @src_ip=0.0.0.0-255.255.255.255')], + expected_responses=[403, 403, 403, 403, 403]) diff --git a/tests/gold_tests/remap/remap_acl_all_denied.replay.yaml b/tests/gold_tests/remap/remap_acl_all_denied.replay.yaml new file mode 100644 index 00000000000..d15782b0463 --- /dev/null +++ b/tests/gold_tests/remap/remap_acl_all_denied.replay.yaml @@ -0,0 +1,126 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# This expects a remap.config that denies all request methods. + +meta: + version: "1.0" + + blocks: + - standard_response: &standard_response + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 20 ] + +sessions: +- protocol: + - name: http + version: 1 + - name: tls + sni: test_sni + transactions: + + - client-request: + method: "GET" + version: "1.1" + url: /test/ip_allow/test_get + headers: + fields: + - [ Content-Length, 0 ] + - [ uuid, get ] + - [ X-Request, get ] + + # Not received. + <<: *standard_response + + proxy-response: + status: 403 + + - client-request: + method: "POST" + version: "1.1" + url: /test/ip_allow/test_post + headers: + fields: + - [Content-Length, 10] + - [ uuid, post ] + - [ X-Request, post ] + + # Not received. + <<: *standard_response + + proxy-response: + status: 403 + + - client-request: + method: "PUT" + version: "1.1" + url: /test/ip_allow/test_put + headers: + fields: + - [ Host, example.com ] + - [ uuid, put ] + - [ X-Request, put ] + - [ Content-Length, 113 ] + content: + encoding: plain + data: "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public,max-age=2\n\nCACHED" + + # Not received. + <<: *standard_response + + proxy-response: + status: 403 + + # DELETE rejected + - client-request: + method: "DELETE" + version: "1.1" + url: /test/ip_allow/test_delete + headers: + fields: + - [ Host, example.com ] + - [ uuid, delete ] + - [ X-Request, delete ] + - [ Content-Length, 0 ] + + <<: *standard_response + + proxy-response: + status: 403 + + # PUSH rejected + - client-request: + method: "PUSH" + version: "1.1" + url: /test/ip_allow/test_push + headers: + fields: + - [ Host, example.com ] + - [ uuid, push ] + - [ X-Request, push ] + - [ Content-Length, 113 ] + content: + encoding: plain + data: "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public,max-age=2\n\nCACHED" + + <<: *standard_response + + proxy-response: + status: 403 diff --git a/tests/gold_tests/remap/remap_acl_get_post_allowed.replay.yaml b/tests/gold_tests/remap/remap_acl_get_post_allowed.replay.yaml new file mode 100644 index 00000000000..cf08a22a8ae --- /dev/null +++ b/tests/gold_tests/remap/remap_acl_get_post_allowed.replay.yaml @@ -0,0 +1,130 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# This expects a remap.config that allows GET and POST, but denies all other +# methods. + +meta: + version: "1.0" + + blocks: + - standard_response: &standard_response + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 20 ] + +sessions: +- protocol: + - name: http + version: 1 + - name: tls + sni: test_sni + transactions: + + - client-request: + method: "GET" + version: "1.1" + url: /test/ip_allow/test_get + headers: + fields: + - [ Content-Length, 0 ] + - [ uuid, get ] + - [ X-Request, get ] + + <<: *standard_response + + proxy-response: + status: 200 + + # POST also is in the allow list. + - client-request: + method: "POST" + version: "1.1" + url: /test/ip_allow/test_post + headers: + fields: + - [Content-Length, 10] + - [ uuid, post ] + - [ X-Request, post ] + + <<: *standard_response + + proxy-response: + status: 200 + + # PUT rejected + - client-request: + method: "PUT" + version: "1.1" + url: /test/ip_allow/test_put + headers: + fields: + - [ Host, example.com ] + - [ uuid, put ] + - [ X-Request, put ] + - [ Content-Length, 113 ] + content: + encoding: plain + data: "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public,max-age=2\n\nCACHED" + + # Not received. + <<: *standard_response + + # Verify that ATS rejected the PUSH. + proxy-response: + status: 403 + + # DELETE rejected + - client-request: + method: "DELETE" + version: "1.1" + url: /test/ip_allow/test_delete + headers: + fields: + - [ Host, example.com ] + - [ uuid, delete ] + - [ X-Request, delete ] + - [ Content-Length, 0 ] + + <<: *standard_response + + # Verify that ATS rejects the DELETE. + proxy-response: + status: 403 + + # PUSH rejected + - client-request: + method: "PUSH" + version: "1.1" + url: /test/ip_allow/test_push + headers: + fields: + - [ Host, example.com ] + - [ uuid, push ] + - [ X-Request, push ] + - [ Content-Length, 113 ] + content: + encoding: plain + data: "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public,max-age=2\n\nCACHED" + + <<: *standard_response + + # Verify that ATS rejected the PUSH. + proxy-response: + status: 403 diff --git a/tests/gold_tests/remap/remap_acl_get_post_denied.replay.yaml b/tests/gold_tests/remap/remap_acl_get_post_denied.replay.yaml new file mode 100644 index 00000000000..2a824456481 --- /dev/null +++ b/tests/gold_tests/remap/remap_acl_get_post_denied.replay.yaml @@ -0,0 +1,124 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +# This expects a remap.config that denies GET and POST, but allows all other +# methods. + +meta: + version: "1.0" + + blocks: + - standard_response: &standard_response + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 20 ] + +sessions: +- protocol: + - name: http + version: 1 + - name: tls + sni: test_sni + transactions: + + - client-request: + method: "GET" + version: "1.1" + url: /test/ip_allow/test_get + headers: + fields: + - [ Content-Length, 0 ] + - [ uuid, get ] + - [ X-Request, get ] + + <<: *standard_response + + proxy-response: + status: 403 + + - client-request: + method: "POST" + version: "1.1" + url: /test/ip_allow/test_post + headers: + fields: + - [Content-Length, 10] + - [ uuid, post ] + - [ X-Request, post ] + + <<: *standard_response + + proxy-response: + status: 403 + + # All other methods are allowed. + - client-request: + method: "PUT" + version: "1.1" + url: /test/ip_allow/test_put + headers: + fields: + - [ Host, example.com ] + - [ uuid, put ] + - [ X-Request, put ] + - [ Content-Length, 113 ] + content: + encoding: plain + data: "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public,max-age=2\n\nCACHED" + + <<: *standard_response + + proxy-response: + status: 200 + + - client-request: + method: "DELETE" + version: "1.1" + url: /test/ip_allow/test_delete + headers: + fields: + - [ Host, example.com ] + - [ uuid, delete ] + - [ X-Request, delete ] + - [ Content-Length, 0 ] + + <<: *standard_response + + proxy-response: + status: 200 + + - client-request: + method: "PUSH" + version: "1.1" + url: /test/ip_allow/test_push + headers: + fields: + - [ Host, example.com ] + - [ uuid, push ] + - [ X-Request, push ] + - [ Content-Length, 113 ] + content: + encoding: plain + data: "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public,max-age=2\n\nCACHED" + + <<: *standard_response + + # ATS will allow the PUSH, but issue a 400 saying that it can't cache it. + proxy-response: + status: 400