diff --git a/weed/s3api/s3api_server.go b/weed/s3api/s3api_server.go index 53d9a95c4..4a3fa4554 100644 --- a/weed/s3api/s3api_server.go +++ b/weed/s3api/s3api_server.go @@ -1,9 +1,11 @@ package s3api import ( + "bytes" "context" "encoding/json" "fmt" + "io" "net" "net/http" "os" @@ -435,11 +437,33 @@ func (s3a *S3ApiServer) UnifiedPostHandler(w http.ResponseWriter, r *http.Reques } // 2. Parse Form to get Action + // Save the body first so we can restore it for STS handler signature verification + var bodyBytes []byte + if r.Body != nil { + // Limit body size to prevent DoS attacks + r.Body = http.MaxBytesReader(w, r.Body, iamRequestBodyLimit) + var err error + bodyBytes, err = io.ReadAll(r.Body) + if err != nil { + glog.Errorf("failed to read request body: %v", err) + s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest) + return + } + r.Body.Close() + // Restore body for ParseForm + r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + } + if err := r.ParseForm(); err != nil { s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest) return } + // Restore body again for downstream handlers (STS needs it for signature verification) + if bodyBytes != nil { + r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + } + // 3. Dispatch action := r.Form.Get("Action") if strings.HasPrefix(action, "AssumeRole") {