|
|
@ -17,17 +17,17 @@ import ( |
|
|
|
|
|
|
|
// RoleStore defines the interface for storing IAM role definitions
|
|
|
|
type RoleStore interface { |
|
|
|
// StoreRole stores a role definition
|
|
|
|
StoreRole(ctx context.Context, roleName string, role *RoleDefinition) error |
|
|
|
// StoreRole stores a role definition (filerAddress ignored for memory stores)
|
|
|
|
StoreRole(ctx context.Context, filerAddress string, roleName string, role *RoleDefinition) error |
|
|
|
|
|
|
|
// GetRole retrieves a role definition
|
|
|
|
GetRole(ctx context.Context, roleName string) (*RoleDefinition, error) |
|
|
|
// GetRole retrieves a role definition (filerAddress ignored for memory stores)
|
|
|
|
GetRole(ctx context.Context, filerAddress string, roleName string) (*RoleDefinition, error) |
|
|
|
|
|
|
|
// ListRoles lists all role names
|
|
|
|
ListRoles(ctx context.Context) ([]string, error) |
|
|
|
// ListRoles lists all role names (filerAddress ignored for memory stores)
|
|
|
|
ListRoles(ctx context.Context, filerAddress string) ([]string, error) |
|
|
|
|
|
|
|
// DeleteRole deletes a role definition
|
|
|
|
DeleteRole(ctx context.Context, roleName string) error |
|
|
|
// DeleteRole deletes a role definition (filerAddress ignored for memory stores)
|
|
|
|
DeleteRole(ctx context.Context, filerAddress string, roleName string) error |
|
|
|
} |
|
|
|
|
|
|
|
// MemoryRoleStore implements RoleStore using in-memory storage
|
|
|
@ -43,8 +43,8 @@ func NewMemoryRoleStore() *MemoryRoleStore { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// StoreRole stores a role definition in memory
|
|
|
|
func (m *MemoryRoleStore) StoreRole(ctx context.Context, roleName string, role *RoleDefinition) error { |
|
|
|
// StoreRole stores a role definition in memory (filerAddress ignored for memory store)
|
|
|
|
func (m *MemoryRoleStore) StoreRole(ctx context.Context, filerAddress string, roleName string, role *RoleDefinition) error { |
|
|
|
if roleName == "" { |
|
|
|
return fmt.Errorf("role name cannot be empty") |
|
|
|
} |
|
|
@ -60,8 +60,8 @@ func (m *MemoryRoleStore) StoreRole(ctx context.Context, roleName string, role * |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
// GetRole retrieves a role definition from memory
|
|
|
|
func (m *MemoryRoleStore) GetRole(ctx context.Context, roleName string) (*RoleDefinition, error) { |
|
|
|
// GetRole retrieves a role definition from memory (filerAddress ignored for memory store)
|
|
|
|
func (m *MemoryRoleStore) GetRole(ctx context.Context, filerAddress string, roleName string) (*RoleDefinition, error) { |
|
|
|
if roleName == "" { |
|
|
|
return nil, fmt.Errorf("role name cannot be empty") |
|
|
|
} |
|
|
@ -78,8 +78,8 @@ func (m *MemoryRoleStore) GetRole(ctx context.Context, roleName string) (*RoleDe |
|
|
|
return copyRoleDefinition(role), nil |
|
|
|
} |
|
|
|
|
|
|
|
// ListRoles lists all role names in memory
|
|
|
|
func (m *MemoryRoleStore) ListRoles(ctx context.Context) ([]string, error) { |
|
|
|
// ListRoles lists all role names in memory (filerAddress ignored for memory store)
|
|
|
|
func (m *MemoryRoleStore) ListRoles(ctx context.Context, filerAddress string) ([]string, error) { |
|
|
|
m.mutex.RLock() |
|
|
|
defer m.mutex.RUnlock() |
|
|
|
|
|
|
@ -91,8 +91,8 @@ func (m *MemoryRoleStore) ListRoles(ctx context.Context) ([]string, error) { |
|
|
|
return names, nil |
|
|
|
} |
|
|
|
|
|
|
|
// DeleteRole deletes a role definition from memory
|
|
|
|
func (m *MemoryRoleStore) DeleteRole(ctx context.Context, roleName string) error { |
|
|
|
// DeleteRole deletes a role definition from memory (filerAddress ignored for memory store)
|
|
|
|
func (m *MemoryRoleStore) DeleteRole(ctx context.Context, filerAddress string, roleName string) error { |
|
|
|
if roleName == "" { |
|
|
|
return fmt.Errorf("role name cannot be empty") |
|
|
|
} |
|
|
@ -136,9 +136,8 @@ func copyRoleDefinition(original *RoleDefinition) *RoleDefinition { |
|
|
|
|
|
|
|
// FilerRoleStore implements RoleStore using SeaweedFS filer
|
|
|
|
type FilerRoleStore struct { |
|
|
|
filerGrpcAddress string |
|
|
|
grpcDialOption grpc.DialOption |
|
|
|
basePath string |
|
|
|
grpcDialOption grpc.DialOption |
|
|
|
basePath string |
|
|
|
} |
|
|
|
|
|
|
|
// NewFilerRoleStore creates a new filer-based role store
|
|
|
@ -147,29 +146,23 @@ func NewFilerRoleStore(config map[string]interface{}) (*FilerRoleStore, error) { |
|
|
|
basePath: "/etc/iam/roles", // Default path for role storage - aligned with /etc/ convention
|
|
|
|
} |
|
|
|
|
|
|
|
// Parse configuration
|
|
|
|
// Parse configuration - only basePath and other settings, NOT filerAddress
|
|
|
|
if config != nil { |
|
|
|
if filerAddr, ok := config["filerAddress"].(string); ok { |
|
|
|
store.filerGrpcAddress = filerAddr |
|
|
|
} |
|
|
|
if basePath, ok := config["basePath"].(string); ok { |
|
|
|
if basePath, ok := config["basePath"].(string); ok && basePath != "" { |
|
|
|
store.basePath = strings.TrimSuffix(basePath, "/") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Validate configuration
|
|
|
|
if store.filerGrpcAddress == "" { |
|
|
|
return nil, fmt.Errorf("filer address is required for FilerRoleStore") |
|
|
|
} |
|
|
|
|
|
|
|
glog.V(2).Infof("Initialized FilerRoleStore with filer %s, basePath %s", |
|
|
|
store.filerGrpcAddress, store.basePath) |
|
|
|
glog.V(2).Infof("Initialized FilerRoleStore with basePath %s", store.basePath) |
|
|
|
|
|
|
|
return store, nil |
|
|
|
} |
|
|
|
|
|
|
|
// StoreRole stores a role definition in filer
|
|
|
|
func (f *FilerRoleStore) StoreRole(ctx context.Context, roleName string, role *RoleDefinition) error { |
|
|
|
func (f *FilerRoleStore) StoreRole(ctx context.Context, filerAddress string, roleName string, role *RoleDefinition) error { |
|
|
|
if filerAddress == "" { |
|
|
|
return fmt.Errorf("filer address is required for FilerRoleStore") |
|
|
|
} |
|
|
|
if roleName == "" { |
|
|
|
return fmt.Errorf("role name cannot be empty") |
|
|
|
} |
|
|
@ -186,7 +179,7 @@ func (f *FilerRoleStore) StoreRole(ctx context.Context, roleName string, role *R |
|
|
|
rolePath := f.getRolePath(roleName) |
|
|
|
|
|
|
|
// Store in filer
|
|
|
|
return f.withFilerClient(func(client filer_pb.SeaweedFilerClient) error { |
|
|
|
return f.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error { |
|
|
|
request := &filer_pb.CreateEntryRequest{ |
|
|
|
Directory: f.basePath, |
|
|
|
Entry: &filer_pb.Entry{ |
|
|
@ -214,13 +207,16 @@ func (f *FilerRoleStore) StoreRole(ctx context.Context, roleName string, role *R |
|
|
|
} |
|
|
|
|
|
|
|
// GetRole retrieves a role definition from filer
|
|
|
|
func (f *FilerRoleStore) GetRole(ctx context.Context, roleName string) (*RoleDefinition, error) { |
|
|
|
func (f *FilerRoleStore) GetRole(ctx context.Context, filerAddress string, roleName string) (*RoleDefinition, error) { |
|
|
|
if filerAddress == "" { |
|
|
|
return nil, fmt.Errorf("filer address is required for FilerRoleStore") |
|
|
|
} |
|
|
|
if roleName == "" { |
|
|
|
return nil, fmt.Errorf("role name cannot be empty") |
|
|
|
} |
|
|
|
|
|
|
|
var roleData []byte |
|
|
|
err := f.withFilerClient(func(client filer_pb.SeaweedFilerClient) error { |
|
|
|
err := f.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error { |
|
|
|
request := &filer_pb.LookupDirectoryEntryRequest{ |
|
|
|
Directory: f.basePath, |
|
|
|
Name: f.getRoleFileName(roleName), |
|
|
@ -254,10 +250,14 @@ func (f *FilerRoleStore) GetRole(ctx context.Context, roleName string) (*RoleDef |
|
|
|
} |
|
|
|
|
|
|
|
// ListRoles lists all role names in filer
|
|
|
|
func (f *FilerRoleStore) ListRoles(ctx context.Context) ([]string, error) { |
|
|
|
func (f *FilerRoleStore) ListRoles(ctx context.Context, filerAddress string) ([]string, error) { |
|
|
|
if filerAddress == "" { |
|
|
|
return nil, fmt.Errorf("filer address is required for FilerRoleStore") |
|
|
|
} |
|
|
|
|
|
|
|
var roleNames []string |
|
|
|
|
|
|
|
err := f.withFilerClient(func(client filer_pb.SeaweedFilerClient) error { |
|
|
|
err := f.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error { |
|
|
|
request := &filer_pb.ListEntriesRequest{ |
|
|
|
Directory: f.basePath, |
|
|
|
Prefix: "", |
|
|
@ -301,12 +301,15 @@ func (f *FilerRoleStore) ListRoles(ctx context.Context) ([]string, error) { |
|
|
|
} |
|
|
|
|
|
|
|
// DeleteRole deletes a role definition from filer
|
|
|
|
func (f *FilerRoleStore) DeleteRole(ctx context.Context, roleName string) error { |
|
|
|
func (f *FilerRoleStore) DeleteRole(ctx context.Context, filerAddress string, roleName string) error { |
|
|
|
if filerAddress == "" { |
|
|
|
return fmt.Errorf("filer address is required for FilerRoleStore") |
|
|
|
} |
|
|
|
if roleName == "" { |
|
|
|
return fmt.Errorf("role name cannot be empty") |
|
|
|
} |
|
|
|
|
|
|
|
return f.withFilerClient(func(client filer_pb.SeaweedFilerClient) error { |
|
|
|
return f.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error { |
|
|
|
request := &filer_pb.DeleteEntryRequest{ |
|
|
|
Directory: f.basePath, |
|
|
|
Name: f.getRoleFileName(roleName), |
|
|
@ -333,6 +336,9 @@ func (f *FilerRoleStore) getRolePath(roleName string) string { |
|
|
|
return f.basePath + "/" + f.getRoleFileName(roleName) |
|
|
|
} |
|
|
|
|
|
|
|
func (f *FilerRoleStore) withFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error { |
|
|
|
return pb.WithGrpcFilerClient(false, 0, pb.ServerAddress(f.filerGrpcAddress), f.grpcDialOption, fn) |
|
|
|
func (f *FilerRoleStore) withFilerClient(filerAddress string, fn func(filer_pb.SeaweedFilerClient) error) error { |
|
|
|
if filerAddress == "" { |
|
|
|
return fmt.Errorf("filer address is required for FilerRoleStore") |
|
|
|
} |
|
|
|
return pb.WithGrpcFilerClient(false, 0, pb.ServerAddress(filerAddress), f.grpcDialOption, fn) |
|
|
|
} |