diff --git a/cmd/api-errors.go b/cmd/api-errors.go index eca4d0e09..81c026aff 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -151,6 +151,7 @@ const ( ErrBadRequest ErrKeyTooLongError ErrInvalidBucketObjectLockConfiguration + ErrObjectLockConfigurationNotFound ErrObjectLockConfigurationNotAllowed ErrNoSuchObjectLockConfiguration ErrObjectLocked @@ -765,9 +766,14 @@ var errorCodes = errorCodeMap{ Description: "Bucket is missing ObjectLockConfiguration", HTTPStatusCode: http.StatusBadRequest, }, + ErrObjectLockConfigurationNotFound: { + Code: "ObjectLockConfigurationNotFoundError", + Description: "Object Lock configuration does not exist for this bucket", + HTTPStatusCode: http.StatusNotFound, + }, ErrObjectLockConfigurationNotAllowed: { 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, }, ErrNoSuchObjectLockConfiguration: { diff --git a/cmd/auth-handler.go b/cmd/auth-handler.go index 7a7cd8113..1ce94df7d 100644 --- a/cmd/auth-handler.go +++ b/cmd/auth-handler.go @@ -591,6 +591,15 @@ func isPutActionAllowed(atype authType, bucketName, objectName string, r *http.R 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 globalPolicySys.IsAllowed(policy.Args{ AccountName: cred.AccessKey, diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 8210dc0cb..f41892de4 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -1103,7 +1103,7 @@ func (api objectAPIHandlers) GetBucketObjectLockConfigHandler(w http.ResponseWri if err != nil { var aerr APIError if err == errConfigNotFound { - aerr = errorCodes.ToAPIErr(ErrMethodNotAllowed) + aerr = errorCodes.ToAPIErr(ErrObjectLockConfigurationNotFound) } else { aerr = toAPIError(ctx, err) } diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index 39145e85a..3930a3119 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -1029,11 +1029,11 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re // apply default bucket configuration/governance headers for dest side. retentionMode, retentionDate, legalHold, s3Err := checkPutObjectLockAllowed(ctx, r, dstBucket, dstObject, getObjectInfo, retPerms, holdPerms) if s3Err == ErrNone && retentionMode.Valid() { - srcInfo.UserDefined[xhttp.AmzObjectLockMode] = string(retentionMode) - srcInfo.UserDefined[xhttp.AmzObjectLockRetainUntilDate] = retentionDate.UTC().Format(time.RFC3339) + srcInfo.UserDefined[strings.ToLower(xhttp.AmzObjectLockMode)] = string(retentionMode) + srcInfo.UserDefined[strings.ToLower(xhttp.AmzObjectLockRetainUntilDate)] = retentionDate.UTC().Format(time.RFC3339) } 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 { 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. - 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 { + if _, _, _, s3Err := checkPutObjectLockAllowed(ctx, r, bucket, object, objectAPI.GetObjectInfo, ErrNone, ErrNone); s3Err != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL, guessIsBrowserReq(r)) return } diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index 8a17ab4bc..1e81d638e 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -335,7 +335,7 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re for _, bucket := range buckets { if globalIAMSys.IsAllowed(iampolicy.Args{ AccountName: claims.AccessKey, - Action: iampolicy.ListBucketAction, + Action: iampolicy.ListAllMyBucketsAction, BucketName: bucket.Name, ConditionValues: getConditionValues(r, "", claims.AccessKey, claims.Map()), IsOwner: owner, diff --git a/pkg/bucket/object/lock/lock.go b/pkg/bucket/object/lock/lock.go index a5befd778..372680105 100644 --- a/pkg/bucket/object/lock/lock.go +++ b/pkg/bucket/object/lock/lock.go @@ -459,10 +459,21 @@ func GetObjectRetentionMeta(meta map[string]string) ObjectRetention { var mode RetMode 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) } - 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 { retainTill = RetentionDate{t.UTC()} } @@ -473,6 +484,9 @@ func GetObjectRetentionMeta(meta map[string]string) ObjectRetention { // GetObjectLegalHoldMeta constructs ObjectLegalHold from metadata func GetObjectLegalHoldMeta(meta map[string]string) ObjectLegalHold { holdStr, ok := meta[strings.ToLower(AmzObjectLockLegalHold)] + if !ok { + holdStr, ok = meta[AmzObjectLockLegalHold] + } if ok { return ObjectLegalHold{XMLNS: "http://s3.amazonaws.com/doc/2006-03-01/", Status: parseLegalHoldStatus(holdStr)} }