mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-11 06:18:27 +01:00
s3api: stop echoing stored tags and internal attributes on GET/HEAD (#12053)
* s3api: stop echoing stored tags and internal attributes on GET/HEAD setResponseHeaders copied every entry.Extended key into the response, only filtering xattr- and x-seaweedfs-. Stored object tags (X-Amz-Tagging-*) and the gateway's own attributes (Seaweed-X-Amz-Acl, -Owner, -Version-Id, -Object-Lock-Mode, ...) therefore leaked to any caller holding s3:GetObject, and to anonymous readers on public-read objects, without s3:GetObjectTagging or READ_ACP. Tag count, user metadata, storage class and the real S3 headers (x-amz-version-id, x-amz-object-lock-*) are unaffected. * s3api: match stored tag and internal attribute keys case-insensitively
This commit is contained in:
1 parent
52d91008ac
commit
403d51631b
2 files changed
+87
-15
No files matched your search
@@ -0,0 +1,66 @@
|
||||
package s3api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
)
|
||||
|
||||
// GetObject/HeadObject must expose only response headers AWS defines: user
|
||||
// metadata, standard entity headers and x-amz-tagging-count. Tag values live
|
||||
// behind GetObjectTagging and ACL/owner/lock state behind its own APIs; the
|
||||
// generic Extended echo must not hand them to any caller that can read the
|
||||
// object.
|
||||
func TestSetResponseHeadersFiltersInternalExtendedKeys(t *testing.T) {
|
||||
s3a := &S3ApiServer{}
|
||||
entry := &filer_pb.Entry{
|
||||
Name: "object",
|
||||
Attributes: &filer_pb.FuseAttributes{Mtime: 100},
|
||||
Extended: map[string][]byte{
|
||||
s3_constants.AmzObjectTaggingPrefix + "project": []byte("alpha"),
|
||||
s3_constants.AmzObjectTaggingPrefix + "owner": []byte("y"),
|
||||
"x-amz-tagging-sneaky": []byte("z"),
|
||||
"seaweed-x-amz-acl": []byte("z"),
|
||||
s3_constants.ExtAmzAclKey: []byte(`[{"Permission":"FULL_CONTROL"}]`),
|
||||
s3_constants.ExtAmzOwnerKey: []byte("admin"),
|
||||
s3_constants.ExtVersionIdKey: []byte("version-1"),
|
||||
s3_constants.ExtObjectLockModeKey: []byte("COMPLIANCE"),
|
||||
s3_constants.ExtETagKey: []byte("d41d8cd98f00b204e9800998ecf8427e"),
|
||||
s3_constants.SeaweedFSWriteId: []byte("write-id"),
|
||||
"X-Amz-Meta-Foo": []byte("bar"),
|
||||
"Cache-Control": []byte("no-cache"),
|
||||
"xattr-user.note": []byte("n"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, method := range []string{http.MethodGet, http.MethodHead} {
|
||||
w := httptest.NewRecorder()
|
||||
s3a.setResponseHeaders(w, httptest.NewRequest(method, "/bucket/object", nil), entry, 8)
|
||||
|
||||
for key := range w.Header() {
|
||||
lowerKey := strings.ToLower(key)
|
||||
if lowerKey == s3_constants.AmzTagCount {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(lowerKey, strings.ToLower(s3_constants.ExtAmzPrefix)) {
|
||||
t.Errorf("%s: internal header %q leaked into response", method, key)
|
||||
}
|
||||
if strings.HasPrefix(lowerKey, strings.ToLower(s3_constants.AmzObjectTaggingPrefix)) {
|
||||
t.Errorf("%s: object tag value %q leaked into response", method, key)
|
||||
}
|
||||
}
|
||||
if got := w.Header().Get(s3_constants.AmzTagCount); got != "2" {
|
||||
t.Errorf("%s: tag count = %q, want 2", method, got)
|
||||
}
|
||||
if got := w.Header()["X-Amz-Meta-foo"]; len(got) != 1 || got[0] != "bar" {
|
||||
t.Errorf("%s: user metadata dropped, X-Amz-Meta-foo = %v", method, got)
|
||||
}
|
||||
if got := w.Header().Get("Cache-Control"); got != "no-cache" {
|
||||
t.Errorf("%s: Cache-Control = %q", method, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user