diff options
Diffstat (limited to 'weed/s3api/s3_bucket_policy_simple_test.go')
| -rw-r--r-- | weed/s3api/s3_bucket_policy_simple_test.go | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/weed/s3api/s3_bucket_policy_simple_test.go b/weed/s3api/s3_bucket_policy_simple_test.go new file mode 100644 index 000000000..025b44900 --- /dev/null +++ b/weed/s3api/s3_bucket_policy_simple_test.go @@ -0,0 +1,228 @@ +package s3api + +import ( + "encoding/json" + "testing" + + "github.com/seaweedfs/seaweedfs/weed/iam/policy" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestBucketPolicyValidationBasics tests the core validation logic +func TestBucketPolicyValidationBasics(t *testing.T) { + s3Server := &S3ApiServer{} + + tests := []struct { + name string + policy *policy.PolicyDocument + bucket string + expectedValid bool + expectedError string + }{ + { + name: "Valid bucket policy", + policy: &policy.PolicyDocument{ + Version: "2012-10-17", + Statement: []policy.Statement{ + { + Sid: "TestStatement", + Effect: "Allow", + Principal: map[string]interface{}{ + "AWS": "*", + }, + Action: []string{"s3:GetObject"}, + Resource: []string{ + "arn:seaweed:s3:::test-bucket/*", + }, + }, + }, + }, + bucket: "test-bucket", + expectedValid: true, + }, + { + name: "Policy without Principal (invalid)", + policy: &policy.PolicyDocument{ + Version: "2012-10-17", + Statement: []policy.Statement{ + { + Effect: "Allow", + Action: []string{"s3:GetObject"}, + Resource: []string{"arn:seaweed:s3:::test-bucket/*"}, + // Principal is missing + }, + }, + }, + bucket: "test-bucket", + expectedValid: false, + expectedError: "bucket policies must specify a Principal", + }, + { + name: "Invalid version", + policy: &policy.PolicyDocument{ + Version: "2008-10-17", // Wrong version + Statement: []policy.Statement{ + { + Effect: "Allow", + Principal: map[string]interface{}{ + "AWS": "*", + }, + Action: []string{"s3:GetObject"}, + Resource: []string{"arn:seaweed:s3:::test-bucket/*"}, + }, + }, + }, + bucket: "test-bucket", + expectedValid: false, + expectedError: "unsupported policy version", + }, + { + name: "Resource not matching bucket", + policy: &policy.PolicyDocument{ + Version: "2012-10-17", + Statement: []policy.Statement{ + { + Effect: "Allow", + Principal: map[string]interface{}{ + "AWS": "*", + }, + Action: []string{"s3:GetObject"}, + Resource: []string{"arn:seaweed:s3:::other-bucket/*"}, // Wrong bucket + }, + }, + }, + bucket: "test-bucket", + expectedValid: false, + expectedError: "does not match bucket", + }, + { + name: "Non-S3 action", + policy: &policy.PolicyDocument{ + Version: "2012-10-17", + Statement: []policy.Statement{ + { + Effect: "Allow", + Principal: map[string]interface{}{ + "AWS": "*", + }, + Action: []string{"iam:GetUser"}, // Non-S3 action + Resource: []string{"arn:seaweed:s3:::test-bucket/*"}, + }, + }, + }, + bucket: "test-bucket", + expectedValid: false, + expectedError: "bucket policies only support S3 actions", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := s3Server.validateBucketPolicy(tt.policy, tt.bucket) + + if tt.expectedValid { + assert.NoError(t, err, "Policy should be valid") + } else { + assert.Error(t, err, "Policy should be invalid") + if tt.expectedError != "" { + assert.Contains(t, err.Error(), tt.expectedError, "Error message should contain expected text") + } + } + }) + } +} + +// TestBucketResourceValidation tests the resource ARN validation +func TestBucketResourceValidation(t *testing.T) { + s3Server := &S3ApiServer{} + + tests := []struct { + name string + resource string + bucket string + valid bool + }{ + { + name: "Exact bucket ARN", + resource: "arn:seaweed:s3:::test-bucket", + bucket: "test-bucket", + valid: true, + }, + { + name: "Bucket wildcard ARN", + resource: "arn:seaweed:s3:::test-bucket/*", + bucket: "test-bucket", + valid: true, + }, + { + name: "Specific object ARN", + resource: "arn:seaweed:s3:::test-bucket/path/to/object.txt", + bucket: "test-bucket", + valid: true, + }, + { + name: "Different bucket ARN", + resource: "arn:seaweed:s3:::other-bucket/*", + bucket: "test-bucket", + valid: false, + }, + { + name: "Global S3 wildcard", + resource: "arn:seaweed:s3:::*", + bucket: "test-bucket", + valid: false, + }, + { + name: "Invalid ARN format", + resource: "invalid-arn", + bucket: "test-bucket", + valid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := s3Server.validateResourceForBucket(tt.resource, tt.bucket) + assert.Equal(t, tt.valid, result, "Resource validation result should match expected") + }) + } +} + +// TestBucketPolicyJSONSerialization tests policy JSON handling +func TestBucketPolicyJSONSerialization(t *testing.T) { + policy := &policy.PolicyDocument{ + Version: "2012-10-17", + Statement: []policy.Statement{ + { + Sid: "PublicReadGetObject", + Effect: "Allow", + Principal: map[string]interface{}{ + "AWS": "*", + }, + Action: []string{"s3:GetObject"}, + Resource: []string{ + "arn:seaweed:s3:::public-bucket/*", + }, + }, + }, + } + + // Test that policy can be marshaled and unmarshaled correctly + jsonData := marshalPolicy(t, policy) + assert.NotEmpty(t, jsonData, "JSON data should not be empty") + + // Verify the JSON contains expected elements + jsonStr := string(jsonData) + assert.Contains(t, jsonStr, "2012-10-17", "JSON should contain version") + assert.Contains(t, jsonStr, "s3:GetObject", "JSON should contain action") + assert.Contains(t, jsonStr, "arn:seaweed:s3:::public-bucket/*", "JSON should contain resource") + assert.Contains(t, jsonStr, "PublicReadGetObject", "JSON should contain statement ID") +} + +// Helper function for marshaling policies +func marshalPolicy(t *testing.T, policyDoc *policy.PolicyDocument) []byte { + data, err := json.Marshal(policyDoc) + require.NoError(t, err) + return data +} |
