mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-01 20:26:27 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fc2fefb4a | ||
|
|
6e393f3326 | ||
|
|
7939e5808e |
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package s3api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -435,11 +437,33 @@ func (s3a *S3ApiServer) UnifiedPostHandler(w http.ResponseWriter, r *http.Reques
|
||||
}
|
||||
|
||||
// 2. Parse Form to get Action
|
||||
// Save the body first so we can restore it for STS handler signature verification
|
||||
var bodyBytes []byte
|
||||
if r.Body != nil {
|
||||
// Limit body size to prevent DoS attacks
|
||||
r.Body = http.MaxBytesReader(w, r.Body, iamRequestBodyLimit)
|
||||
var err error
|
||||
bodyBytes, err = io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to read request body: %v", err)
|
||||
s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
|
||||
return
|
||||
}
|
||||
r.Body.Close()
|
||||
// Restore body for ParseForm
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
}
|
||||
|
||||
if err := r.ParseForm(); err != nil {
|
||||
s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Restore body again for downstream handlers (STS needs it for signature verification)
|
||||
if bodyBytes != nil {
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
}
|
||||
|
||||
// 3. Dispatch
|
||||
action := r.Form.Get("Action")
|
||||
if strings.HasPrefix(action, "AssumeRole") {
|
||||
|
||||
Reference in New Issue
Block a user