[#604] Add support of MFADelete argument and x-amz-mfa header

Signed-off-by: Pavel Pogodaev <p.pogodaev@yadro.com>
This commit is contained in:
Pavel Pogodaev 2025-01-21 15:08:34 +03:00
parent 13fce51021
commit 7fbc69f4f5
28 changed files with 906 additions and 118 deletions

View file

@ -15,6 +15,7 @@ import (
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"github.com/pquerna/otp/totp"
)
// limitation of AWS https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html
@ -84,6 +85,26 @@ func (h *handler) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
return
}
if len(versionID) > 0 && bktSettings.MFADeleteEnabled() {
serialNumber, token, err := h.getMFAHeader(r)
if err != nil {
h.logAndSendError(ctx, w, "could not get mfa header", reqInfo, err)
return
}
device, err := h.mfa.GetMFADevice(ctx, reqInfo.Namespace, nameFromArn(serialNumber))
if err != nil {
h.logAndSendError(ctx, w, "could not get mfa device", reqInfo, err)
return
}
validate := totp.Validate(token, device.Key.Secret())
if !validate {
h.logAndSendError(ctx, w, "could not validate token", reqInfo, fmt.Errorf("mfa Authentication must be used for this request"))
return
}
}
networkInfo, err := h.obj.GetNetworkInfo(ctx)
if err != nil {
h.logAndSendError(ctx, w, "could not get network info", reqInfo, err)
@ -186,6 +207,26 @@ func (h *handler) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Re
return
}
if haveVersionedObjects(requested.Objects) && bktSettings.MFADeleteEnabled() {
serialNumber, token, err := h.getMFAHeader(r)
if err != nil {
h.logAndSendError(ctx, w, "could not get mfa header", reqInfo, err)
return
}
device, err := h.mfa.GetMFADevice(ctx, reqInfo.Namespace, nameFromArn(serialNumber))
if err != nil {
h.logAndSendError(ctx, w, "could not get mfa device", reqInfo, err)
return
}
validate := totp.Validate(token, device.Key.Secret())
if !validate {
h.logAndSendError(ctx, w, "could not validate token", reqInfo, fmt.Errorf("mfa Authentication must be used for this request"))
return
}
}
networkInfo, err := h.obj.GetNetworkInfo(ctx)
if err != nil {
h.logAndSendError(ctx, w, "could not get network info", reqInfo, err)
@ -245,6 +286,12 @@ func (h *handler) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
return
}
bktSettings, err := h.obj.GetBucketSettings(ctx, bktInfo)
if err != nil {
h.logAndSendError(ctx, w, "could not get bucket settings", reqInfo, err)
return
}
if err = checkOwner(bktInfo, reqInfo.User); err != nil {
h.logAndSendError(ctx, w, "request owner id does not match bucket owner id", reqInfo, err)
return
@ -260,7 +307,7 @@ func (h *handler) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
skipObjCheck := false
if value, ok := r.Header[api.AmzForceBucketDelete]; ok {
s := value[0]
if s == "true" {
if s == "true" && !bktSettings.MFADeleteEnabled() {
skipObjCheck = true
}
}
@ -287,3 +334,12 @@ func (h *handler) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
func haveVersionedObjects(objects []ObjectIdentifier) bool {
for _, o := range objects {
if len(o.VersionID) > 0 {
return true
}
}
return false
}