[#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

@ -1,6 +1,7 @@
package handler
import (
"fmt"
"net/http"
"git.frostfs.info/TrueCloudLab/frostfs-observability/tracing"
@ -8,6 +9,7 @@ import (
"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"
"github.com/pquerna/otp/totp"
)
func (h *handler) PutBucketVersioningHandler(w http.ResponseWriter, r *http.Request) {
@ -15,6 +17,7 @@ func (h *handler) PutBucketVersioningHandler(w http.ResponseWriter, r *http.Requ
defer span.End()
reqInfo := middleware.GetReqInfo(ctx)
var serialNumber, token string
configuration := new(VersioningConfiguration)
if err := h.cfg.NewXMLDecoder(r.Body, r.UserAgent()).Decode(configuration); err != nil {
@ -34,14 +37,49 @@ func (h *handler) PutBucketVersioningHandler(w http.ResponseWriter, r *http.Requ
return
}
newMfa := len(configuration.MfaDelete) > 0
if settings.MFADeleteEnabled() || newMfa {
serialNumber, token, err = h.getMFAHeader(r)
if err != nil {
h.logAndSendError(ctx, w, "invalid x-amz-mfa header", reqInfo, errors.GetAPIError(errors.ErrBadRequest))
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
}
}
// settings pointer is stored in the cache, so modify a copy of the settings
newSettings := *settings
if newMfa {
switch configuration.MfaDelete {
case data.MFADeleteEnabled:
newSettings.Versioning.MFADeleteStatus = data.MFADeleteEnabled
newSettings.Versioning.MFASerialNumber = serialNumber
case data.MFADeleteDisabled:
newSettings.Versioning.MFADeleteStatus = data.MFADeleteDisabled
default:
h.logAndSendError(ctx, w, "failed to get mfa configuration", reqInfo, nil)
return
}
}
if configuration.Status != data.VersioningEnabled && configuration.Status != data.VersioningSuspended {
h.logAndSendError(ctx, w, "invalid versioning configuration", reqInfo, errors.GetAPIError(errors.ErrMalformedXML))
return
}
// settings pointer is stored in the cache, so modify a copy of the settings
newSettings := *settings
newSettings.Versioning = configuration.Status
newSettings.Versioning.VersioningStatus = configuration.Status
p := &layer.PutSettingsParams{
BktInfo: bktInfo,
@ -85,7 +123,10 @@ func (h *handler) GetBucketVersioningHandler(w http.ResponseWriter, r *http.Requ
func formVersioningConfiguration(settings *data.BucketSettings) *VersioningConfiguration {
res := &VersioningConfiguration{}
if !settings.Unversioned() {
res.Status = settings.Versioning
res.Status = settings.Versioning.VersioningStatus
}
if settings.MFADeleteEnabled() {
res.MfaDelete = data.MFADeleteEnabled
}
return res