forked from TrueCloudLab/frostfs-s3-gw
[#357] Add check of request and resource tags
Signed-off-by: Marina Biryukova <m.biryukova@yadro.com>
This commit is contained in:
parent
9f29fcbd52
commit
3ff027587c
24 changed files with 506 additions and 155 deletions
|
@ -168,8 +168,8 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
} else {
|
||||
tagPrm := &layer.GetObjectTaggingParams{
|
||||
ObjectVersion: &layer.ObjectVersion{
|
||||
tagPrm := &data.GetObjectTaggingParams{
|
||||
ObjectVersion: &data.ObjectVersion{
|
||||
BktInfo: srcObjPrm.BktInfo,
|
||||
ObjectName: srcObject,
|
||||
VersionID: srcObjInfo.VersionID(),
|
||||
|
@ -259,8 +259,8 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if tagSet != nil {
|
||||
tagPrm := &layer.PutObjectTaggingParams{
|
||||
ObjectVersion: &layer.ObjectVersion{
|
||||
tagPrm := &data.PutObjectTaggingParams{
|
||||
ObjectVersion: &data.ObjectVersion{
|
||||
BktInfo: dstBktInfo,
|
||||
ObjectName: reqInfo.ObjectName,
|
||||
VersionID: dstObjInfo.VersionID(),
|
||||
|
|
|
@ -11,9 +11,11 @@ import (
|
|||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/encryption"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -289,23 +291,24 @@ func copyObject(hc *handlerContext, bktName, fromObject, toObject string, copyMe
|
|||
}
|
||||
|
||||
func putObjectTagging(t *testing.T, tc *handlerContext, bktName, objName string, tags map[string]string) {
|
||||
body := &Tagging{
|
||||
TagSet: make([]Tag, 0, len(tags)),
|
||||
body := &data.Tagging{
|
||||
TagSet: make([]data.Tag, 0, len(tags)),
|
||||
}
|
||||
|
||||
for key, val := range tags {
|
||||
body.TagSet = append(body.TagSet, Tag{
|
||||
body.TagSet = append(body.TagSet, data.Tag{
|
||||
Key: key,
|
||||
Value: val,
|
||||
})
|
||||
}
|
||||
|
||||
w, r := prepareTestRequest(tc, bktName, objName, body)
|
||||
middleware.GetReqInfo(r.Context()).Tagging = body
|
||||
tc.Handler().PutObjectTaggingHandler(w, r)
|
||||
assertStatus(t, w, http.StatusOK)
|
||||
}
|
||||
|
||||
func getObjectTagging(t *testing.T, tc *handlerContext, bktName, objName, version string) *Tagging {
|
||||
func getObjectTagging(t *testing.T, tc *handlerContext, bktName, objName, version string) *data.Tagging {
|
||||
query := make(url.Values)
|
||||
query.Add(api.QueryVersionID, version)
|
||||
|
||||
|
@ -313,7 +316,7 @@ func getObjectTagging(t *testing.T, tc *handlerContext, bktName, objName, versio
|
|||
tc.Handler().GetObjectTaggingHandler(w, r)
|
||||
assertStatus(t, w, http.StatusOK)
|
||||
|
||||
tagging := &Tagging{}
|
||||
tagging := &data.Tagging{}
|
||||
err := xml.NewDecoder(w.Result().Body).Decode(tagging)
|
||||
require.NoError(t, err)
|
||||
return tagging
|
||||
|
|
|
@ -184,7 +184,7 @@ func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
t := &layer.ObjectVersion{
|
||||
t := &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: info.Name,
|
||||
VersionID: info.VersionID(),
|
||||
|
|
|
@ -70,7 +70,7 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
t := &layer.ObjectVersion{
|
||||
t := &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: info.Name,
|
||||
VersionID: info.VersionID(),
|
||||
|
|
|
@ -133,7 +133,7 @@ func (h *handler) PutObjectLegalHoldHandler(w http.ResponseWriter, r *http.Reque
|
|||
}
|
||||
|
||||
p := &layer.PutLockInfoParams{
|
||||
ObjVersion: &layer.ObjectVersion{
|
||||
ObjVersion: &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: reqInfo.ObjectName,
|
||||
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
||||
|
@ -172,7 +172,7 @@ func (h *handler) GetObjectLegalHoldHandler(w http.ResponseWriter, r *http.Reque
|
|||
return
|
||||
}
|
||||
|
||||
p := &layer.ObjectVersion{
|
||||
p := &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: reqInfo.ObjectName,
|
||||
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
||||
|
@ -221,7 +221,7 @@ func (h *handler) PutObjectRetentionHandler(w http.ResponseWriter, r *http.Reque
|
|||
}
|
||||
|
||||
p := &layer.PutLockInfoParams{
|
||||
ObjVersion: &layer.ObjectVersion{
|
||||
ObjVersion: &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: reqInfo.ObjectName,
|
||||
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
||||
|
@ -256,7 +256,7 @@ func (h *handler) GetObjectRetentionHandler(w http.ResponseWriter, r *http.Reque
|
|||
return
|
||||
}
|
||||
|
||||
p := &layer.ObjectVersion{
|
||||
p := &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: reqInfo.ObjectName,
|
||||
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
||||
|
|
|
@ -487,8 +487,8 @@ func (h *handler) completeMultipartUpload(r *http.Request, c *layer.CompleteMult
|
|||
objInfo := extendedObjInfo.ObjectInfo
|
||||
|
||||
if len(uploadData.TagSet) != 0 {
|
||||
tagPrm := &layer.PutObjectTaggingParams{
|
||||
ObjectVersion: &layer.ObjectVersion{
|
||||
tagPrm := &data.PutObjectTaggingParams{
|
||||
ObjectVersion: &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: objInfo.Name,
|
||||
VersionID: objInfo.VersionID(),
|
||||
|
|
|
@ -307,8 +307,8 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if tagSet != nil {
|
||||
tagPrm := &layer.PutObjectTaggingParams{
|
||||
ObjectVersion: &layer.ObjectVersion{
|
||||
tagPrm := &data.PutObjectTaggingParams{
|
||||
ObjectVersion: &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: objInfo.Name,
|
||||
VersionID: objInfo.VersionID(),
|
||||
|
@ -483,7 +483,12 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if tagging := auth.MultipartFormValue(r, "tagging"); tagging != "" {
|
||||
buffer := bytes.NewBufferString(tagging)
|
||||
tagSet, err = h.readTagSet(buffer)
|
||||
tags := new(data.Tagging)
|
||||
if err = h.cfg.NewXMLDecoder(buffer).Decode(tags); err != nil {
|
||||
h.logAndSendError(w, "could not decode tag set", reqInfo, errors.GetAPIError(errors.ErrMalformedXML))
|
||||
return
|
||||
}
|
||||
tagSet, err = h.readTagSet(tags)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not read tag set", reqInfo, err)
|
||||
return
|
||||
|
@ -574,8 +579,8 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if tagSet != nil {
|
||||
tagPrm := &layer.PutObjectTaggingParams{
|
||||
ObjectVersion: &layer.ObjectVersion{
|
||||
tagPrm := &data.PutObjectTaggingParams{
|
||||
ObjectVersion: &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: objInfo.Name,
|
||||
VersionID: objInfo.VersionID(),
|
||||
|
@ -789,7 +794,7 @@ func parseTaggingHeader(header http.Header) (map[string]string, error) {
|
|||
}
|
||||
tagSet = make(map[string]string, len(queries))
|
||||
for k, v := range queries {
|
||||
tag := Tag{Key: k, Value: v[0]}
|
||||
tag := data.Tag{Key: k, Value: v[0]}
|
||||
if err = checkTag(tag); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -185,12 +185,6 @@ type VersioningConfiguration struct {
|
|||
MfaDelete string `xml:"MfaDelete,omitempty"`
|
||||
}
|
||||
|
||||
// Tagging contains tag set.
|
||||
type Tagging struct {
|
||||
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ Tagging"`
|
||||
TagSet []Tag `xml:"TagSet>Tag"`
|
||||
}
|
||||
|
||||
// PostResponse contains result of posting object.
|
||||
type PostResponse struct {
|
||||
Bucket string `xml:"Bucket"`
|
||||
|
@ -198,12 +192,6 @@ type PostResponse struct {
|
|||
ETag string `xml:"Etag"`
|
||||
}
|
||||
|
||||
// Tag is an AWS key-value tag.
|
||||
type Tag struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// MarshalXML -- StringMap marshals into XML.
|
||||
func (s StringMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||
tokens := []xml.Token{start}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
@ -10,7 +9,6 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||
"go.uber.org/zap"
|
||||
|
@ -28,7 +26,7 @@ func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request
|
|||
ctx := r.Context()
|
||||
reqInfo := middleware.GetReqInfo(ctx)
|
||||
|
||||
tagSet, err := h.readTagSet(r.Body)
|
||||
tagSet, err := h.readTagSet(reqInfo.Tagging)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not read tag set", reqInfo, err)
|
||||
return
|
||||
|
@ -40,8 +38,8 @@ func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request
|
|||
return
|
||||
}
|
||||
|
||||
tagPrm := &layer.PutObjectTaggingParams{
|
||||
ObjectVersion: &layer.ObjectVersion{
|
||||
tagPrm := &data.PutObjectTaggingParams{
|
||||
ObjectVersion: &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: reqInfo.ObjectName,
|
||||
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
||||
|
@ -87,8 +85,8 @@ func (h *handler) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request
|
|||
return
|
||||
}
|
||||
|
||||
tagPrm := &layer.GetObjectTaggingParams{
|
||||
ObjectVersion: &layer.ObjectVersion{
|
||||
tagPrm := &data.GetObjectTaggingParams{
|
||||
ObjectVersion: &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: reqInfo.ObjectName,
|
||||
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
||||
|
@ -119,7 +117,7 @@ func (h *handler) DeleteObjectTaggingHandler(w http.ResponseWriter, r *http.Requ
|
|||
return
|
||||
}
|
||||
|
||||
p := &layer.ObjectVersion{
|
||||
p := &data.ObjectVersion{
|
||||
BktInfo: bktInfo,
|
||||
ObjectName: reqInfo.ObjectName,
|
||||
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
|
||||
|
@ -152,7 +150,7 @@ func (h *handler) DeleteObjectTaggingHandler(w http.ResponseWriter, r *http.Requ
|
|||
func (h *handler) PutBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
||||
reqInfo := middleware.GetReqInfo(r.Context())
|
||||
|
||||
tagSet, err := h.readTagSet(r.Body)
|
||||
tagSet, err := h.readTagSet(reqInfo.Tagging)
|
||||
if err != nil {
|
||||
h.logAndSendError(w, "could not read tag set", reqInfo, err)
|
||||
return
|
||||
|
@ -207,12 +205,7 @@ func (h *handler) DeleteBucketTaggingHandler(w http.ResponseWriter, r *http.Requ
|
|||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (h *handler) readTagSet(reader io.Reader) (map[string]string, error) {
|
||||
tagging := new(Tagging)
|
||||
if err := h.cfg.NewXMLDecoder(reader).Decode(tagging); err != nil {
|
||||
return nil, errors.GetAPIError(errors.ErrMalformedXML)
|
||||
}
|
||||
|
||||
func (h *handler) readTagSet(tagging *data.Tagging) (map[string]string, error) {
|
||||
if err := checkTagSet(tagging.TagSet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -228,10 +221,10 @@ func (h *handler) readTagSet(reader io.Reader) (map[string]string, error) {
|
|||
return tagSet, nil
|
||||
}
|
||||
|
||||
func encodeTagging(tagSet map[string]string) *Tagging {
|
||||
tagging := &Tagging{}
|
||||
func encodeTagging(tagSet map[string]string) *data.Tagging {
|
||||
tagging := &data.Tagging{}
|
||||
for k, v := range tagSet {
|
||||
tagging.TagSet = append(tagging.TagSet, Tag{Key: k, Value: v})
|
||||
tagging.TagSet = append(tagging.TagSet, data.Tag{Key: k, Value: v})
|
||||
}
|
||||
sort.Slice(tagging.TagSet, func(i, j int) bool {
|
||||
return tagging.TagSet[i].Key < tagging.TagSet[j].Key
|
||||
|
@ -240,7 +233,7 @@ func encodeTagging(tagSet map[string]string) *Tagging {
|
|||
return tagging
|
||||
}
|
||||
|
||||
func checkTagSet(tagSet []Tag) error {
|
||||
func checkTagSet(tagSet []data.Tag) error {
|
||||
if len(tagSet) > maxTags {
|
||||
return errors.GetAPIError(errors.ErrInvalidTagsSizeExceed)
|
||||
}
|
||||
|
@ -254,7 +247,7 @@ func checkTagSet(tagSet []Tag) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkTag(tag Tag) error {
|
||||
func checkTag(tag data.Tag) error {
|
||||
if len(tag.Key) < 1 || len(tag.Key) > keyTagMaxLength {
|
||||
return errors.GetAPIError(errors.ErrInvalidTagKey)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -20,23 +22,23 @@ func TestTagsValidity(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range []struct {
|
||||
tag Tag
|
||||
tag data.Tag
|
||||
valid bool
|
||||
}{
|
||||
{tag: Tag{}, valid: false},
|
||||
{tag: Tag{Key: "", Value: "1"}, valid: false},
|
||||
{tag: Tag{Key: "aws:key", Value: "val"}, valid: false},
|
||||
{tag: Tag{Key: "key~", Value: "val"}, valid: false},
|
||||
{tag: Tag{Key: "key\\", Value: "val"}, valid: false},
|
||||
{tag: Tag{Key: "key?", Value: "val"}, valid: false},
|
||||
{tag: Tag{Key: sbKey.String() + "b", Value: "val"}, valid: false},
|
||||
{tag: Tag{Key: "key", Value: sbValue.String() + "b"}, valid: false},
|
||||
{tag: data.Tag{}, valid: false},
|
||||
{tag: data.Tag{Key: "", Value: "1"}, valid: false},
|
||||
{tag: data.Tag{Key: "aws:key", Value: "val"}, valid: false},
|
||||
{tag: data.Tag{Key: "key~", Value: "val"}, valid: false},
|
||||
{tag: data.Tag{Key: "key\\", Value: "val"}, valid: false},
|
||||
{tag: data.Tag{Key: "key?", Value: "val"}, valid: false},
|
||||
{tag: data.Tag{Key: sbKey.String() + "b", Value: "val"}, valid: false},
|
||||
{tag: data.Tag{Key: "key", Value: sbValue.String() + "b"}, valid: false},
|
||||
|
||||
{tag: Tag{Key: sbKey.String(), Value: "val"}, valid: true},
|
||||
{tag: Tag{Key: "key", Value: sbValue.String()}, valid: true},
|
||||
{tag: Tag{Key: "k e y", Value: "v a l"}, valid: true},
|
||||
{tag: Tag{Key: "12345", Value: "1234"}, valid: true},
|
||||
{tag: Tag{Key: allowedTagChars, Value: allowedTagChars}, valid: true},
|
||||
{tag: data.Tag{Key: sbKey.String(), Value: "val"}, valid: true},
|
||||
{tag: data.Tag{Key: "key", Value: sbValue.String()}, valid: true},
|
||||
{tag: data.Tag{Key: "k e y", Value: "v a l"}, valid: true},
|
||||
{tag: data.Tag{Key: "12345", Value: "1234"}, valid: true},
|
||||
{tag: data.Tag{Key: allowedTagChars, Value: allowedTagChars}, valid: true},
|
||||
} {
|
||||
err := checkTag(tc.tag)
|
||||
if tc.valid {
|
||||
|
@ -55,13 +57,13 @@ func TestPutObjectTaggingCheckUniqueness(t *testing.T) {
|
|||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
body *Tagging
|
||||
body *data.Tagging
|
||||
error bool
|
||||
}{
|
||||
{
|
||||
name: "Two tags with unique keys",
|
||||
body: &Tagging{
|
||||
TagSet: []Tag{
|
||||
body: &data.Tagging{
|
||||
TagSet: []data.Tag{
|
||||
{
|
||||
Key: "key-1",
|
||||
Value: "val-1",
|
||||
|
@ -76,8 +78,8 @@ func TestPutObjectTaggingCheckUniqueness(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Two tags with the same keys",
|
||||
body: &Tagging{
|
||||
TagSet: []Tag{
|
||||
body: &data.Tagging{
|
||||
TagSet: []data.Tag{
|
||||
{
|
||||
Key: "key-1",
|
||||
Value: "val-1",
|
||||
|
@ -93,6 +95,7 @@ func TestPutObjectTaggingCheckUniqueness(t *testing.T) {
|
|||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
w, r := prepareTestRequest(hc, bktName, objName, tc.body)
|
||||
middleware.GetReqInfo(r.Context()).Tagging = tc.body
|
||||
hc.Handler().PutObjectTaggingHandler(w, r)
|
||||
if tc.error {
|
||||
assertS3Error(t, w, apiErrors.GetAPIError(apiErrors.ErrInvalidTagKeyUniqueness))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue