| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- package memory
- import (
- "context"
- "encoding/json"
- "fmt"
- "github.com/seaweedfs/seaweedfs/weed/credential"
- "github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
- )
- func (store *MemoryStore) LoadConfiguration(ctx context.Context) (*iam_pb.S3ApiConfiguration, error) {
- store.mu.RLock()
- defer store.mu.RUnlock()
- if !store.initialized {
- return nil, fmt.Errorf("store not initialized")
- }
- config := &iam_pb.S3ApiConfiguration{}
- // Convert all users to identities
- for _, user := range store.users {
- // Deep copy the identity to avoid mutation issues
- identityCopy := store.deepCopyIdentity(user)
- config.Identities = append(config.Identities, identityCopy)
- }
- return config, nil
- }
- func (store *MemoryStore) SaveConfiguration(ctx context.Context, config *iam_pb.S3ApiConfiguration) error {
- store.mu.Lock()
- defer store.mu.Unlock()
- if !store.initialized {
- return fmt.Errorf("store not initialized")
- }
- // Clear existing data
- store.users = make(map[string]*iam_pb.Identity)
- store.accessKeys = make(map[string]string)
- // Add all identities
- for _, identity := range config.Identities {
- // Deep copy to avoid mutation issues
- identityCopy := store.deepCopyIdentity(identity)
- store.users[identity.Name] = identityCopy
- // Index access keys
- for _, credential := range identity.Credentials {
- store.accessKeys[credential.AccessKey] = identity.Name
- }
- }
- return nil
- }
- func (store *MemoryStore) CreateUser(ctx context.Context, identity *iam_pb.Identity) error {
- store.mu.Lock()
- defer store.mu.Unlock()
- if !store.initialized {
- return fmt.Errorf("store not initialized")
- }
- if _, exists := store.users[identity.Name]; exists {
- return credential.ErrUserAlreadyExists
- }
- // Check for duplicate access keys
- for _, cred := range identity.Credentials {
- if _, exists := store.accessKeys[cred.AccessKey]; exists {
- return fmt.Errorf("access key %s already exists", cred.AccessKey)
- }
- }
- // Deep copy to avoid mutation issues
- identityCopy := store.deepCopyIdentity(identity)
- store.users[identity.Name] = identityCopy
- // Index access keys
- for _, cred := range identity.Credentials {
- store.accessKeys[cred.AccessKey] = identity.Name
- }
- return nil
- }
- func (store *MemoryStore) GetUser(ctx context.Context, username string) (*iam_pb.Identity, error) {
- store.mu.RLock()
- defer store.mu.RUnlock()
- if !store.initialized {
- return nil, fmt.Errorf("store not initialized")
- }
- user, exists := store.users[username]
- if !exists {
- return nil, credential.ErrUserNotFound
- }
- // Return a deep copy to avoid mutation issues
- return store.deepCopyIdentity(user), nil
- }
- func (store *MemoryStore) UpdateUser(ctx context.Context, username string, identity *iam_pb.Identity) error {
- store.mu.Lock()
- defer store.mu.Unlock()
- if !store.initialized {
- return fmt.Errorf("store not initialized")
- }
- existingUser, exists := store.users[username]
- if !exists {
- return credential.ErrUserNotFound
- }
- // Remove old access keys from index
- for _, cred := range existingUser.Credentials {
- delete(store.accessKeys, cred.AccessKey)
- }
- // Check for duplicate access keys (excluding current user)
- for _, cred := range identity.Credentials {
- if existingUsername, exists := store.accessKeys[cred.AccessKey]; exists && existingUsername != username {
- return fmt.Errorf("access key %s already exists", cred.AccessKey)
- }
- }
- // Deep copy to avoid mutation issues
- identityCopy := store.deepCopyIdentity(identity)
- store.users[username] = identityCopy
- // Re-index access keys
- for _, cred := range identity.Credentials {
- store.accessKeys[cred.AccessKey] = username
- }
- return nil
- }
- func (store *MemoryStore) DeleteUser(ctx context.Context, username string) error {
- store.mu.Lock()
- defer store.mu.Unlock()
- if !store.initialized {
- return fmt.Errorf("store not initialized")
- }
- user, exists := store.users[username]
- if !exists {
- return credential.ErrUserNotFound
- }
- // Remove access keys from index
- for _, cred := range user.Credentials {
- delete(store.accessKeys, cred.AccessKey)
- }
- // Remove user
- delete(store.users, username)
- return nil
- }
- func (store *MemoryStore) ListUsers(ctx context.Context) ([]string, error) {
- store.mu.RLock()
- defer store.mu.RUnlock()
- if !store.initialized {
- return nil, fmt.Errorf("store not initialized")
- }
- var usernames []string
- for username := range store.users {
- usernames = append(usernames, username)
- }
- return usernames, nil
- }
- func (store *MemoryStore) GetUserByAccessKey(ctx context.Context, accessKey string) (*iam_pb.Identity, error) {
- store.mu.RLock()
- defer store.mu.RUnlock()
- if !store.initialized {
- return nil, fmt.Errorf("store not initialized")
- }
- username, exists := store.accessKeys[accessKey]
- if !exists {
- return nil, credential.ErrAccessKeyNotFound
- }
- user, exists := store.users[username]
- if !exists {
- // This should not happen, but handle it gracefully
- return nil, credential.ErrUserNotFound
- }
- // Return a deep copy to avoid mutation issues
- return store.deepCopyIdentity(user), nil
- }
- func (store *MemoryStore) CreateAccessKey(ctx context.Context, username string, cred *iam_pb.Credential) error {
- store.mu.Lock()
- defer store.mu.Unlock()
- if !store.initialized {
- return fmt.Errorf("store not initialized")
- }
- user, exists := store.users[username]
- if !exists {
- return credential.ErrUserNotFound
- }
- // Check if access key already exists
- if _, exists := store.accessKeys[cred.AccessKey]; exists {
- return fmt.Errorf("access key %s already exists", cred.AccessKey)
- }
- // Add credential to user
- user.Credentials = append(user.Credentials, &iam_pb.Credential{
- AccessKey: cred.AccessKey,
- SecretKey: cred.SecretKey,
- })
- // Index the access key
- store.accessKeys[cred.AccessKey] = username
- return nil
- }
- func (store *MemoryStore) DeleteAccessKey(ctx context.Context, username string, accessKey string) error {
- store.mu.Lock()
- defer store.mu.Unlock()
- if !store.initialized {
- return fmt.Errorf("store not initialized")
- }
- user, exists := store.users[username]
- if !exists {
- return credential.ErrUserNotFound
- }
- // Find and remove the credential
- var newCredentials []*iam_pb.Credential
- found := false
- for _, cred := range user.Credentials {
- if cred.AccessKey == accessKey {
- found = true
- // Remove from access key index
- delete(store.accessKeys, accessKey)
- } else {
- newCredentials = append(newCredentials, cred)
- }
- }
- if !found {
- return credential.ErrAccessKeyNotFound
- }
- user.Credentials = newCredentials
- return nil
- }
- // deepCopyIdentity creates a deep copy of an identity to avoid mutation issues
- func (store *MemoryStore) deepCopyIdentity(identity *iam_pb.Identity) *iam_pb.Identity {
- if identity == nil {
- return nil
- }
- // Use JSON marshaling/unmarshaling for deep copy
- // This is simple and safe for protobuf messages
- data, err := json.Marshal(identity)
- if err != nil {
- // Fallback to shallow copy if JSON fails
- return &iam_pb.Identity{
- Name: identity.Name,
- Account: identity.Account,
- Credentials: identity.Credentials,
- Actions: identity.Actions,
- }
- }
- var copy iam_pb.Identity
- if err := json.Unmarshal(data, ©); err != nil {
- // Fallback to shallow copy if JSON fails
- return &iam_pb.Identity{
- Name: identity.Name,
- Account: identity.Account,
- Credentials: identity.Credentials,
- Actions: identity.Actions,
- }
- }
- return ©
- }
|