From 88956ccad8386f883f7d49ded46e6b0bb198c804 Mon Sep 17 00:00:00 2001 From: yhirose Date: Mon, 7 Sep 2026 21:49:00 -0400 Subject: [PATCH] Self-host the httpbin auth-testing backend for BaseAuthTest/DigestAuthTest These tests exercise the squid proxies by hitting /basic-auth and /digest-auth on an external httpbin-style site. That site's identity has already moved twice (httpbin.org -> httpcan.org, per #2300) chasing uptime, and httpcan.org itself is now down (Cloudflare 502 from its origin), failing CI with no code change involved. Adds two containers to the existing squid docker-compose stack instead: go-httpbin (mccutchen/go-httpbin) as the backend, and an nginx sidecar in front of it under the single "httpbin" hostname so both the NoSSL tests (port 80) and the SSL tests, which CONNECT-tunnel through the proxy to port 443, resolve the same name -- go-httpbin only listens on one port at a time, so it can't serve both protocols itself. nginx uses the repo's existing self-signed test cert; the SSL client tests already disable verification for it like other self-signed-cert tests in this suite. go-httpbin was picked over the more feature-complete kennethreitz/httpbin after finding the latter accepts a wrong digest-auth username as long as the password matches -- confirmed with a direct curl against the container, unrelated to anything in this repo. go-httpbin correctly rejects both. The trade-off is losing SHA-512 digest-auth coverage here, since go-httpbin only implements MD5 and SHA-256; nothing else in the suite exercises SHA-512 digest auth against a live server. Response body assertions are adjusted to go-httpbin's actual JSON shape (an added "authorized" field, no "algorithm" field), and the domain changes from httpcan.org to the self-hosted "httpbin". This only affects 'make proxy'/'make proxy_mbedtls'/'make proxy_wolfssl' and the Proxy Test CI workflow -- the default 'make' target is untouched. --- test/proxy/docker-compose.yml | 21 +++++++++++++++++++++ test/proxy/httpbin_nginx.conf | 22 ++++++++++++++++++++++ test/test_proxy.cc | 28 ++++++++++++++++------------ 3 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 test/proxy/httpbin_nginx.conf diff --git a/test/proxy/docker-compose.yml b/test/proxy/docker-compose.yml index 8ffe81e..c222d04 100644 --- a/test/proxy/docker-compose.yml +++ b/test/proxy/docker-compose.yml @@ -18,3 +18,24 @@ services: context: ./ args: auth: digest + + # Self-hosted stand-in for the httpbin.org-style auth-testing endpoints + # (/basic-auth, /digest-auth) that BaseAuthTest/DigestAuthTest exercise + # through the proxies above, so those tests don't depend on an external + # site's uptime. + httpbin_backend: + image: mccutchen/go-httpbin:latest + restart: always + + # TLS termination in front of httpbin_backend (which only speaks plain + # HTTP) so the SSL variants of those tests can CONNECT-tunnel through the + # proxies to "httpbin" on port 443, same as the NoSSL variants do on 80. + httpbin: + image: nginx:alpine + restart: always + depends_on: + - httpbin_backend + volumes: + - ./httpbin_nginx.conf:/etc/nginx/conf.d/default.conf:ro + - ../cert.pem:/etc/nginx/certs/cert.pem:ro + - ../key.pem:/etc/nginx/certs/key.pem:ro diff --git a/test/proxy/httpbin_nginx.conf b/test/proxy/httpbin_nginx.conf new file mode 100644 index 0000000..5eaf267 --- /dev/null +++ b/test/proxy/httpbin_nginx.conf @@ -0,0 +1,22 @@ +server { + listen 80; + server_name httpbin; + + location / { + proxy_pass http://httpbin_backend:8080; + proxy_set_header Host $host; + } +} + +server { + listen 443 ssl; + server_name httpbin; + + ssl_certificate /etc/nginx/certs/cert.pem; + ssl_certificate_key /etc/nginx/certs/key.pem; + + location / { + proxy_pass http://httpbin_backend:8080; + proxy_set_header Host $host; + } +} diff --git a/test/test_proxy.cc b/test/test_proxy.cc index 5683bf3..f83786b 100644 --- a/test/test_proxy.cc +++ b/test/test_proxy.cc @@ -173,7 +173,8 @@ template void BaseAuthTestFromHTTPWatch(T &cli) { cli.Get("/basic-auth/hello/world", Headers{make_basic_authentication_header("hello", "world")}); ASSERT_TRUE(res != nullptr); - EXPECT_EQ(normalizeJson("{\"authenticated\":true,\"user\":\"hello\"}\n"), + EXPECT_EQ(normalizeJson("{\"authenticated\":true,\"user\":\"hello\"," + "\"authorized\":true}\n"), normalizeJson(res->body)); EXPECT_EQ(StatusCode::OK_200, res->status); } @@ -182,7 +183,8 @@ template void BaseAuthTestFromHTTPWatch(T &cli) { cli.set_basic_auth("hello", "world"); auto res = cli.Get("/basic-auth/hello/world"); ASSERT_TRUE(res != nullptr); - EXPECT_EQ(normalizeJson("{\"authenticated\":true,\"user\":\"hello\"}\n"), + EXPECT_EQ(normalizeJson("{\"authenticated\":true,\"user\":\"hello\"," + "\"authorized\":true}\n"), normalizeJson(res->body)); EXPECT_EQ(StatusCode::OK_200, res->status); } @@ -203,13 +205,14 @@ template void BaseAuthTestFromHTTPWatch(T &cli) { } TEST(BaseAuthTest, NoSSL) { - Client cli("httpcan.org"); + Client cli("httpbin"); BaseAuthTestFromHTTPWatch(cli); } #ifdef CPPHTTPLIB_SSL_ENABLED TEST(BaseAuthTest, SSL) { - SSLClient cli("httpcan.org"); + SSLClient cli("httpbin"); + cli.enable_server_certificate_verification(false); BaseAuthTestFromHTTPWatch(cli); } #endif @@ -228,21 +231,21 @@ template void DigestAuthTestFromHTTPWatch(T &cli) { } { + // go-httpbin (the "httpbin" test double) only implements MD5 and + // SHA-256 for digest auth, so SHA-256 is as far as this can exercise + // the client's digest-auth algorithm selection end-to-end. std::vector paths = { "/digest-auth/auth/hello/world/MD5", "/digest-auth/auth/hello/world/SHA-256", - "/digest-auth/auth/hello/world/SHA-512", }; cli.set_digest_auth("hello", "world"); for (auto path : paths) { auto res = cli.Get(path.c_str()); ASSERT_TRUE(res != nullptr); - std::string algo(path.substr(path.rfind('/') + 1)); - EXPECT_EQ( - normalizeJson("{\"algorithm\":\"" + algo + - "\",\"authenticated\":true,\"user\":\"hello\"}\n"), - normalizeJson(res->body)); + EXPECT_EQ(normalizeJson("{\"authenticated\":true,\"user\":\"hello\"," + "\"authorized\":true}\n"), + normalizeJson(res->body)); EXPECT_EQ(StatusCode::OK_200, res->status); } @@ -263,12 +266,13 @@ template void DigestAuthTestFromHTTPWatch(T &cli) { } TEST(DigestAuthTest, SSL) { - SSLClient cli("httpcan.org"); + SSLClient cli("httpbin"); + cli.enable_server_certificate_verification(false); DigestAuthTestFromHTTPWatch(cli); } TEST(DigestAuthTest, NoSSL) { - Client cli("httpcan.org"); + Client cli("httpbin"); DigestAuthTestFromHTTPWatch(cli); } #endif