aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lu <chrislusf@users.noreply.github.com>2025-08-01 15:45:34 -0700
committerGitHub <noreply@github.com>2025-08-01 15:45:34 -0700
commit3d4e8409a53cf8103c9b93e2fde13be8e8652a25 (patch)
treecd63eab649a2198d56a5822c76adebc9b535db75
parentfd447465c2f1a3c4b5fb1ebb80ba628fdde567b8 (diff)
downloadseaweedfs-3d4e8409a53cf8103c9b93e2fde13be8e8652a25.tar.xz
seaweedfs-3d4e8409a53cf8103c9b93e2fde13be8e8652a25.zip
Support X-Forwarded-Port (#7070)
* support for the X-Forwarded-Prefix header * remove comments * refactoring * refactoring * path.Clean * support X-Forwarded-Port * Update weed/s3api/auth_signature_v4.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update weed/s3api/auto_signature_v4_test.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * more tests --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
-rw-r--r--weed/s3api/auth_signature_v4.go11
-rw-r--r--weed/s3api/auto_signature_v4_test.go95
2 files changed, 105 insertions, 1 deletions
diff --git a/weed/s3api/auth_signature_v4.go b/weed/s3api/auth_signature_v4.go
index b42547de7..226ae9a26 100644
--- a/weed/s3api/auth_signature_v4.go
+++ b/weed/s3api/auth_signature_v4.go
@@ -490,7 +490,16 @@ func extractSignedHeaders(signedHeaders []string, r *http.Request) (http.Header,
func extractHostHeader(r *http.Request) string {
// Check for X-Forwarded-Host header first, which is set by reverse proxies
if forwardedHost := r.Header.Get("X-Forwarded-Host"); forwardedHost != "" {
- // Using reverse proxy with X-Forwarded-Host.
+ // Check if reverse proxy also forwarded the port
+ if forwardedPort := r.Header.Get("X-Forwarded-Port"); forwardedPort != "" {
+ // Determine the protocol to check for standard ports
+ proto := r.Header.Get("X-Forwarded-Proto")
+ // Only add port if it's not the standard port for the protocol
+ if (proto == "https" && forwardedPort != "443") || (proto != "https" && forwardedPort != "80") {
+ return forwardedHost + ":" + forwardedPort
+ }
+ }
+ // Using reverse proxy with X-Forwarded-Host (standard port or no port forwarded).
return forwardedHost
}
diff --git a/weed/s3api/auto_signature_v4_test.go b/weed/s3api/auto_signature_v4_test.go
index 61da40aff..27d25d745 100644
--- a/weed/s3api/auto_signature_v4_test.go
+++ b/weed/s3api/auto_signature_v4_test.go
@@ -322,6 +322,101 @@ func TestSignatureV4WithForwardedPrefix(t *testing.T) {
}
}
+// Test X-Forwarded-Port support for reverse proxy scenarios
+func TestSignatureV4WithForwardedPort(t *testing.T) {
+ tests := []struct {
+ name string
+ host string
+ forwardedHost string
+ forwardedPort string
+ forwardedProto string
+ expectedHost string
+ }{
+ {
+ name: "HTTP with non-standard port",
+ host: "backend:8333",
+ forwardedHost: "example.com",
+ forwardedPort: "8080",
+ forwardedProto: "http",
+ expectedHost: "example.com:8080",
+ },
+ {
+ name: "HTTPS with non-standard port",
+ host: "backend:8333",
+ forwardedHost: "example.com",
+ forwardedPort: "8443",
+ forwardedProto: "https",
+ expectedHost: "example.com:8443",
+ },
+ {
+ name: "HTTP with standard port (80)",
+ host: "backend:8333",
+ forwardedHost: "example.com",
+ forwardedPort: "80",
+ forwardedProto: "http",
+ expectedHost: "example.com",
+ },
+ {
+ name: "HTTPS with standard port (443)",
+ host: "backend:8333",
+ forwardedHost: "example.com",
+ forwardedPort: "443",
+ forwardedProto: "https",
+ expectedHost: "example.com",
+ },
+ {
+ name: "empty proto with non-standard port",
+ host: "backend:8333",
+ forwardedHost: "example.com",
+ forwardedPort: "8080",
+ forwardedProto: "",
+ expectedHost: "example.com:8080",
+ },
+ {
+ name: "empty proto with standard http port",
+ host: "backend:8333",
+ forwardedHost: "example.com",
+ forwardedPort: "80",
+ forwardedProto: "",
+ expectedHost: "example.com",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ iam := newTestIAM()
+
+ // Create a request
+ r, err := newTestRequest("GET", "https://"+tt.host+"/test-bucket/test-object", 0, nil)
+ if err != nil {
+ t.Fatalf("Failed to create test request: %v", err)
+ }
+
+ // Set the mux variables manually since we're not going through the actual router
+ r = mux.SetURLVars(r, map[string]string{
+ "bucket": "test-bucket",
+ "object": "test-object",
+ })
+
+ // Set forwarded headers
+ r.Header.Set("Host", tt.host)
+ r.Header.Set("X-Forwarded-Host", tt.forwardedHost)
+ r.Header.Set("X-Forwarded-Port", tt.forwardedPort)
+ r.Header.Set("X-Forwarded-Proto", tt.forwardedProto)
+
+ // Sign the request with the expected host header
+ // We need to temporarily modify the Host header for signing
+ signV4WithPath(r, "AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", r.URL.Path)
+
+ // Test signature verification
+ _, errCode := iam.doesSignatureMatch(getContentSha256Cksum(r), r)
+ if errCode != s3err.ErrNone {
+ t.Errorf("Expected successful signature validation with forwarded port, got error: %v (code: %d)", errCode, int(errCode))
+ }
+ })
+ }
+}
+
// Test basic presigned URL functionality without prefix
func TestPresignedSignatureV4Basic(t *testing.T) {
iam := newTestIAM()