fix: authenticate before parsing form in IAM API (#7803)

fix: authenticate before parsing form in IAM API (#7802)

The AuthIam middleware was calling ParseForm() before AuthSignatureOnly(),
which consumed the request body before signature verification could hash it.

For IAM requests (service != 's3'), the signature verification needs to hash
the request body. When ParseForm() was called first, the body was already
consumed, resulting in an empty body hash and SignatureDoesNotMatch error.

The fix moves authentication before form parsing. The streamHashRequestBody
function preserves the body after reading, so ParseForm() works correctly
after authentication.

Fixes #7802
This commit is contained in:
Chris Lu
2025-12-17 01:06:43 -08:00
committed by GitHub
parent 2763f105f4
commit 99a2e79efc
2 changed files with 172 additions and 10 deletions

View File

@@ -641,7 +641,18 @@ func (e *EmbeddedIamApi) AuthIam(f http.HandlerFunc, _ Action) http.HandlerFunc
return
}
// Parse form to get Action and UserName
// Authenticate BEFORE parsing form.
// ParseForm() reads and consumes the request body, but signature verification
// needs to hash the body for IAM requests (service != "s3").
// The streamHashRequestBody function in auth_signature_v4.go preserves the body
// after reading it, so ParseForm() will work correctly after authentication.
identity, errCode := e.iam.AuthSignatureOnly(r)
if errCode != s3err.ErrNone {
s3err.WriteErrorResponse(w, r, errCode)
return
}
// Now parse form to get Action and UserName (body was preserved by auth)
if err := r.ParseForm(); err != nil {
s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
return
@@ -650,15 +661,6 @@ func (e *EmbeddedIamApi) AuthIam(f http.HandlerFunc, _ Action) http.HandlerFunc
action := r.Form.Get("Action")
targetUserName := r.PostForm.Get("UserName")
// Authenticate the request using signature-only verification.
// This bypasses S3 authorization checks (identity.canDo) since IAM operations
// have their own permission model based on self-service vs admin operations.
identity, errCode := e.iam.AuthSignatureOnly(r)
if errCode != s3err.ErrNone {
s3err.WriteErrorResponse(w, r, errCode)
return
}
// IAM API requests must be authenticated - reject nil identity
// (can happen for authTypePostPolicy or authTypeStreamingUnsigned)
if identity == nil {