diff --git a/src/proxy/http/HttpTransact.cc b/src/proxy/http/HttpTransact.cc index ae4ebc55745..cdefddbd5d5 100644 --- a/src/proxy/http/HttpTransact.cc +++ b/src/proxy/http/HttpTransact.cc @@ -7486,11 +7486,11 @@ HttpTransact::what_is_document_freshness(State *s, HTTPHdr *client_request, HTTP HttpTransact::Authentication_t HttpTransact::AuthenticationNeeded(const OverridableHttpConfigParams *p, HTTPHdr *client_request, HTTPHdr *obj_response) { - /////////////////////////////////////////////////////////////////////// - // from RFC2068, sec 14.8, if a client request has the Authorization // - // header set, we can't serve it unless the response is public, or // - // if it has a Cache-Control revalidate flag, and we do revalidate. // - /////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// + // Per RFC 7234 section 3.2, if a client request has the Authorization // + // header set, we can't serve a cached response unless the response has one // + // of: must-revalidate, proxy-revalidate, public, or s-maxage directives. // + /////////////////////////////////////////////////////////////////////////////// if ((p->cache_ignore_auth == 0) && client_request->presence(MIME_PRESENCE_AUTHORIZATION)) { if (obj_response->is_cache_control_set(HTTP_VALUE_MUST_REVALIDATE.c_str()) || @@ -7500,6 +7500,8 @@ HttpTransact::AuthenticationNeeded(const OverridableHttpConfigParams *p, HTTPHdr return Authentication_t::MUST_REVALIDATE; } else if (obj_response->is_cache_control_set(HTTP_VALUE_PUBLIC.c_str())) { return Authentication_t::SUCCESS; + } else if (obj_response->is_cache_control_set(HTTP_VALUE_S_MAXAGE.c_str())) { + return Authentication_t::SUCCESS; } else { if (obj_response->field_find("@WWW-Auth"sv) && client_request->method_get_wksidx() == HTTP_WKSIDX_GET) { return Authentication_t::CACHE_AUTH; diff --git a/tests/gold_tests/cache/cache-auth.test.py b/tests/gold_tests/cache/cache-auth.test.py index 08613554647..e60064c3a47 100644 --- a/tests/gold_tests/cache/cache-auth.test.py +++ b/tests/gold_tests/cache/cache-auth.test.py @@ -23,3 +23,7 @@ # Verify proxy.config.http.cache.ignore_authentication behavior. Test.ATSReplayTest(replay_file="replay/ignore_authentication.replay.yaml") + +# Verify that s-maxage allows serving cached responses to requests with +# Authorization headers per RFC 7234 section 3.2 +Test.ATSReplayTest(replay_file="replay/auth-s-maxage.replay.yaml") diff --git a/tests/gold_tests/cache/replay/auth-s-maxage.replay.yaml b/tests/gold_tests/cache/replay/auth-s-maxage.replay.yaml new file mode 100644 index 00000000000..2cf1d364312 --- /dev/null +++ b/tests/gold_tests/cache/replay/auth-s-maxage.replay.yaml @@ -0,0 +1,204 @@ +# 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 replay file tests RFC 7234 section 3.2: +# A shared cache can serve cached responses to requests with Authorization +# headers if the response has s-maxage directive (along with must-revalidate +# and public). +# +# This replay file assumes that caching is enabled and +# proxy.config.http.cache.ignore_authentication is set to 0 (current default). +# +meta: + version: "1.0" + +# Configuration section for autest integration +autest: + description: 'Test s-maxage allows serving cached responses to requests with Authorization headers per RFC 7234 section 3.2' + + # Server configuration + server: + name: 'server-s-maxage' + + # Client configuration + client: + name: 'client-s-maxage' + + # ATS configuration + ats: + name: 'ts-auth-s-maxage' + + # ATS process configuration + process_config: + enable_cache: true + + # ATS records.config settings + records_config: + proxy.config.diags.debug.enabled: 1 + proxy.config.diags.debug.tags: 'http' + + # Remap configuration + remap_config: + - from: "/" + to: "http://127.0.0.1:{SERVER_HTTP_PORT}/" + +sessions: + - transactions: + # First request: Cache a 200 response with s-maxage. + - client-request: + method: "GET" + version: "1.1" + url: /auth/s-maxage-test + headers: + fields: + - [uuid, s-maxage-cache-fill] + - [Host, example.com] + + server-response: + status: 200 + reason: OK + headers: + fields: + - [Content-Length, 16] + - [Cache-Control, "s-maxage=300"] + + proxy-response: + status: 200 + + # Second request: Request with Authorization header should be served from cache + # because response has s-maxage per RFC 7234 section 3.2. + - client-request: + # Add a delay so ATS has time to finish any caching IO for the + # previous transaction. + delay: 100ms + method: "GET" + version: "1.1" + url: /auth/s-maxage-test + headers: + fields: + - [uuid, s-maxage-with-auth] + - [Host, example.com] + - [Authorization, "Basic ZGVtbzphdHNAc3Ryb25ncHc="] + + # The server should NOT be reached because the cached response + # with s-maxage should be served. Return 400 to verify caching. + server-response: + status: 400 + reason: "Bad Request" + headers: + fields: + - [Content-Length, 0] + + # Expect the cached 200 response per RFC 7234 section 3.2 + proxy-response: + status: 200 + + - transactions: + # Test 2: Verify that public also works. + - client-request: + method: "GET" + version: "1.1" + url: /auth/public-test + headers: + fields: + - [uuid, public-cache-fill] + - [Host, example.com] + + server-response: + status: 200 + reason: OK + headers: + fields: + - [Content-Length, 16] + - [Cache-Control, "public, max-age=300"] + + proxy-response: + status: 200 + + # Request with Authorization header should be served from cache with public + - client-request: + delay: 100ms + method: "GET" + version: "1.1" + url: /auth/public-test + headers: + fields: + - [uuid, public-with-auth] + - [Host, example.com] + - [Authorization, "Basic ZGVtbzphdHNAc3Ryb25ncHc="] + + # The server should NOT be reached because the cached response + # with public should be served. Return 400 to verify caching. + server-response: + status: 400 + reason: "Bad Request" + headers: + fields: + - [Content-Length, 0] + + # Expect cached 200 response + proxy-response: + status: 200 + + - transactions: + # Test 3: Without s-maxage or public, Authorization should require revalidation + - client-request: + method: "GET" + version: "1.1" + url: /auth/no-directive-test + headers: + fields: + - [uuid, no-directive-cache-fill] + - [Host, example.com] + + server-response: + status: 200 + reason: OK + headers: + fields: + - [Content-Length, 16] + - [Cache-Control, "max-age=300"] + + proxy-response: + status: 200 + + # Request with Authorization header should NOT be served from cache + - client-request: + delay: 100ms + method: "GET" + version: "1.1" + url: /auth/no-directive-test + headers: + fields: + - [uuid, no-directive-with-auth] + - [Host, example.com] + - [Authorization, "Basic ZGVtbzphdHNAc3Ryb25ncHc="] + + # The request should be forwarded to the server and a 404 response + # should be returned. + server-response: + status: 404 + reason: "Not Found" + headers: + fields: + - [Content-Length, 20] + + # Expect the new 404 response from server rather than the previous 200 + # response. + proxy-response: + status: 404 +