Custom Policies for Buckets (#1332)

* custom policies

* fixing error

* add formatting
This commit is contained in:
adfost
2021-12-28 18:21:29 -08:00
committed by GitHub
parent 10b8a93b5e
commit b2f38200f7
9 changed files with 116 additions and 46 deletions

View File

@@ -3735,6 +3735,9 @@ func init() {
"creation_date": {
"type": "string"
},
"definition": {
"type": "string"
},
"details": {
"type": "object",
"properties": {
@@ -5294,6 +5297,9 @@ func init() {
"properties": {
"access": {
"$ref": "#/definitions/bucketAccess"
},
"definition": {
"type": "string"
}
}
},
@@ -9626,6 +9632,9 @@ func init() {
"creation_date": {
"type": "string"
},
"definition": {
"type": "string"
},
"details": {
"type": "object",
"properties": {
@@ -11185,6 +11194,9 @@ func init() {
"properties": {
"access": {
"$ref": "#/definitions/bucketAccess"
},
"definition": {
"type": "string"
}
}
},

View File

@@ -436,7 +436,7 @@ func getMakeBucketResponse(session *models.Principal, br *models.MakeBucketReque
}
// setBucketAccessPolicy set the access permissions on an existing bucket.
func setBucketAccessPolicy(ctx context.Context, client MinioClient, bucketName string, access models.BucketAccess) error {
func setBucketAccessPolicy(ctx context.Context, client MinioClient, bucketName string, access models.BucketAccess, policyDefinition string) error {
if strings.TrimSpace(bucketName) == "" {
return fmt.Errorf("error: bucket name not present")
}
@@ -444,18 +444,21 @@ func setBucketAccessPolicy(ctx context.Context, client MinioClient, bucketName s
return fmt.Errorf("error: bucket access not present")
}
// Prepare policyJSON corresponding to the access type
if access != models.BucketAccessPRIVATE && access != models.BucketAccessPUBLIC {
if access != models.BucketAccessPRIVATE && access != models.BucketAccessPUBLIC && access != models.BucketAccessCUSTOM {
return fmt.Errorf("access: `%s` not supported", access)
}
bucketPolicy := consoleAccess2policyAccess(access)
bucketAccessPolicy := policy.BucketAccessPolicy{Version: minioIAMPolicy.DefaultVersion}
if access == models.BucketAccessCUSTOM {
err := client.setBucketPolicyWithContext(ctx, bucketName, policyDefinition)
if err != nil {
return err
}
return nil
}
bucketPolicy := consoleAccess2policyAccess(access)
bucketAccessPolicy.Statements = policy.SetPolicy(bucketAccessPolicy.Statements,
bucketPolicy, bucketName, "")
// implemented like minio/mc/ s3Client.SetAccess()
if len(bucketAccessPolicy.Statements) == 0 {
return client.setBucketPolicyWithContext(ctx, bucketName, "")
}
policyJSON, err := json.Marshal(bucketAccessPolicy)
if err != nil {
return err
@@ -469,6 +472,7 @@ func getBucketSetPolicyResponse(session *models.Principal, bucketName string, re
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel()
// get updated bucket details and return it
mClient, err := newMinioClient(session)
if err != nil {
return nil, prepareError(err)
@@ -476,11 +480,11 @@ func getBucketSetPolicyResponse(session *models.Principal, bucketName string, re
// create a minioClient interface implementation
// defining the client to be used
minioClient := minioClient{client: mClient}
// set bucket access policy
if err := setBucketAccessPolicy(ctx, minioClient, bucketName, *req.Access); err != nil {
if err := setBucketAccessPolicy(ctx, minioClient, bucketName, *req.Access, req.Definition); err != nil {
return nil, prepareError(err)
}
// get updated bucket details and return it
// set bucket access policy
bucket, err := getBucketInfo(ctx, minioClient, bucketName)
if err != nil {
return nil, prepareError(err)
@@ -548,19 +552,19 @@ func getBucketInfo(ctx context.Context, client MinioClient, bucketName string) (
LogError("error getting bucket policy: %v", err)
}
var policyAccess policy.BucketPolicy
if policyStr == "" {
policyAccess = policy.BucketPolicyNone
bucketAccess = models.BucketAccessPRIVATE
} else {
var p policy.BucketAccessPolicy
if err = json.Unmarshal([]byte(policyStr), &p); err != nil {
return nil, err
}
policyAccess = policy.GetPolicy(p.Statements, bucketName, "")
}
bucketAccess = policyAccess2consoleAccess(policyAccess)
if bucketAccess == models.BucketAccessPRIVATE && policyStr != "" {
bucketAccess = models.BucketAccessCUSTOM
policyAccess := policy.GetPolicy(p.Statements, bucketName, "")
if len(p.Statements) > 0 && policyAccess == policy.BucketPolicyNone {
bucketAccess = models.BucketAccessCUSTOM
} else {
bucketAccess = policyAccess2consoleAccess(policyAccess)
}
}
bucketTags, err := client.GetBucketTagging(ctx, bucketName)
if err != nil {
@@ -574,6 +578,7 @@ func getBucketInfo(ctx context.Context, client MinioClient, bucketName string) (
return &models.Bucket{
Name: &bucketName,
Access: &bucketAccess,
Definition: policyStr,
CreationDate: "", // to be implemented
Size: 0, // to be implemented
Details: bucketDetails,

View File

@@ -338,8 +338,8 @@ func TestBucketInfo(t *testing.T) {
assert.Equal(outputExpected.CreationDate, bucketInfo.CreationDate)
assert.Equal(outputExpected.Size, bucketInfo.Size)
// Test-3: getBucketInfo() get a bucket with CUSTOM access
// if bucket has a custom policy set it should return CUSTOM
// Test-3: getBucketInfo() get a bucket with PRIVATE access
// if bucket has a null statement, the the bucket is PRIVATE
mockPolicy = "{\"Version\":\"2012-10-17\",\"Statement\":[]}"
minioGetBucketPolicyMock = func(bucketName string) (string, error) {
return mockPolicy, nil
@@ -347,7 +347,7 @@ func TestBucketInfo(t *testing.T) {
bucketToSet = "csbucket"
outputExpected = &models.Bucket{
Name: swag.String(bucketToSet),
Access: models.NewBucketAccess(models.BucketAccessCUSTOM),
Access: models.NewBucketAccess(models.BucketAccessPRIVATE),
CreationDate: "", // to be implemented
Size: 0, // to be implemented
}
@@ -393,27 +393,27 @@ func TestSetBucketAccess(t *testing.T) {
minioSetBucketPolicyWithContextMock = func(ctx context.Context, bucketName, policy string) error {
return nil
}
if err := setBucketAccessPolicy(ctx, minClient, "bucktest1", models.BucketAccessPUBLIC); err != nil {
if err := setBucketAccessPolicy(ctx, minClient, "bucktest1", models.BucketAccessPUBLIC, ""); err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
// Test-2: setBucketAccessPolicy() set private access
if err := setBucketAccessPolicy(ctx, minClient, "bucktest1", models.BucketAccessPRIVATE); err != nil {
if err := setBucketAccessPolicy(ctx, minClient, "bucktest1", models.BucketAccessPRIVATE, ""); err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
// Test-3: setBucketAccessPolicy() set invalid access, expected error
if err := setBucketAccessPolicy(ctx, minClient, "bucktest1", "other"); assert.Error(err) {
if err := setBucketAccessPolicy(ctx, minClient, "bucktest1", "other", ""); assert.Error(err) {
assert.Equal("access: `other` not supported", err.Error())
}
// Test-4: setBucketAccessPolicy() set access on empty bucket name, expected error
if err := setBucketAccessPolicy(ctx, minClient, "", models.BucketAccessPRIVATE); assert.Error(err) {
if err := setBucketAccessPolicy(ctx, minClient, "", models.BucketAccessPRIVATE, ""); assert.Error(err) {
assert.Equal("error: bucket name not present", err.Error())
}
// Test-5: setBucketAccessPolicy() set empty access on bucket, expected error
if err := setBucketAccessPolicy(ctx, minClient, "bucktest1", ""); assert.Error(err) {
if err := setBucketAccessPolicy(ctx, minClient, "bucktest1", "", ""); assert.Error(err) {
assert.Equal("error: bucket access not present", err.Error())
}
@@ -421,7 +421,7 @@ func TestSetBucketAccess(t *testing.T) {
minioSetBucketPolicyWithContextMock = func(ctx context.Context, bucketName, policy string) error {
return errors.New("error")
}
if err := setBucketAccessPolicy(ctx, minClient, "bucktest1", models.BucketAccessPUBLIC); assert.Error(err) {
if err := setBucketAccessPolicy(ctx, minClient, "bucktest1", models.BucketAccessPUBLIC, ""); assert.Error(err) {
assert.Equal("error", err.Error())
}