diff --git a/plugins/s3_auth/s3_auth.cc b/plugins/s3_auth/s3_auth.cc index df5c090779c..e9ac6c53c90 100644 --- a/plugins/s3_auth/s3_auth.cc +++ b/plugins/s3_auth/s3_auth.cc @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,7 @@ #include #include #include "tscore/ink_config.h" +#include "tscpp/util/TextView.h" #include "aws_auth_v4.h" @@ -523,41 +525,28 @@ S3Config::parse_config(const std::string &config_fname) TSError("[%s] called without a config file, this is broken", PLUGIN_NAME); return false; } else { - char line[512]; // These are long lines ... - FILE *file = fopen(config_fname.c_str(), "r"); + std::ifstream file; + file.open(config_fname, std::ios_base::in); - if (nullptr == file) { + if (!file.is_open()) { TSError("[%s] unable to open %s", PLUGIN_NAME, config_fname.c_str()); return false; } - while (fgets(line, sizeof(line), file) != nullptr) { - char *pos1, *pos2; + for (std::string buf; std::getline(file, buf);) { + ts::TextView line{buf}; - // Skip leading white spaces - pos1 = line; - while (*pos1 && isspace(*pos1)) { - ++pos1; - } - if (!*pos1 || ('#' == *pos1)) { - continue; - } + // Skip leading/trailing white spaces + ts::TextView key_val = line.trim_if(&isspace); - // Skip trailing white spaces - pos2 = pos1; - pos1 = pos2 + strlen(pos2) - 1; - while ((pos1 > pos2) && isspace(*pos1)) { - *(pos1--) = '\0'; - } - if (pos1 == pos2) { + // Skip empty or comment lines + if (key_val.empty() || ('#' == key_val[0])) { continue; } // Identify the keys (and values if appropriate) - std::string key_val(pos2, pos1 - pos2 + 1); - size_t eq_pos = key_val.find_first_of("="); - std::string key_str = trimWhiteSpaces(key_val.substr(0, eq_pos == String::npos ? key_val.size() : eq_pos)); - std::string val_str = eq_pos == String::npos ? "" : trimWhiteSpaces(key_val.substr(eq_pos + 1, key_val.size())); + std::string key_str{key_val.split_prefix_at('=').trim_if(&isspace)}; + std::string val_str{key_val.trim_if(&isspace)}; if (key_str == "secret_key") { set_secret(val_str.c_str()); @@ -578,11 +567,9 @@ S3Config::parse_config(const std::string &config_fname) } else if (key_str == "expiration") { set_expiration(val_str.c_str()); } else { - // ToDo: warnings? + TSWarning("[%s] unknown config key: %s", PLUGIN_NAME, key_str.c_str()); } } - - fclose(file); } return true; diff --git a/tests/gold_tests/pluginTest/s3_auth/gold/s3_auth_parsing.gold b/tests/gold_tests/pluginTest/s3_auth/gold/s3_auth_parsing.gold new file mode 100644 index 00000000000..50a707eb2d3 --- /dev/null +++ b/tests/gold_tests/pluginTest/s3_auth/gold/s3_auth_parsing.gold @@ -0,0 +1,17 @@ +* Trying 127.0.0.1:``... +* Connected to 127.0.0.1 (127.0.0.1) port `` (#0) +> GET /s3-bucket HTTP/1.1 +> Host: www.example.com +> User-Agent: curl/`` +> Accept: */* +> +* Mark bundle as not supporting multiuse +< HTTP/1.1 200 OK +< Content-Length: 8 +< Date: `` +< Age: 0 +< Connection: keep-alive +< Server: `` +< +{ [8 bytes data] +* Connection #0 to host 127.0.0.1 left intact diff --git a/tests/gold_tests/pluginTest/s3_auth/gold/s3_auth_parsing_ts.gold b/tests/gold_tests/pluginTest/s3_auth/gold/s3_auth_parsing_ts.gold new file mode 100644 index 00000000000..d266d6a69e6 --- /dev/null +++ b/tests/gold_tests/pluginTest/s3_auth/gold/s3_auth_parsing_ts.gold @@ -0,0 +1,5 @@ +``DIAG: (s3_auth) New rule: access_key=1234567, virtual_host=no, version=4 +``DIAG: (s3_auth) Set the header x-amz-content-sha256: UNSIGNED-PAYLOAD +``DIAG: (s3_auth) Set the header x-amz-date: `` +``DIAG: (s3_auth) Set the header x-amz-security-token: hkMsi6/bfHyBKrSeM/H0hoXeyx8z1yZ/mJ0c+B/TqYx=tTJDjnQWtul38Z9iVJjeH1HB4VT2c=2o3yE3o=I9kmFs/lJDR85qWjB8e5asY/WbjyRpbAzmDipQpboIcYnUYg55bxrQFidV/q8gZa5A9MpR3n=op1C0lWjeBqcEJxpevNZxteSQTQfeGsi98Cdf+On=/SINVlKrNhMnmMsDOLMGx1YYt9d4UsRg1jtVrwxL4Vd/F7aHCZySAXKv+1rkhACR023wpa3dhp+xirGJxSO9LWwvcrTdM4xJo4RS8B40tGENOJ1NKixUJxwN/6og58Oft/u==uleR89Ja=7zszK2H7tX3DqmEYNvNDYQh/7VBRe5otghQtPwJzWpXAGk+Vme4hPPM5K6axH2LxipXzRiIV=oxNs0upKNu1FvuzbCQmkQdKQVmXl0344vngngrgN7wkEfrYtmKwICmpAS0cbW9jdSClgziVo4NaFc/hsIfok=4UA3hVtxIdw74lFNXD0RR7HKXkFPLIn85M7peOZsqMUCfO4gxr7KCfabszQQf0YcP/mt79XK50=WrSJG7oUyn+clUySPhlegqHAfT9a50uSK5WiQmOnGNGLF4wDO10sqKN1xRgQbYHPtwL+Ye0EMisvmYA3==kScorTSGaQWyibSWXAvxq9+IVGBYShVJ6S7DmTT=u/2d/fGEge+Xmbxlftza=cxJ=Md=k1Q71Lp6Boa56d7wtYRpK6tXHJ9I/2r7rN1E4OtwkFqb7SfWV3UXwyUrXyaaNPTIbqnAHnbgUGtuU6pgICpfREiIxVqvKBf6ErbxHRmMmAuYKxk5E9Mn6nnbxR4WTniweKYeDv2w39zge/tss+36Moeuio9d2eoyRFqXhq=rUGtDwX3fzXV0wV+dUojxOYQ57GQDl7+68PwHPcX794OIXuGOxBk83lNIYIcYz3Vc7qnGy6tFTz7f6S9+EZuSGN7TY5VKkT2eWye46DebrDF9Nwzs/FVpTzbPD/KGDIBtFIbazglhKoWe9txqb1QW8vFNNVOEhYa+cViO3g8ZmY1wG960US2zsnX5Eg8Q5a4h3+sxaJSJ4ONiXZWJuAgKRQzcrszu+M5C0ZVoCOv1goEgfNJeSm/yFc/3rx8wmeWLIJFtq65B7zF72HRKq1nthHAguaxXr20nguHpKkDpNBDVa=WwuJsbeGI +``DIAG: (s3_auth) Set the header Authorization: AWS4-HMAC-SHA256 Credential=``/us-east-1/s3/aws4_request,SignedHeaders=accept;client-ip;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-security-token,Signature=`` diff --git a/tests/gold_tests/pluginTest/s3_auth/rules/v4-parse-test.test_input b/tests/gold_tests/pluginTest/s3_auth/rules/v4-parse-test.test_input new file mode 100644 index 00000000000..3b963c485fb --- /dev/null +++ b/tests/gold_tests/pluginTest/s3_auth/rules/v4-parse-test.test_input @@ -0,0 +1,29 @@ +# +# 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. + +# Test empty lines + +# Test space in front + access_key=1234567 + +# Test space in between +secret_key = 9999999 + +# long line, space behind +session_token=hkMsi6/bfHyBKrSeM/H0hoXeyx8z1yZ/mJ0c+B/TqYx=tTJDjnQWtul38Z9iVJjeH1HB4VT2c=2o3yE3o=I9kmFs/lJDR85qWjB8e5asY/WbjyRpbAzmDipQpboIcYnUYg55bxrQFidV/q8gZa5A9MpR3n=op1C0lWjeBqcEJxpevNZxteSQTQfeGsi98Cdf+On=/SINVlKrNhMnmMsDOLMGx1YYt9d4UsRg1jtVrwxL4Vd/F7aHCZySAXKv+1rkhACR023wpa3dhp+xirGJxSO9LWwvcrTdM4xJo4RS8B40tGENOJ1NKixUJxwN/6og58Oft/u==uleR89Ja=7zszK2H7tX3DqmEYNvNDYQh/7VBRe5otghQtPwJzWpXAGk+Vme4hPPM5K6axH2LxipXzRiIV=oxNs0upKNu1FvuzbCQmkQdKQVmXl0344vngngrgN7wkEfrYtmKwICmpAS0cbW9jdSClgziVo4NaFc/hsIfok=4UA3hVtxIdw74lFNXD0RR7HKXkFPLIn85M7peOZsqMUCfO4gxr7KCfabszQQf0YcP/mt79XK50=WrSJG7oUyn+clUySPhlegqHAfT9a50uSK5WiQmOnGNGLF4wDO10sqKN1xRgQbYHPtwL+Ye0EMisvmYA3==kScorTSGaQWyibSWXAvxq9+IVGBYShVJ6S7DmTT=u/2d/fGEge+Xmbxlftza=cxJ=Md=k1Q71Lp6Boa56d7wtYRpK6tXHJ9I/2r7rN1E4OtwkFqb7SfWV3UXwyUrXyaaNPTIbqnAHnbgUGtuU6pgICpfREiIxVqvKBf6ErbxHRmMmAuYKxk5E9Mn6nnbxR4WTniweKYeDv2w39zge/tss+36Moeuio9d2eoyRFqXhq=rUGtDwX3fzXV0wV+dUojxOYQ57GQDl7+68PwHPcX794OIXuGOxBk83lNIYIcYz3Vc7qnGy6tFTz7f6S9+EZuSGN7TY5VKkT2eWye46DebrDF9Nwzs/FVpTzbPD/KGDIBtFIbazglhKoWe9txqb1QW8vFNNVOEhYa+cViO3g8ZmY1wG960US2zsnX5Eg8Q5a4h3+sxaJSJ4ONiXZWJuAgKRQzcrszu+M5C0ZVoCOv1goEgfNJeSm/yFc/3rx8wmeWLIJFtq65B7zF72HRKq1nthHAguaxXr20nguHpKkDpNBDVa=WwuJsbeGI + +version=4 diff --git a/tests/gold_tests/pluginTest/s3_auth/s3_auth_config.test.py b/tests/gold_tests/pluginTest/s3_auth/s3_auth_config.test.py new file mode 100644 index 00000000000..5523ff63ad6 --- /dev/null +++ b/tests/gold_tests/pluginTest/s3_auth/s3_auth_config.test.py @@ -0,0 +1,66 @@ +''' +Test s3_auth config parsing +''' +# 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. + +ts = Test.MakeATSProcess("ts") +server = Test.MakeOriginServer("server") + +Test.testName = "s3_auth: config parsing" + +# define the request header and the desired response header +request_header = { + "headers": "GET /s3-bucket HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", + "x-amz-security-token": "hkMsi6/bfHyBKrSeM/H0hoXeyx8z1yZ/mJ0c+B/TqYx=tTJDjnQWtul38Z9iVJjeH1HB4VT2c=2o3yE3o=I9kmFs/lJDR85qWjB8e5asY/WbjyRpbAzmDipQpboIcYnUYg55bxrQFidV/q8gZa5A9MpR3n=op1C0lWjeBqcEJxpevNZxteSQTQfeGsi98Cdf+On=/SINVlKrNhMnmMsDOLMGx1YYt9d4UsRg1jtVrwxL4Vd/F7aHCZySAXKv+1rkhACR023wpa3dhp+xirGJxSO9LWwvcrTdM4xJo4RS8B40tGENOJ1NKixUJxwN/6og58Oft/u==uleR89Ja=7zszK2H7tX3DqmEYNvNDYQh/7VBRe5otghQtPwJzWpXAGk+Vme4hPPM5K6axH2LxipXzRiIV=oxNs0upKNu1FvuzbCQmkQdKQVmXl0344vngngrgN7wkEfrYtmKwICmpAS0cbW9jdSClgziVo4NaFc/hsIfok=4UA3hVtxIdw74lFNXD0RR7HKXkFPLIn85M7peOZsqMUCfO4gxr7KCfabszQQf0YcP/mt79XK50=WrSJG7oUyn+clUySPhlegqHAfT9a50uSK5WiQmOnGNGLF4wDO10sqKN1xRgQbYHPtwL+Ye0EMisvmYA3==kScorTSGaQWyibSWXAvxq9+IVGBYShVJ6S7DmTT=u/2d/fGEge+Xmbxlftza=cxJ=Md=k1Q71Lp6Boa56d7wtYRpK6tXHJ9I/2r7rN1E4OtwkFqb7SfWV3UXwyUrXyaaNPTIbqnAHnbgUGtuU6pgICpfREiIxVqvKBf6ErbxHRmMmAuYKxk5E9Mn6nnbxR4WTniweKYeDv2w39zge/tss+36Moeuio9d2eoyRFqXhq=rUGtDwX3fzXV0wV+dUojxOYQ57GQDl7+68PwHPcX794OIXuGOxBk83lNIYIcYz3Vc7qnGy6tFTz7f6S9+EZuSGN7TY5VKkT2eWye46DebrDF9Nwzs/FVpTzbPD/KGDIBtFIbazglhKoWe9txqb1QW8vFNNVOEhYa+cViO3g8ZmY1wG960US2zsnX5Eg8Q5a4h3+sxaJSJ4ONiXZWJuAgKRQzcrszu+M5C0ZVoCOv1goEgfNJeSm/yFc/3rx8wmeWLIJFtq65B7zF72HRKq1nthHAguaxXr20nguHpKkDpNBDVa=WwuJsbeGI", + "body": "" +} + +# desired response form the origin server +response_header = { + "headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", + "timestamp": "1469733493.993", + "body": "success!" +} + +# add request/response +server.addResponse("sessionlog.log", request_header, response_header) + +ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 's3_auth', +}) + +ts.Setup.CopyAs('rules/v4-parse-test.test_input', Test.RunDirectory) + +ts.Disk.remap_config.AddLine( + f'map http://www.example.com http://127.0.0.1:{server.Variables.Port} \ + @plugin=s3_auth.so \ + @pparam=--config @pparam={Test.RunDirectory}/v4-parse-test.test_input' +) + +# Test Case +tr = Test.AddTestRun() +tr.Processes.Default.Command = f'curl -s -v -H "Host: www.example.com" http://127.0.0.1:{ts.Variables.port}/s3-bucket;' +tr.Processes.Default.ReturnCode = 0 +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(ts) +tr.Processes.Default.Streams.stderr = "gold/s3_auth_parsing.gold" +tr.StillRunningAfter = server + +ts.Disk.traffic_out.Content = "gold/s3_auth_parsing_ts.gold" +ts.ReturnCode = 0