s3: support STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER for signed chunked uploads with checksums (#7623)
* s3: support STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER for signed chunked uploads with checksums When AWS SDK v2 clients upload with both chunked encoding and checksum validation enabled, they use the x-amz-content-sha256 header value of STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER instead of the simpler STREAMING-AWS4-HMAC-SHA256-PAYLOAD. This caused the chunked reader to not be properly activated, resulting in chunk-signature metadata being stored as part of the file content. Changes: - Add streamingSignedPayloadTrailer constant for the new header value - Update isRequestSignStreamingV4() to recognize this header - Update newChunkedReader() to handle this streaming type - Update calculateSeedSignature() to accept this header - Add unit test for signed streaming upload with trailer Fixes issue where Quarkus/AWS SDK v2 uploads with checksum validation resulted in corrupted file content containing chunk-signature data. * address review comments: add trailer signature to test, fix constant alignment * test: separate canonical trailer text (\n) from on-wire format (\r\n) * test: add negative test for invalid trailer signature * refactor: check HTTP method first in streaming auth checks (fail-fast) * test: handle crc32 Write error return for completeness * refactor: extract createTrailerStreamingRequest helper to reduce test duplication * fmt * docs: clarify test comment about trailer signature validation status * refactor: calculate chunk data length dynamically instead of hardcoding * Update weed/s3api/chunked_reader_v4_test.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * fix: use current time for signatures instead of hardcoded past date --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -53,10 +53,11 @@ func (iam *IdentityAccessManagement) reqSignatureV4Verify(r *http.Request) (*Ide
|
||||
|
||||
// Constants specific to this file
|
||||
const (
|
||||
emptySHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
streamingContentSHA256 = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"
|
||||
streamingUnsignedPayload = "STREAMING-UNSIGNED-PAYLOAD-TRAILER"
|
||||
unsignedPayload = "UNSIGNED-PAYLOAD"
|
||||
emptySHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
streamingContentSHA256 = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"
|
||||
streamingContentSHA256Trailer = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER"
|
||||
streamingUnsignedPayload = "STREAMING-UNSIGNED-PAYLOAD-TRAILER"
|
||||
unsignedPayload = "UNSIGNED-PAYLOAD"
|
||||
// Limit for IAM/STS request body size to prevent DoS attacks
|
||||
iamRequestBodyLimit = 10 * (1 << 20) // 10 MiB
|
||||
)
|
||||
@@ -214,14 +215,14 @@ func (iam *IdentityAccessManagement) verifyV4Signature(r *http.Request, shouldCh
|
||||
availableKeys = append(availableKeys, key)
|
||||
}
|
||||
iam.m.RUnlock()
|
||||
|
||||
|
||||
glog.Warningf("InvalidAccessKeyId: attempted key '%s' not found. Available keys: %d, Auth enabled: %v",
|
||||
authInfo.AccessKey, len(availableKeys), iam.isAuthEnabled)
|
||||
|
||||
|
||||
if glog.V(2) && len(availableKeys) > 0 {
|
||||
glog.V(2).Infof("Available access keys: %v", availableKeys)
|
||||
}
|
||||
|
||||
|
||||
return nil, nil, "", nil, s3err.ErrInvalidAccessKeyID
|
||||
}
|
||||
|
||||
@@ -562,10 +563,10 @@ func (iam *IdentityAccessManagement) doesPolicySignatureV4Match(formValues http.
|
||||
iam.m.RLock()
|
||||
availableKeyCount := len(iam.accessKeyIdent)
|
||||
iam.m.RUnlock()
|
||||
|
||||
|
||||
glog.Warningf("InvalidAccessKeyId (POST policy): attempted key '%s' not found. Available keys: %d, Auth enabled: %v",
|
||||
credHeader.accessKey, availableKeyCount, iam.isAuthEnabled)
|
||||
|
||||
|
||||
return s3err.ErrInvalidAccessKeyID
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user