aboutsummaryrefslogtreecommitdiff
path: root/weed/s3api/s3_sse_bucket_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/s3api/s3_sse_bucket_test.go')
-rw-r--r--weed/s3api/s3_sse_bucket_test.go401
1 files changed, 401 insertions, 0 deletions
diff --git a/weed/s3api/s3_sse_bucket_test.go b/weed/s3api/s3_sse_bucket_test.go
new file mode 100644
index 000000000..74ad9296b
--- /dev/null
+++ b/weed/s3api/s3_sse_bucket_test.go
@@ -0,0 +1,401 @@
+package s3api
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/seaweedfs/seaweedfs/weed/pb/s3_pb"
+)
+
+// TestBucketDefaultSSEKMSEnforcement tests bucket default encryption enforcement
+func TestBucketDefaultSSEKMSEnforcement(t *testing.T) {
+ kmsKey := SetupTestKMS(t)
+ defer kmsKey.Cleanup()
+
+ // Create bucket encryption configuration
+ config := &s3_pb.EncryptionConfiguration{
+ SseAlgorithm: "aws:kms",
+ KmsKeyId: kmsKey.KeyID,
+ BucketKeyEnabled: false,
+ }
+
+ t.Run("Bucket with SSE-KMS default encryption", func(t *testing.T) {
+ // Test that default encryption config is properly stored and retrieved
+ if config.SseAlgorithm != "aws:kms" {
+ t.Errorf("Expected SSE algorithm aws:kms, got %s", config.SseAlgorithm)
+ }
+
+ if config.KmsKeyId != kmsKey.KeyID {
+ t.Errorf("Expected KMS key ID %s, got %s", kmsKey.KeyID, config.KmsKeyId)
+ }
+ })
+
+ t.Run("Default encryption headers generation", func(t *testing.T) {
+ // Test generating default encryption headers for objects
+ headers := GetDefaultEncryptionHeaders(config)
+
+ if headers == nil {
+ t.Fatal("Expected default headers, got nil")
+ }
+
+ expectedAlgorithm := headers["X-Amz-Server-Side-Encryption"]
+ if expectedAlgorithm != "aws:kms" {
+ t.Errorf("Expected X-Amz-Server-Side-Encryption header aws:kms, got %s", expectedAlgorithm)
+ }
+
+ expectedKeyID := headers["X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id"]
+ if expectedKeyID != kmsKey.KeyID {
+ t.Errorf("Expected X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id header %s, got %s", kmsKey.KeyID, expectedKeyID)
+ }
+ })
+
+ t.Run("Default encryption detection", func(t *testing.T) {
+ // Test IsDefaultEncryptionEnabled
+ enabled := IsDefaultEncryptionEnabled(config)
+ if !enabled {
+ t.Error("Should detect default encryption as enabled")
+ }
+
+ // Test with nil config
+ enabled = IsDefaultEncryptionEnabled(nil)
+ if enabled {
+ t.Error("Should detect default encryption as disabled for nil config")
+ }
+
+ // Test with empty config
+ emptyConfig := &s3_pb.EncryptionConfiguration{}
+ enabled = IsDefaultEncryptionEnabled(emptyConfig)
+ if enabled {
+ t.Error("Should detect default encryption as disabled for empty config")
+ }
+ })
+}
+
+// TestBucketEncryptionConfigValidation tests XML validation of bucket encryption configurations
+func TestBucketEncryptionConfigValidation(t *testing.T) {
+ testCases := []struct {
+ name string
+ xml string
+ expectError bool
+ description string
+ }{
+ {
+ name: "Valid SSE-S3 configuration",
+ xml: `<ServerSideEncryptionConfiguration>
+ <Rule>
+ <ApplyServerSideEncryptionByDefault>
+ <SSEAlgorithm>AES256</SSEAlgorithm>
+ </ApplyServerSideEncryptionByDefault>
+ </Rule>
+ </ServerSideEncryptionConfiguration>`,
+ expectError: false,
+ description: "Basic SSE-S3 configuration should be valid",
+ },
+ {
+ name: "Valid SSE-KMS configuration",
+ xml: `<ServerSideEncryptionConfiguration>
+ <Rule>
+ <ApplyServerSideEncryptionByDefault>
+ <SSEAlgorithm>aws:kms</SSEAlgorithm>
+ <KMSMasterKeyID>test-key-id</KMSMasterKeyID>
+ </ApplyServerSideEncryptionByDefault>
+ </Rule>
+ </ServerSideEncryptionConfiguration>`,
+ expectError: false,
+ description: "SSE-KMS configuration with key ID should be valid",
+ },
+ {
+ name: "Valid SSE-KMS without key ID",
+ xml: `<ServerSideEncryptionConfiguration>
+ <Rule>
+ <ApplyServerSideEncryptionByDefault>
+ <SSEAlgorithm>aws:kms</SSEAlgorithm>
+ </ApplyServerSideEncryptionByDefault>
+ </Rule>
+ </ServerSideEncryptionConfiguration>`,
+ expectError: false,
+ description: "SSE-KMS without key ID should use default key",
+ },
+ {
+ name: "Invalid XML structure",
+ xml: `<ServerSideEncryptionConfiguration>
+ <InvalidRule>
+ <SSEAlgorithm>AES256</SSEAlgorithm>
+ </InvalidRule>
+ </ServerSideEncryptionConfiguration>`,
+ expectError: true,
+ description: "Invalid XML structure should be rejected",
+ },
+ {
+ name: "Empty configuration",
+ xml: `<ServerSideEncryptionConfiguration>
+ </ServerSideEncryptionConfiguration>`,
+ expectError: true,
+ description: "Empty configuration should be rejected",
+ },
+ {
+ name: "Invalid algorithm",
+ xml: `<ServerSideEncryptionConfiguration>
+ <Rule>
+ <ApplyServerSideEncryptionByDefault>
+ <SSEAlgorithm>INVALID</SSEAlgorithm>
+ </ApplyServerSideEncryptionByDefault>
+ </Rule>
+ </ServerSideEncryptionConfiguration>`,
+ expectError: true,
+ description: "Invalid algorithm should be rejected",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ config, err := encryptionConfigFromXMLBytes([]byte(tc.xml))
+
+ if tc.expectError && err == nil {
+ t.Errorf("Expected error for %s, but got none. %s", tc.name, tc.description)
+ }
+
+ if !tc.expectError && err != nil {
+ t.Errorf("Expected no error for %s, but got: %v. %s", tc.name, err, tc.description)
+ }
+
+ if !tc.expectError && config != nil {
+ // Validate the parsed configuration
+ t.Logf("Successfully parsed config: Algorithm=%s, KeyID=%s",
+ config.SseAlgorithm, config.KmsKeyId)
+ }
+ })
+ }
+}
+
+// TestBucketEncryptionAPIOperations tests the bucket encryption API operations
+func TestBucketEncryptionAPIOperations(t *testing.T) {
+ // Note: These tests would normally require a full S3 API server setup
+ // For now, we test the individual components
+
+ t.Run("PUT bucket encryption", func(t *testing.T) {
+ xml := `<ServerSideEncryptionConfiguration>
+ <Rule>
+ <ApplyServerSideEncryptionByDefault>
+ <SSEAlgorithm>aws:kms</SSEAlgorithm>
+ <KMSMasterKeyID>test-key-id</KMSMasterKeyID>
+ </ApplyServerSideEncryptionByDefault>
+ </Rule>
+ </ServerSideEncryptionConfiguration>`
+
+ // Parse the XML to protobuf
+ config, err := encryptionConfigFromXMLBytes([]byte(xml))
+ if err != nil {
+ t.Fatalf("Failed to parse encryption config: %v", err)
+ }
+
+ // Verify the parsed configuration
+ if config.SseAlgorithm != "aws:kms" {
+ t.Errorf("Expected algorithm aws:kms, got %s", config.SseAlgorithm)
+ }
+
+ if config.KmsKeyId != "test-key-id" {
+ t.Errorf("Expected key ID test-key-id, got %s", config.KmsKeyId)
+ }
+
+ // Convert back to XML
+ xmlBytes, err := encryptionConfigToXMLBytes(config)
+ if err != nil {
+ t.Fatalf("Failed to convert config to XML: %v", err)
+ }
+
+ // Verify round-trip
+ if len(xmlBytes) == 0 {
+ t.Error("Generated XML should not be empty")
+ }
+
+ // Parse again to verify
+ roundTripConfig, err := encryptionConfigFromXMLBytes(xmlBytes)
+ if err != nil {
+ t.Fatalf("Failed to parse round-trip XML: %v", err)
+ }
+
+ if roundTripConfig.SseAlgorithm != config.SseAlgorithm {
+ t.Error("Round-trip algorithm doesn't match")
+ }
+
+ if roundTripConfig.KmsKeyId != config.KmsKeyId {
+ t.Error("Round-trip key ID doesn't match")
+ }
+ })
+
+ t.Run("GET bucket encryption", func(t *testing.T) {
+ // Test getting encryption configuration
+ config := &s3_pb.EncryptionConfiguration{
+ SseAlgorithm: "AES256",
+ KmsKeyId: "",
+ BucketKeyEnabled: false,
+ }
+
+ // Convert to XML for GET response
+ xmlBytes, err := encryptionConfigToXMLBytes(config)
+ if err != nil {
+ t.Fatalf("Failed to convert config to XML: %v", err)
+ }
+
+ if len(xmlBytes) == 0 {
+ t.Error("Generated XML should not be empty")
+ }
+
+ // Verify XML contains expected elements
+ xmlStr := string(xmlBytes)
+ if !strings.Contains(xmlStr, "AES256") {
+ t.Error("XML should contain AES256 algorithm")
+ }
+ })
+
+ t.Run("DELETE bucket encryption", func(t *testing.T) {
+ // Test deleting encryption configuration
+ // This would typically involve removing the configuration from metadata
+
+ // Simulate checking if encryption is enabled after deletion
+ enabled := IsDefaultEncryptionEnabled(nil)
+ if enabled {
+ t.Error("Encryption should be disabled after deletion")
+ }
+ })
+}
+
+// TestBucketEncryptionEdgeCases tests edge cases in bucket encryption
+func TestBucketEncryptionEdgeCases(t *testing.T) {
+ t.Run("Large XML configuration", func(t *testing.T) {
+ // Test with a large but valid XML
+ largeXML := `<ServerSideEncryptionConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
+ <Rule>
+ <ApplyServerSideEncryptionByDefault>
+ <SSEAlgorithm>aws:kms</SSEAlgorithm>
+ <KMSMasterKeyID>arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012</KMSMasterKeyID>
+ </ApplyServerSideEncryptionByDefault>
+ <BucketKeyEnabled>true</BucketKeyEnabled>
+ </Rule>
+ </ServerSideEncryptionConfiguration>`
+
+ config, err := encryptionConfigFromXMLBytes([]byte(largeXML))
+ if err != nil {
+ t.Fatalf("Failed to parse large XML: %v", err)
+ }
+
+ if config.SseAlgorithm != "aws:kms" {
+ t.Error("Should parse large XML correctly")
+ }
+ })
+
+ t.Run("XML with namespaces", func(t *testing.T) {
+ // Test XML with namespaces
+ namespacedXML := `<ServerSideEncryptionConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
+ <Rule>
+ <ApplyServerSideEncryptionByDefault>
+ <SSEAlgorithm>AES256</SSEAlgorithm>
+ </ApplyServerSideEncryptionByDefault>
+ </Rule>
+ </ServerSideEncryptionConfiguration>`
+
+ config, err := encryptionConfigFromXMLBytes([]byte(namespacedXML))
+ if err != nil {
+ t.Fatalf("Failed to parse namespaced XML: %v", err)
+ }
+
+ if config.SseAlgorithm != "AES256" {
+ t.Error("Should parse namespaced XML correctly")
+ }
+ })
+
+ t.Run("Malformed XML", func(t *testing.T) {
+ malformedXMLs := []string{
+ `<ServerSideEncryptionConfiguration><Rule><SSEAlgorithm>AES256</Rule>`, // Unclosed tags
+ `<ServerSideEncryptionConfiguration><Rule></Rule></ServerSideEncryptionConfiguration>`, // Empty rule
+ `not-xml-at-all`, // Not XML
+ `<ServerSideEncryptionConfiguration xmlns="invalid-namespace"><Rule><ApplyServerSideEncryptionByDefault><SSEAlgorithm>AES256</SSEAlgorithm></ApplyServerSideEncryptionByDefault></Rule></ServerSideEncryptionConfiguration>`, // Invalid namespace
+ }
+
+ for i, malformedXML := range malformedXMLs {
+ t.Run(fmt.Sprintf("Malformed XML %d", i), func(t *testing.T) {
+ _, err := encryptionConfigFromXMLBytes([]byte(malformedXML))
+ if err == nil {
+ t.Errorf("Expected error for malformed XML %d, but got none", i)
+ }
+ })
+ }
+ })
+}
+
+// TestGetDefaultEncryptionHeaders tests generation of default encryption headers
+func TestGetDefaultEncryptionHeaders(t *testing.T) {
+ testCases := []struct {
+ name string
+ config *s3_pb.EncryptionConfiguration
+ expectedHeaders map[string]string
+ }{
+ {
+ name: "Nil configuration",
+ config: nil,
+ expectedHeaders: nil,
+ },
+ {
+ name: "SSE-S3 configuration",
+ config: &s3_pb.EncryptionConfiguration{
+ SseAlgorithm: "AES256",
+ },
+ expectedHeaders: map[string]string{
+ "X-Amz-Server-Side-Encryption": "AES256",
+ },
+ },
+ {
+ name: "SSE-KMS configuration with key",
+ config: &s3_pb.EncryptionConfiguration{
+ SseAlgorithm: "aws:kms",
+ KmsKeyId: "test-key-id",
+ },
+ expectedHeaders: map[string]string{
+ "X-Amz-Server-Side-Encryption": "aws:kms",
+ "X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": "test-key-id",
+ },
+ },
+ {
+ name: "SSE-KMS configuration without key",
+ config: &s3_pb.EncryptionConfiguration{
+ SseAlgorithm: "aws:kms",
+ },
+ expectedHeaders: map[string]string{
+ "X-Amz-Server-Side-Encryption": "aws:kms",
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ headers := GetDefaultEncryptionHeaders(tc.config)
+
+ if tc.expectedHeaders == nil && headers != nil {
+ t.Error("Expected nil headers but got some")
+ }
+
+ if tc.expectedHeaders != nil && headers == nil {
+ t.Error("Expected headers but got nil")
+ }
+
+ if tc.expectedHeaders != nil && headers != nil {
+ for key, expectedValue := range tc.expectedHeaders {
+ if actualValue, exists := headers[key]; !exists {
+ t.Errorf("Expected header %s not found", key)
+ } else if actualValue != expectedValue {
+ t.Errorf("Header %s: expected %s, got %s", key, expectedValue, actualValue)
+ }
+ }
+
+ // Check for unexpected headers
+ for key := range headers {
+ if _, expected := tc.expectedHeaders[key]; !expected {
+ t.Errorf("Unexpected header found: %s", key)
+ }
+ }
+ }
+ })
+ }
+}