package s3api import ( "context" "sync" "testing" "github.com/seaweedfs/seaweedfs/weed/credential" _ "github.com/seaweedfs/seaweedfs/weed/credential/memory" "github.com/seaweedfs/seaweedfs/weed/filer" "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb" "github.com/seaweedfs/seaweedfs/weed/pb/iam_pb" ) func TestOnIamConfigChangeLegacyIdentityDeletionReloadsConfiguration(t *testing.T) { s3a := newTestS3ApiServerWithMemoryIAM(t, []*iam_pb.Identity{ { Name: "anonymous", Actions: []string{ "Read:test", }, }, }) err := s3a.onIamConfigChange( filer.IamConfigDirectory, &filer_pb.Entry{Name: filer.IamIdentityFile}, nil, ) if err != nil { t.Fatalf("onIamConfigChange returned error for legacy identity deletion: %v", err) } if !hasIdentity(s3a.iam, "anonymous") { t.Fatalf("expected anonymous identity to remain loaded after legacy identity deletion event") } } func TestOnIamConfigChangeReloadsOnIamIdentityDirectoryChanges(t *testing.T) { s3a := newTestS3ApiServerWithMemoryIAM(t, []*iam_pb.Identity{ {Name: "anonymous"}, }) // Seed initial in-memory IAM state. if err := s3a.iam.LoadS3ApiConfigurationFromCredentialManager(); err != nil { t.Fatalf("failed to load initial IAM configuration: %v", err) } if hasIdentity(s3a.iam, "alice") { t.Fatalf("did not expect alice identity before creating user") } if err := s3a.iam.credentialManager.CreateUser(context.Background(), &iam_pb.Identity{Name: "alice"}); err != nil { t.Fatalf("failed to create alice in memory credential manager: %v", err) } err := s3a.onIamConfigChange( filer.IamConfigDirectory+"/identities", nil, &filer_pb.Entry{Name: "alice.json"}, ) if err != nil { t.Fatalf("onIamConfigChange returned error for identities directory update: %v", err) } if !hasIdentity(s3a.iam, "alice") { t.Fatalf("expected alice identity to be loaded after /etc/iam/identities update") } } func newTestS3ApiServerWithMemoryIAM(t *testing.T, identities []*iam_pb.Identity) *S3ApiServer { t.Helper() // Create S3ApiConfiguration for test with provided identities config := &iam_pb.S3ApiConfiguration{ Identities: identities, Accounts: []*iam_pb.Account{}, ServiceAccounts: []*iam_pb.ServiceAccount{}, } // Create memory credential manager cm, err := credential.NewCredentialManager(credential.StoreTypeMemory, nil, "") if err != nil { t.Fatalf("failed to create memory credential manager: %v", err) } // Save test configuration if err := cm.SaveConfiguration(context.Background(), config); err != nil { t.Fatalf("failed to save test configuration: %v", err) } // Create a test IAM instance iam := &IdentityAccessManagement{ m: sync.RWMutex{}, nameToIdentity: make(map[string]*Identity), accessKeyIdent: make(map[string]*Identity), identities: []*Identity{}, policies: make(map[string]*iam_pb.Policy), accounts: make(map[string]*Account), emailAccount: make(map[string]*Account), hashes: make(map[string]*sync.Pool), hashCounters: make(map[string]*int32), isAuthEnabled: false, stopChan: make(chan struct{}), useStaticConfig: false, credentialManager: cm, } // Load test configuration if err := iam.ReplaceS3ApiConfiguration(config); err != nil { t.Fatalf("failed to load test configuration: %v", err) } return &S3ApiServer{ iam: iam, } } func hasIdentity(iam *IdentityAccessManagement, identityName string) bool { iam.m.RLock() defer iam.m.RUnlock() _, ok := iam.nameToIdentity[identityName] return ok }