| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- 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)
- }
- }
- }
- })
- }
- }
|