diff --git a/weed/iam/integration/iam_manager.go b/weed/iam/integration/iam_manager.go index ccbb5ef00..61556e407 100644 --- a/weed/iam/integration/iam_manager.go +++ b/weed/iam/integration/iam_manager.go @@ -7,6 +7,7 @@ import ( "fmt" "strings" + "github.com/seaweedfs/seaweedfs/weed/glog" "github.com/seaweedfs/seaweedfs/weed/iam/policy" "github.com/seaweedfs/seaweedfs/weed/iam/providers" "github.com/seaweedfs/seaweedfs/weed/iam/sts" @@ -103,7 +104,15 @@ func (m *IAMManager) Initialize(config *IAMConfig, filerAddressProvider func() s // Initialize STS service m.stsService = sts.NewSTSService() - if err := m.stsService.Initialize(config.STS); err != nil { + + // Use default config if none provided + stsConfig := config.STS + if stsConfig == nil { + glog.V(1).Infof("No STS configuration provided, using defaults") + stsConfig = sts.DefaultSTSConfig() + } + + if err := m.stsService.Initialize(stsConfig); err != nil { return fmt.Errorf("failed to initialize STS service: %w", err) } diff --git a/weed/iam/integration/iam_manager_sts_test.go b/weed/iam/integration/iam_manager_sts_test.go new file mode 100644 index 000000000..05d21b5df --- /dev/null +++ b/weed/iam/integration/iam_manager_sts_test.go @@ -0,0 +1,108 @@ +package integration + +import ( + "testing" + "time" + + "github.com/seaweedfs/seaweedfs/weed/iam/policy" + "github.com/seaweedfs/seaweedfs/weed/iam/sts" +) + +// TestIAMManagerInitializeWithoutSTSConfig tests that IAM manager can initialize +// without an explicit STS configuration by using defaults +func TestIAMManagerInitializeWithoutSTSConfig(t *testing.T) { + manager := NewIAMManager() + + // Create config without STS section (nil) + // But with minimal policy and role configs to satisfy other components + config := &IAMConfig{ + STS: nil, // No STS config provided - will use defaults + Policy: &policy.PolicyEngineConfig{ + DefaultEffect: "Deny", + StoreType: "memory", + }, + Roles: &RoleStoreConfig{ + StoreType: "memory", + }, + } + + // Initialize should succeed with default STS config + err := manager.Initialize(config, func() string { return "localhost:8888" }) + if err != nil { + t.Fatalf("Failed to initialize IAM manager without STS config: %v", err) + } + + // Verify STS service is initialized + stsService := manager.GetSTSService() + if stsService == nil { + t.Fatal("STS service is nil after initialization") + } + + if !stsService.IsInitialized() { + t.Fatal("STS service is not initialized") + } + + // Verify the default config was applied + if stsService.Config.Issuer != "seaweedfs-sts" { + t.Errorf("Expected default issuer 'seaweedfs-sts', got '%s'", stsService.Config.Issuer) + } + + if stsService.Config.TokenDuration.Duration != 1*time.Hour { + t.Errorf("Expected default token duration 1h, got %v", stsService.Config.TokenDuration.Duration) + } + + if stsService.Config.MaxSessionLength.Duration != 12*time.Hour { + t.Errorf("Expected default max session length 12h, got %v", stsService.Config.MaxSessionLength.Duration) + } + + t.Logf("Successfully initialized STS service with default configuration") +} + +// TestIAMManagerInitializeWithExplicitSTSConfig tests that explicit STS config still works +func TestIAMManagerInitializeWithExplicitSTSConfig(t *testing.T) { + manager := NewIAMManager() + + // Create config with explicit STS section + config := &IAMConfig{ + STS: &sts.STSConfig{ + TokenDuration: sts.FlexibleDuration{Duration: 30 * time.Minute}, + MaxSessionLength: sts.FlexibleDuration{Duration: 2 * time.Hour}, + Issuer: "custom-issuer", + SigningKey: []byte("custom-signing-key-for-testing-purposes-only"), + AccountId: "999888777666", + }, + Policy: &policy.PolicyEngineConfig{ + DefaultEffect: "Deny", + StoreType: "memory", + }, + Roles: &RoleStoreConfig{ + StoreType: "memory", + }, + } + + // Initialize should succeed with explicit config + err := manager.Initialize(config, func() string { return "localhost:8888" }) + if err != nil { + t.Fatalf("Failed to initialize IAM manager with explicit STS config: %v", err) + } + + // Verify STS service uses the custom config + stsService := manager.GetSTSService() + if stsService == nil { + t.Fatal("STS service is nil after initialization") + } + + if !stsService.IsInitialized() { + t.Fatal("STS service is not initialized") + } + + if stsService.Config.Issuer != "custom-issuer" { + t.Errorf("Expected issuer 'custom-issuer', got '%s'", stsService.Config.Issuer) + } + + if stsService.Config.AccountId != "999888777666" { + t.Errorf("Expected account ID '999888777666', got '%s'", stsService.Config.AccountId) + } + + t.Logf("Successfully initialized STS service with explicit configuration") +} diff --git a/weed/iam/sts/sts_service.go b/weed/iam/sts/sts_service.go index ffbd69e27..43845bf41 100644 --- a/weed/iam/sts/sts_service.go +++ b/weed/iam/sts/sts_service.go @@ -2,6 +2,7 @@ package sts import ( "context" + "crypto/rand" "encoding/json" "errors" "fmt" @@ -258,6 +259,28 @@ func NewSTSService() *STSService { } } +// DefaultSTSConfig returns a default STS configuration with sensible defaults +// This ensures the STS service can be initialized even when no explicit configuration is provided +func DefaultSTSConfig() *STSConfig { + // Generate a secure random signing key + signingKey := make([]byte, 32) // 256 bits + if _, err := rand.Read(signingKey); err != nil { + // Fallback to a warning message if random generation fails + // This should never happen in practice, but we handle it defensively + glog.Warningf("Failed to generate random signing key, using deterministic fallback: %v", err) + signingKey = []byte("default-signing-key-change-in-production-environments") + } + + return &STSConfig{ + TokenDuration: FlexibleDuration{Duration: 1 * time.Hour}, // 1 hour default + MaxSessionLength: FlexibleDuration{Duration: 12 * time.Hour}, // 12 hours max + Issuer: "seaweedfs-sts", + SigningKey: signingKey, + AccountId: "111122223333", // Default AWS account ID + Providers: nil, // No providers by default + } +} + // Initialize initializes the STS service with configuration func (s *STSService) Initialize(config *STSConfig) error { if config == nil {