fix: object lock behavior when default lock config is enabled (#9305)

This commit is contained in:
kannappanr 2020-04-13 14:03:23 -07:00 committed by GitHub
parent cc9b63eb51
commit 1fa65c7f2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 38 additions and 13 deletions

View file

@ -151,6 +151,7 @@ const (
ErrBadRequest ErrBadRequest
ErrKeyTooLongError ErrKeyTooLongError
ErrInvalidBucketObjectLockConfiguration ErrInvalidBucketObjectLockConfiguration
ErrObjectLockConfigurationNotFound
ErrObjectLockConfigurationNotAllowed ErrObjectLockConfigurationNotAllowed
ErrNoSuchObjectLockConfiguration ErrNoSuchObjectLockConfiguration
ErrObjectLocked ErrObjectLocked
@ -765,9 +766,14 @@ var errorCodes = errorCodeMap{
Description: "Bucket is missing ObjectLockConfiguration", Description: "Bucket is missing ObjectLockConfiguration",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
ErrObjectLockConfigurationNotFound: {
Code: "ObjectLockConfigurationNotFoundError",
Description: "Object Lock configuration does not exist for this bucket",
HTTPStatusCode: http.StatusNotFound,
},
ErrObjectLockConfigurationNotAllowed: { ErrObjectLockConfigurationNotAllowed: {
Code: "InvalidBucketState", Code: "InvalidBucketState",
Description: "Object Lock configuration cannot be enabled on existing buckets.", Description: "Object Lock configuration cannot be enabled on existing buckets",
HTTPStatusCode: http.StatusConflict, HTTPStatusCode: http.StatusConflict,
}, },
ErrNoSuchObjectLockConfiguration: { ErrNoSuchObjectLockConfiguration: {

View file

@ -591,6 +591,15 @@ func isPutActionAllowed(atype authType, bucketName, objectName string, r *http.R
return s3Err return s3Err
} }
// Do not check for PutObjectRetentionAction permission,
// if mode and retain until date are not set.
// Can happen when bucket has default lock config set
if action == iampolicy.PutObjectRetentionAction &&
r.Header.Get(xhttp.AmzObjectLockMode) == "" &&
r.Header.Get(xhttp.AmzObjectLockRetainUntilDate) == "" {
return ErrNone
}
if cred.AccessKey == "" { if cred.AccessKey == "" {
if globalPolicySys.IsAllowed(policy.Args{ if globalPolicySys.IsAllowed(policy.Args{
AccountName: cred.AccessKey, AccountName: cred.AccessKey,

View file

@ -1103,7 +1103,7 @@ func (api objectAPIHandlers) GetBucketObjectLockConfigHandler(w http.ResponseWri
if err != nil { if err != nil {
var aerr APIError var aerr APIError
if err == errConfigNotFound { if err == errConfigNotFound {
aerr = errorCodes.ToAPIErr(ErrMethodNotAllowed) aerr = errorCodes.ToAPIErr(ErrObjectLockConfigurationNotFound)
} else { } else {
aerr = toAPIError(ctx, err) aerr = toAPIError(ctx, err)
} }

View file

@ -1029,11 +1029,11 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
// apply default bucket configuration/governance headers for dest side. // apply default bucket configuration/governance headers for dest side.
retentionMode, retentionDate, legalHold, s3Err := checkPutObjectLockAllowed(ctx, r, dstBucket, dstObject, getObjectInfo, retPerms, holdPerms) retentionMode, retentionDate, legalHold, s3Err := checkPutObjectLockAllowed(ctx, r, dstBucket, dstObject, getObjectInfo, retPerms, holdPerms)
if s3Err == ErrNone && retentionMode.Valid() { if s3Err == ErrNone && retentionMode.Valid() {
srcInfo.UserDefined[xhttp.AmzObjectLockMode] = string(retentionMode) srcInfo.UserDefined[strings.ToLower(xhttp.AmzObjectLockMode)] = string(retentionMode)
srcInfo.UserDefined[xhttp.AmzObjectLockRetainUntilDate] = retentionDate.UTC().Format(time.RFC3339) srcInfo.UserDefined[strings.ToLower(xhttp.AmzObjectLockRetainUntilDate)] = retentionDate.UTC().Format(time.RFC3339)
} }
if s3Err == ErrNone && legalHold.Status.Valid() { if s3Err == ErrNone && legalHold.Status.Valid() {
srcInfo.UserDefined[xhttp.AmzObjectLockLegalHold] = string(legalHold.Status) srcInfo.UserDefined[strings.ToLower(xhttp.AmzObjectLockLegalHold)] = string(legalHold.Status)
} }
if s3Err != ErrNone { if s3Err != ErrNone {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL, guessIsBrowserReq(r))
@ -2398,11 +2398,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
} }
} }
// Enforce object lock governance in case a competing upload finalized first. if _, _, _, s3Err := checkPutObjectLockAllowed(ctx, r, bucket, object, objectAPI.GetObjectInfo, ErrNone, ErrNone); s3Err != ErrNone {
retPerms := isPutActionAllowed(getRequestAuthType(r), bucket, object, r, iampolicy.PutObjectRetentionAction)
holdPerms := isPutActionAllowed(getRequestAuthType(r), bucket, object, r, iampolicy.PutObjectLegalHoldAction)
if _, _, _, s3Err := checkPutObjectLockAllowed(ctx, r, bucket, object, objectAPI.GetObjectInfo, retPerms, holdPerms); s3Err != ErrNone {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL, guessIsBrowserReq(r))
return return
} }

View file

@ -335,7 +335,7 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re
for _, bucket := range buckets { for _, bucket := range buckets {
if globalIAMSys.IsAllowed(iampolicy.Args{ if globalIAMSys.IsAllowed(iampolicy.Args{
AccountName: claims.AccessKey, AccountName: claims.AccessKey,
Action: iampolicy.ListBucketAction, Action: iampolicy.ListAllMyBucketsAction,
BucketName: bucket.Name, BucketName: bucket.Name,
ConditionValues: getConditionValues(r, "", claims.AccessKey, claims.Map()), ConditionValues: getConditionValues(r, "", claims.AccessKey, claims.Map()),
IsOwner: owner, IsOwner: owner,

View file

@ -459,10 +459,21 @@ func GetObjectRetentionMeta(meta map[string]string) ObjectRetention {
var mode RetMode var mode RetMode
var retainTill RetentionDate var retainTill RetentionDate
if modeStr, ok := meta[strings.ToLower(AmzObjectLockMode)]; ok { var modeStr, tillStr string
ok := false
modeStr, ok = meta[strings.ToLower(AmzObjectLockMode)]
if !ok {
modeStr, ok = meta[AmzObjectLockMode]
}
if ok {
mode = parseRetMode(modeStr) mode = parseRetMode(modeStr)
} }
if tillStr, ok := meta[strings.ToLower(AmzObjectLockRetainUntilDate)]; ok { tillStr, ok = meta[strings.ToLower(AmzObjectLockRetainUntilDate)]
if !ok {
tillStr, ok = meta[AmzObjectLockRetainUntilDate]
}
if ok {
if t, e := time.Parse(time.RFC3339, tillStr); e == nil { if t, e := time.Parse(time.RFC3339, tillStr); e == nil {
retainTill = RetentionDate{t.UTC()} retainTill = RetentionDate{t.UTC()}
} }
@ -473,6 +484,9 @@ func GetObjectRetentionMeta(meta map[string]string) ObjectRetention {
// GetObjectLegalHoldMeta constructs ObjectLegalHold from metadata // GetObjectLegalHoldMeta constructs ObjectLegalHold from metadata
func GetObjectLegalHoldMeta(meta map[string]string) ObjectLegalHold { func GetObjectLegalHoldMeta(meta map[string]string) ObjectLegalHold {
holdStr, ok := meta[strings.ToLower(AmzObjectLockLegalHold)] holdStr, ok := meta[strings.ToLower(AmzObjectLockLegalHold)]
if !ok {
holdStr, ok = meta[AmzObjectLockLegalHold]
}
if ok { if ok {
return ObjectLegalHold{XMLNS: "http://s3.amazonaws.com/doc/2006-03-01/", Status: parseLegalHoldStatus(holdStr)} return ObjectLegalHold{XMLNS: "http://s3.amazonaws.com/doc/2006-03-01/", Status: parseLegalHoldStatus(holdStr)}
} }