Merge pull request #568 from versity/fix/555-put-object-lock-config-disabled

PutObjectLockConfiguration default disabled object lock
This commit is contained in:
Ben McClelland
2024-05-16 08:51:44 -07:00
committed by GitHub
6 changed files with 101 additions and 22 deletions

View File

@@ -951,6 +951,20 @@ func (az *Azure) PutObjectLockConfiguration(ctx context.Context, bucket string,
return azureErrToS3Err(err)
}
cfg, exists := props.Metadata[string(keyBucketLock)]
if !exists {
return s3err.GetAPIError(s3err.ErrObjectLockConfigurationNotAllowed)
}
var bucketLockCfg auth.BucketLockConfig
if err := json.Unmarshal([]byte(*cfg), &bucketLockCfg); err != nil {
return fmt.Errorf("unmarshal object lock config: %w", err)
}
if !bucketLockCfg.Enabled {
return s3err.GetAPIError(s3err.ErrObjectLockConfigurationNotAllowed)
}
props.Metadata[string(keyBucketLock)] = backend.GetStringPtr(string(config))
_, err = client.SetMetadata(ctx, &container.SetMetadataOptions{

View File

@@ -2207,6 +2207,23 @@ func (p *Posix) PutObjectLockConfiguration(_ context.Context, bucket string, con
return fmt.Errorf("stat bucket: %w", err)
}
cfg, err := p.meta.RetrieveAttribute(bucket, "", bucketLockKey)
if errors.Is(err, meta.ErrNoSuchKey) {
return s3err.GetAPIError(s3err.ErrObjectLockConfigurationNotAllowed)
}
if err != nil {
return fmt.Errorf("get object lock config: %w", err)
}
var bucketLockCfg auth.BucketLockConfig
if err := json.Unmarshal(cfg, &bucketLockCfg); err != nil {
return fmt.Errorf("unmarshal object lock config: %w", err)
}
if !bucketLockCfg.Enabled {
return s3err.GetAPIError(s3err.ErrObjectLockConfigurationNotAllowed)
}
if err := p.meta.StoreAttribute(bucket, "", bucketLockKey, config); err != nil {
return fmt.Errorf("set object lock config: %w", err)
}

View File

@@ -115,6 +115,7 @@ const (
ErrObjectLockConfigurationNotFound
ErrNoSuchObjectLockConfiguration
ErrInvalidBucketObjectLockConfiguration
ErrObjectLockConfigurationNotAllowed
ErrObjectLocked
ErrPastObjectLockRetainDate
ErrNoSuchBucketPolicy
@@ -430,6 +431,11 @@ var errorCodeResponse = map[ErrorCode]APIError{
Description: "Bucket is missing ObjectLockConfiguration",
HTTPStatusCode: http.StatusBadRequest,
},
ErrObjectLockConfigurationNotAllowed: {
Code: "InvalidBucketState",
Description: "Object Lock configuration cannot be enabled on existing buckets",
HTTPStatusCode: http.StatusConflict,
},
ErrObjectLocked: {
Code: "InvalidRequest",
Description: "Object is WORM protected and cannot be overwritten",

View File

@@ -310,6 +310,7 @@ func TestDeleteBucketPolicy(s *S3Conf) {
func TestPutObjectLockConfiguration(s *S3Conf) {
PutObjectLockConfiguration_non_existing_bucket(s)
PutObjectLockConfiguration_empty_config(s)
PutObjectLockConfiguration_not_enabled_on_bucket_creation(s)
PutObjectLockConfiguration_both_years_and_days(s)
PutObjectLockConfiguration_success(s)
}
@@ -628,6 +629,7 @@ func GetIntTests() IntTests {
"DeleteBucketPolicy_success": DeleteBucketPolicy_success,
"PutObjectLockConfiguration_non_existing_bucket": PutObjectLockConfiguration_non_existing_bucket,
"PutObjectLockConfiguration_empty_config": PutObjectLockConfiguration_empty_config,
"PutObjectLockConfiguration_not_enabled_on_bucket_creation": PutObjectLockConfiguration_not_enabled_on_bucket_creation,
"PutObjectLockConfiguration_both_years_and_days": PutObjectLockConfiguration_both_years_and_days,
"PutObjectLockConfiguration_success": PutObjectLockConfiguration_success,
"GetObjectLockConfiguration_non_existing_bucket": GetObjectLockConfiguration_non_existing_bucket,

View File

@@ -6343,6 +6343,30 @@ func PutObjectLockConfiguration_empty_config(s *S3Conf) error {
})
}
func PutObjectLockConfiguration_not_enabled_on_bucket_creation(s *S3Conf) error {
testName := "PutObjectLockConfiguration_not_enabled_on_bucket_creation"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
var days int32 = 12
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.PutObjectLockConfiguration(ctx, &s3.PutObjectLockConfigurationInput{
Bucket: &bucket,
ObjectLockConfiguration: &types.ObjectLockConfiguration{
ObjectLockEnabled: types.ObjectLockEnabledEnabled,
Rule: &types.ObjectLockRule{
DefaultRetention: &types.DefaultRetention{
Days: &days,
},
},
},
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrObjectLockConfigurationNotAllowed)); err != nil {
return err
}
return nil
})
}
func PutObjectLockConfiguration_both_years_and_days(s *S3Conf) error {
testName := "PutObjectLockConfiguration_both_years_and_days"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
@@ -6383,7 +6407,7 @@ func PutObjectLockConfiguration_success(s *S3Conf) error {
return err
}
return nil
})
}, withLock())
}
func GetObjectLockConfiguration_non_existing_bucket(s *S3Conf) error {
@@ -6467,7 +6491,7 @@ func GetObjectLockConfiguration_success(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func PutObjectRetention_non_existing_bucket(s *S3Conf) error {
@@ -6510,7 +6534,7 @@ func PutObjectRetention_non_existing_object(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func PutObjectRetention_unset_bucket_object_lock_config(s *S3Conf) error {
@@ -6576,7 +6600,7 @@ func PutObjectRetention_disabled_bucket_object_lock_config(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func PutObjectRetention_expired_retain_until_date(s *S3Conf) error {
@@ -6603,7 +6627,7 @@ func PutObjectRetention_expired_retain_until_date(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func PutObjectRetention_success(s *S3Conf) error {
@@ -6639,7 +6663,7 @@ func PutObjectRetention_success(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func GetObjectRetention_non_existing_bucket(s *S3Conf) error {
@@ -6755,7 +6779,7 @@ func GetObjectRetention_success(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func PutObjectLegalHold_non_existing_bucket(s *S3Conf) error {
@@ -6796,7 +6820,7 @@ func PutObjectLegalHold_non_existing_object(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func PutObjectLegalHold_invalid_body(s *S3Conf) error {
@@ -6875,7 +6899,7 @@ func PutObjectLegalHold_disabled_bucket_object_lock_config(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func PutObjectLegalHold_success(s *S3Conf) error {
@@ -6909,7 +6933,7 @@ func PutObjectLegalHold_success(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func GetObjectLegalHold_non_existing_bucket(s *S3Conf) error {
@@ -7011,7 +7035,7 @@ func GetObjectLegalHold_success(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func WORMProtection_bucket_object_lock_configuration_compliance_mode(s *S3Conf) error {
@@ -7049,7 +7073,7 @@ func WORMProtection_bucket_object_lock_configuration_compliance_mode(s *S3Conf)
}
return nil
})
}, withLock())
}
func WORMProtection_bucket_object_lock_governance_root_overwrite(s *S3Conf) error {
@@ -7090,7 +7114,7 @@ func WORMProtection_bucket_object_lock_governance_root_overwrite(s *S3Conf) erro
}
return nil
})
}, withLock())
}
func WORMProtection_object_lock_retention_compliance_root_access_denied(s *S3Conf) error {
@@ -7129,7 +7153,7 @@ func WORMProtection_object_lock_retention_compliance_root_access_denied(s *S3Con
}
return nil
})
}, withLock())
}
func WORMProtection_object_lock_retention_governance_root_overwrite(s *S3Conf) error {
@@ -7169,7 +7193,7 @@ func WORMProtection_object_lock_retention_governance_root_overwrite(s *S3Conf) e
}
return nil
})
}, withLock())
}
func WORMProtection_object_lock_retention_governance_user_access_denied(s *S3Conf) error {
@@ -7226,7 +7250,7 @@ func WORMProtection_object_lock_retention_governance_user_access_denied(s *S3Con
}
return nil
})
}, withLock())
}
func WORMProtection_object_lock_legal_hold_user_access_denied(s *S3Conf) error {
@@ -7281,7 +7305,7 @@ func WORMProtection_object_lock_legal_hold_user_access_denied(s *S3Conf) error {
}
return nil
})
}, withLock())
}
func WORMProtection_object_lock_legal_hold_root_overwrite(s *S3Conf) error {
@@ -7319,7 +7343,7 @@ func WORMProtection_object_lock_legal_hold_root_overwrite(s *S3Conf) error {
}
return nil
})
}, withLock())
}
// Access control tests (with bucket ACLs and Policies)

View File

@@ -54,12 +54,18 @@ func getBucketName() string {
return fmt.Sprintf("test-bucket-%v", bcktCount)
}
func setup(s *S3Conf, bucket string) error {
func setup(s *S3Conf, bucket string, opts ...setupOpt) error {
s3client := s3.NewFromConfig(s.Config())
cfg := new(setupCfg)
for _, opt := range opts {
opt(cfg)
}
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.CreateBucket(ctx, &s3.CreateBucketInput{
Bucket: &bucket,
Bucket: &bucket,
ObjectLockEnabledForBucket: &cfg.LockEnabled,
})
cancel()
return err
@@ -113,10 +119,20 @@ func teardown(s *S3Conf, bucket string) error {
return err
}
func actionHandler(s *S3Conf, testName string, handler func(s3client *s3.Client, bucket string) error) error {
type setupCfg struct {
LockEnabled bool
}
type setupOpt func(*setupCfg)
func withLock() setupOpt {
return func(s *setupCfg) { s.LockEnabled = true }
}
func actionHandler(s *S3Conf, testName string, handler func(s3client *s3.Client, bucket string) error, opts ...setupOpt) error {
runF(testName)
bucketName := getBucketName()
err := setup(s, bucketName)
err := setup(s, bucketName, opts...)
if err != nil {
failF("%v: failed to create a bucket: %v", testName, err)
return fmt.Errorf("%v: failed to create a bucket: %w", testName, err)