You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							338 lines
						
					
					
						
							8.7 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							338 lines
						
					
					
						
							8.7 KiB
						
					
					
				| package dash | |
| 
 | |
| import ( | |
| 	"context" | |
| 	"crypto/rand" | |
| 	"encoding/base64" | |
| 	"fmt" | |
| 	"time" | |
| 
 | |
| 	"github.com/seaweedfs/seaweedfs/weed/credential" | |
| 	"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb" | |
| ) | |
| 
 | |
| // CreateObjectStoreUser creates a new user using the credential manager | |
| func (s *AdminServer) CreateObjectStoreUser(req CreateUserRequest) (*ObjectStoreUser, error) { | |
| 	if s.credentialManager == nil { | |
| 		return nil, fmt.Errorf("credential manager not available") | |
| 	} | |
| 
 | |
| 	ctx := context.Background() | |
| 
 | |
| 	// Create new identity | |
| 	newIdentity := &iam_pb.Identity{ | |
| 		Name:    req.Username, | |
| 		Actions: req.Actions, | |
| 	} | |
| 
 | |
| 	// Add account if email is provided | |
| 	if req.Email != "" { | |
| 		newIdentity.Account = &iam_pb.Account{ | |
| 			Id:           generateAccountId(), | |
| 			DisplayName:  req.Username, | |
| 			EmailAddress: req.Email, | |
| 		} | |
| 	} | |
| 
 | |
| 	// Generate access key if requested | |
| 	var accessKey, secretKey string | |
| 	if req.GenerateKey { | |
| 		accessKey = generateAccessKey() | |
| 		secretKey = generateSecretKey() | |
| 		newIdentity.Credentials = []*iam_pb.Credential{ | |
| 			{ | |
| 				AccessKey: accessKey, | |
| 				SecretKey: secretKey, | |
| 			}, | |
| 		} | |
| 	} | |
| 
 | |
| 	// Create user using credential manager | |
| 	err := s.credentialManager.CreateUser(ctx, newIdentity) | |
| 	if err != nil { | |
| 		if err == credential.ErrUserAlreadyExists { | |
| 			return nil, fmt.Errorf("user %s already exists", req.Username) | |
| 		} | |
| 		return nil, fmt.Errorf("failed to create user: %v", err) | |
| 	} | |
| 
 | |
| 	// Return created user | |
| 	user := &ObjectStoreUser{ | |
| 		Username:    req.Username, | |
| 		Email:       req.Email, | |
| 		AccessKey:   accessKey, | |
| 		SecretKey:   secretKey, | |
| 		Permissions: req.Actions, | |
| 	} | |
| 
 | |
| 	return user, nil | |
| } | |
| 
 | |
| // UpdateObjectStoreUser updates an existing user | |
| func (s *AdminServer) UpdateObjectStoreUser(username string, req UpdateUserRequest) (*ObjectStoreUser, error) { | |
| 	if s.credentialManager == nil { | |
| 		return nil, fmt.Errorf("credential manager not available") | |
| 	} | |
| 
 | |
| 	ctx := context.Background() | |
| 
 | |
| 	// Get existing user | |
| 	identity, err := s.credentialManager.GetUser(ctx, username) | |
| 	if err != nil { | |
| 		if err == credential.ErrUserNotFound { | |
| 			return nil, fmt.Errorf("user %s not found", username) | |
| 		} | |
| 		return nil, fmt.Errorf("failed to get user: %v", err) | |
| 	} | |
| 
 | |
| 	// Create updated identity | |
| 	updatedIdentity := &iam_pb.Identity{ | |
| 		Name:        identity.Name, | |
| 		Account:     identity.Account, | |
| 		Credentials: identity.Credentials, | |
| 		Actions:     identity.Actions, | |
| 	} | |
| 
 | |
| 	// Update actions if provided | |
| 	if len(req.Actions) > 0 { | |
| 		updatedIdentity.Actions = req.Actions | |
| 	} | |
| 
 | |
| 	// Update email if provided | |
| 	if req.Email != "" { | |
| 		if updatedIdentity.Account == nil { | |
| 			updatedIdentity.Account = &iam_pb.Account{ | |
| 				Id:          generateAccountId(), | |
| 				DisplayName: username, | |
| 			} | |
| 		} | |
| 		updatedIdentity.Account.EmailAddress = req.Email | |
| 	} | |
| 
 | |
| 	// Update user using credential manager | |
| 	err = s.credentialManager.UpdateUser(ctx, username, updatedIdentity) | |
| 	if err != nil { | |
| 		return nil, fmt.Errorf("failed to update user: %v", err) | |
| 	} | |
| 
 | |
| 	// Return updated user | |
| 	user := &ObjectStoreUser{ | |
| 		Username:    username, | |
| 		Email:       req.Email, | |
| 		Permissions: updatedIdentity.Actions, | |
| 	} | |
| 
 | |
| 	// Get first access key for display | |
| 	if len(updatedIdentity.Credentials) > 0 { | |
| 		user.AccessKey = updatedIdentity.Credentials[0].AccessKey | |
| 		user.SecretKey = updatedIdentity.Credentials[0].SecretKey | |
| 	} | |
| 
 | |
| 	return user, nil | |
| } | |
| 
 | |
| // DeleteObjectStoreUser deletes a user using the credential manager | |
| func (s *AdminServer) DeleteObjectStoreUser(username string) error { | |
| 	if s.credentialManager == nil { | |
| 		return fmt.Errorf("credential manager not available") | |
| 	} | |
| 
 | |
| 	ctx := context.Background() | |
| 
 | |
| 	// Delete user using credential manager | |
| 	err := s.credentialManager.DeleteUser(ctx, username) | |
| 	if err != nil { | |
| 		if err == credential.ErrUserNotFound { | |
| 			return fmt.Errorf("user %s not found", username) | |
| 		} | |
| 		return fmt.Errorf("failed to delete user: %v", err) | |
| 	} | |
| 
 | |
| 	return nil | |
| } | |
| 
 | |
| // GetObjectStoreUserDetails returns detailed information about a user | |
| func (s *AdminServer) GetObjectStoreUserDetails(username string) (*UserDetails, error) { | |
| 	if s.credentialManager == nil { | |
| 		return nil, fmt.Errorf("credential manager not available") | |
| 	} | |
| 
 | |
| 	ctx := context.Background() | |
| 
 | |
| 	// Get user using credential manager | |
| 	identity, err := s.credentialManager.GetUser(ctx, username) | |
| 	if err != nil { | |
| 		if err == credential.ErrUserNotFound { | |
| 			return nil, fmt.Errorf("user %s not found", username) | |
| 		} | |
| 		return nil, fmt.Errorf("failed to get user: %v", err) | |
| 	} | |
| 
 | |
| 	details := &UserDetails{ | |
| 		Username: username, | |
| 		Actions:  identity.Actions, | |
| 	} | |
| 
 | |
| 	// Set email from account if available | |
| 	if identity.Account != nil { | |
| 		details.Email = identity.Account.EmailAddress | |
| 	} | |
| 
 | |
| 	// Convert credentials to access key info | |
| 	for _, cred := range identity.Credentials { | |
| 		details.AccessKeys = append(details.AccessKeys, AccessKeyInfo{ | |
| 			AccessKey: cred.AccessKey, | |
| 			SecretKey: cred.SecretKey, | |
| 			CreatedAt: time.Now().AddDate(0, -1, 0), // Mock creation date | |
| 		}) | |
| 	} | |
| 
 | |
| 	return details, nil | |
| } | |
| 
 | |
| // CreateAccessKey creates a new access key for a user | |
| func (s *AdminServer) CreateAccessKey(username string) (*AccessKeyInfo, error) { | |
| 	if s.credentialManager == nil { | |
| 		return nil, fmt.Errorf("credential manager not available") | |
| 	} | |
| 
 | |
| 	ctx := context.Background() | |
| 
 | |
| 	// Check if user exists | |
| 	_, err := s.credentialManager.GetUser(ctx, username) | |
| 	if err != nil { | |
| 		if err == credential.ErrUserNotFound { | |
| 			return nil, fmt.Errorf("user %s not found", username) | |
| 		} | |
| 		return nil, fmt.Errorf("failed to get user: %v", err) | |
| 	} | |
| 
 | |
| 	// Generate new access key | |
| 	accessKey := generateAccessKey() | |
| 	secretKey := generateSecretKey() | |
| 
 | |
| 	credential := &iam_pb.Credential{ | |
| 		AccessKey: accessKey, | |
| 		SecretKey: secretKey, | |
| 	} | |
| 
 | |
| 	// Create access key using credential manager | |
| 	err = s.credentialManager.CreateAccessKey(ctx, username, credential) | |
| 	if err != nil { | |
| 		return nil, fmt.Errorf("failed to create access key: %v", err) | |
| 	} | |
| 
 | |
| 	return &AccessKeyInfo{ | |
| 		AccessKey: accessKey, | |
| 		SecretKey: secretKey, | |
| 		CreatedAt: time.Now(), | |
| 	}, nil | |
| } | |
| 
 | |
| // DeleteAccessKey deletes an access key for a user | |
| func (s *AdminServer) DeleteAccessKey(username, accessKeyId string) error { | |
| 	if s.credentialManager == nil { | |
| 		return fmt.Errorf("credential manager not available") | |
| 	} | |
| 
 | |
| 	ctx := context.Background() | |
| 
 | |
| 	// Delete access key using credential manager | |
| 	err := s.credentialManager.DeleteAccessKey(ctx, username, accessKeyId) | |
| 	if err != nil { | |
| 		if err == credential.ErrUserNotFound { | |
| 			return fmt.Errorf("user %s not found", username) | |
| 		} | |
| 		if err == credential.ErrAccessKeyNotFound { | |
| 			return fmt.Errorf("access key %s not found for user %s", accessKeyId, username) | |
| 		} | |
| 		return fmt.Errorf("failed to delete access key: %v", err) | |
| 	} | |
| 
 | |
| 	return nil | |
| } | |
| 
 | |
| // GetUserPolicies returns the policies for a user (actions) | |
| func (s *AdminServer) GetUserPolicies(username string) ([]string, error) { | |
| 	if s.credentialManager == nil { | |
| 		return nil, fmt.Errorf("credential manager not available") | |
| 	} | |
| 
 | |
| 	ctx := context.Background() | |
| 
 | |
| 	// Get user using credential manager | |
| 	identity, err := s.credentialManager.GetUser(ctx, username) | |
| 	if err != nil { | |
| 		if err == credential.ErrUserNotFound { | |
| 			return nil, fmt.Errorf("user %s not found", username) | |
| 		} | |
| 		return nil, fmt.Errorf("failed to get user: %v", err) | |
| 	} | |
| 
 | |
| 	return identity.Actions, nil | |
| } | |
| 
 | |
| // UpdateUserPolicies updates the policies (actions) for a user | |
| func (s *AdminServer) UpdateUserPolicies(username string, actions []string) error { | |
| 	if s.credentialManager == nil { | |
| 		return fmt.Errorf("credential manager not available") | |
| 	} | |
| 
 | |
| 	ctx := context.Background() | |
| 
 | |
| 	// Get existing user | |
| 	identity, err := s.credentialManager.GetUser(ctx, username) | |
| 	if err != nil { | |
| 		if err == credential.ErrUserNotFound { | |
| 			return fmt.Errorf("user %s not found", username) | |
| 		} | |
| 		return fmt.Errorf("failed to get user: %v", err) | |
| 	} | |
| 
 | |
| 	// Create updated identity with new actions | |
| 	updatedIdentity := &iam_pb.Identity{ | |
| 		Name:        identity.Name, | |
| 		Account:     identity.Account, | |
| 		Credentials: identity.Credentials, | |
| 		Actions:     actions, | |
| 	} | |
| 
 | |
| 	// Update user using credential manager | |
| 	err = s.credentialManager.UpdateUser(ctx, username, updatedIdentity) | |
| 	if err != nil { | |
| 		return fmt.Errorf("failed to update user policies: %v", err) | |
| 	} | |
| 
 | |
| 	return nil | |
| } | |
| 
 | |
| // Helper functions for generating keys and IDs | |
| func generateAccessKey() string { | |
| 	// Generate 20-character access key (AWS standard) | |
| 	const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" | |
| 	b := make([]byte, 20) | |
| 	for i := range b { | |
| 		b[i] = charset[randomInt(len(charset))] | |
| 	} | |
| 	return string(b) | |
| } | |
| 
 | |
| func generateSecretKey() string { | |
| 	// Generate 40-character secret key (AWS standard) | |
| 	b := make([]byte, 30) // 30 bytes = 40 characters in base64 | |
| 	rand.Read(b) | |
| 	return base64.StdEncoding.EncodeToString(b) | |
| } | |
| 
 | |
| func generateAccountId() string { | |
| 	// Generate 12-digit account ID | |
| 	b := make([]byte, 8) | |
| 	rand.Read(b) | |
| 	return fmt.Sprintf("%012d", b[0]<<24|b[1]<<16|b[2]<<8|b[3]) | |
| } | |
| 
 | |
| func randomInt(max int) int { | |
| 	b := make([]byte, 1) | |
| 	rand.Read(b) | |
| 	return int(b[0]) % max | |
| }
 |