Browse Source

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>
detect-and-plan-ec-tasks
Chris Lu 2 months ago
committed by GitHub
parent
commit
3d4e8409a5
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 11
      weed/s3api/auth_signature_v4.go
  2. 95
      weed/s3api/auto_signature_v4_test.go

11
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 { func extractHostHeader(r *http.Request) string {
// Check for X-Forwarded-Host header first, which is set by reverse proxies // Check for X-Forwarded-Host header first, which is set by reverse proxies
if forwardedHost := r.Header.Get("X-Forwarded-Host"); forwardedHost != "" { 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 return forwardedHost
} }

95
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 // Test basic presigned URL functionality without prefix
func TestPresignedSignatureV4Basic(t *testing.T) { func TestPresignedSignatureV4Basic(t *testing.T) {
iam := newTestIAM() iam := newTestIAM()

Loading…
Cancel
Save