[#216] Add bucket owner check

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2021-08-23 11:19:41 +03:00 committed by Kirillov Denis
parent 68e4e1bbc3
commit d81a3d7b45
7 changed files with 78 additions and 10 deletions

View file

@ -71,6 +71,15 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
if err = h.checkBucketOwner(r, srcBucket, r.Header.Get(api.AmzSourceExpectedBucketOwner)); err != nil {
h.logAndSendError(w, "source expected owner doesn't match", reqInfo, err)
return
}
if err = h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
return
}
if inf, err = h.obj.GetObjectInfo(r.Context(), srcBucket, srcObject); err != nil { if inf, err = h.obj.GetObjectInfo(r.Context(), srcBucket, srcObject); err != nil {
h.logAndSendError(w, "could not find object", reqInfo, err) h.logAndSendError(w, "could not find object", reqInfo, err)
return return

View file

@ -44,6 +44,11 @@ type DeleteObjectsResponse struct {
func (h *handler) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) { func (h *handler) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
reqInfo := api.GetReqInfo(r.Context()) reqInfo := api.GetReqInfo(r.Context())
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
return
}
if err := h.obj.DeleteObject(r.Context(), reqInfo.BucketName, reqInfo.ObjectName); err != nil { if err := h.obj.DeleteObject(r.Context(), reqInfo.BucketName, reqInfo.ObjectName); err != nil {
h.log.Error("could not delete object", h.log.Error("could not delete object",
zap.String("request_id", reqInfo.RequestID), zap.String("request_id", reqInfo.RequestID),
@ -100,6 +105,11 @@ func (h *handler) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Re
DeletedObjects: make([]ObjectIdentifier, 0, len(toRemove)), DeletedObjects: make([]ObjectIdentifier, 0, len(toRemove)),
} }
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
return
}
if errs := h.obj.DeleteObjects(r.Context(), reqInfo.BucketName, toRemove); errs != nil && !requested.Quiet { if errs := h.obj.DeleteObjects(r.Context(), reqInfo.BucketName, toRemove); errs != nil && !requested.Quiet {
additional := []zap.Field{ additional := []zap.Field{
zap.Strings("objects_name", toRemove), zap.Strings("objects_name", toRemove),
@ -135,6 +145,10 @@ func (h *handler) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Re
func (h *handler) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) { func (h *handler) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
reqInfo := api.GetReqInfo(r.Context()) reqInfo := api.GetReqInfo(r.Context())
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
return
}
if err := h.obj.DeleteBucket(r.Context(), &layer.DeleteBucketParams{Name: reqInfo.BucketName}); err != nil { if err := h.obj.DeleteBucket(r.Context(), &layer.DeleteBucketParams{Name: reqInfo.BucketName}); err != nil {
h.logAndSendError(w, "couldn't delete bucket", reqInfo, err) h.logAndSendError(w, "couldn't delete bucket", reqInfo, err)
} }

View file

@ -93,6 +93,11 @@ func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
if err = h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
return
}
if inf, err = h.obj.GetObjectInfo(r.Context(), reqInfo.BucketName, reqInfo.ObjectName); err != nil { if inf, err = h.obj.GetObjectInfo(r.Context(), reqInfo.BucketName, reqInfo.ObjectName); err != nil {
h.logAndSendError(w, "could not find object", reqInfo, err) h.logAndSendError(w, "could not find object", reqInfo, err)
return return

View file

@ -31,6 +31,11 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
reqInfo = api.GetReqInfo(r.Context()) reqInfo = api.GetReqInfo(r.Context())
) )
if err = h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
return
}
if inf, err = h.obj.GetObjectInfo(r.Context(), reqInfo.BucketName, reqInfo.ObjectName); err != nil { if inf, err = h.obj.GetObjectInfo(r.Context(), reqInfo.BucketName, reqInfo.ObjectName); err != nil {
h.logAndSendError(w, "could not fetch object info", reqInfo, err) h.logAndSendError(w, "could not fetch object info", reqInfo, err)
return return
@ -56,7 +61,11 @@ func (h *handler) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
bktInfo, err := h.obj.GetBucketInfo(r.Context(), reqInfo.BucketName) bktInfo, err := h.obj.GetBucketInfo(r.Context(), reqInfo.BucketName)
if err != nil { if err != nil {
h.logAndSendError(w, "could not fetch object info", reqInfo, err) h.logAndSendError(w, "could not get bucket info", reqInfo, err)
return
}
if err = checkOwner(bktInfo, r.Header.Get(api.AmzExpectedBucketOwner)); err != nil {
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
return return
} }

View file

@ -21,6 +21,11 @@ func (h *handler) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
return return
} }
if err = h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
return
}
list, err := h.obj.ListObjectsV1(r.Context(), params) list, err := h.obj.ListObjectsV1(r.Context(), params)
if err != nil { if err != nil {
h.logAndSendError(w, "something went wrong", reqInfo, err) h.logAndSendError(w, "something went wrong", reqInfo, err)
@ -60,6 +65,11 @@ func (h *handler) ListObjectsV2Handler(w http.ResponseWriter, r *http.Request) {
return return
} }
if err = h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
return
}
list, err := h.obj.ListObjectsV2(r.Context(), params) list, err := h.obj.ListObjectsV2(r.Context(), params)
if err != nil { if err != nil {
h.logAndSendError(w, "something went wrong", reqInfo, err) h.logAndSendError(w, "something went wrong", reqInfo, err)

View file

@ -18,3 +18,23 @@ func (h *handler) logAndSendError(w http.ResponseWriter, logText string, reqInfo
h.log.Error(logText, fields...) h.log.Error(logText, fields...)
api.WriteErrorResponse(w, reqInfo, err) api.WriteErrorResponse(w, reqInfo, err)
} }
func (h *handler) checkBucketOwner(r *http.Request, bucket string, header ...string) error {
var expected string
if len(header) == 0 {
expected = r.Header.Get(api.AmzExpectedBucketOwner)
} else {
expected = header[0]
}
if len(expected) == 0 {
return nil
}
bktInfo, err := h.obj.GetBucketInfo(r.Context(), bucket)
if err != nil {
return err
}
return checkOwner(bktInfo, expected)
}

View file

@ -30,15 +30,16 @@ const (
IfMatch = "If-Match" IfMatch = "If-Match"
IfNoneMatch = "If-None-Match" IfNoneMatch = "If-None-Match"
AmzCopyIfModifiedSince = "X-Amz-Copy-Source-If-Modified-Since" AmzCopyIfModifiedSince = "X-Amz-Copy-Source-If-Modified-Since"
AmzCopyIfUnmodifiedSince = "X-Amz-Copy-Source-If-Unmodified-Since" AmzCopyIfUnmodifiedSince = "X-Amz-Copy-Source-If-Unmodified-Since"
AmzCopyIfMatch = "X-Amz-Copy-Source-If-Match" AmzCopyIfMatch = "X-Amz-Copy-Source-If-Match"
AmzCopyIfNoneMatch = "X-Amz-Copy-Source-If-None-Match" AmzCopyIfNoneMatch = "X-Amz-Copy-Source-If-None-Match"
AmzACL = "X-Amz-Acl" AmzACL = "X-Amz-Acl"
AmzGrantFullControl = "X-Amz-Grant-Full-Control" AmzGrantFullControl = "X-Amz-Grant-Full-Control"
AmzGrantRead = "X-Amz-Grant-Read" AmzGrantRead = "X-Amz-Grant-Read"
AmzGrantWrite = "X-Amz-Grant-Write" AmzGrantWrite = "X-Amz-Grant-Write"
AmzExpectedBucketOwner = "X-Amz-Expected-Bucket-Owner" AmzExpectedBucketOwner = "X-Amz-Expected-Bucket-Owner"
AmzSourceExpectedBucketOwner = "X-Amz-Source-Expected-Bucket-Owner"
ContainerID = "X-Container-Id" ContainerID = "X-Container-Id"
) )