forked from baron/baron-sso
feat: 테넌트 그룹 기반 권한 상속 고도화 및 개발자 포털 보안 강화 #239
This commit is contained in:
@@ -18,6 +18,7 @@ type TenantService interface {
|
||||
GetTenantByDomain(ctx context.Context, emailDomain string) (*domain.Tenant, error)
|
||||
GetTenantBySlug(ctx context.Context, slug string) (*domain.Tenant, error)
|
||||
GetTenant(ctx context.Context, id string) (*domain.Tenant, error)
|
||||
ListManageableTenants(ctx context.Context, userID string) ([]domain.Tenant, error)
|
||||
ApproveTenant(ctx context.Context, id string) error
|
||||
SetKetoService(keto KetoService) // 추가
|
||||
}
|
||||
@@ -39,6 +40,60 @@ func (s *tenantService) GetTenant(ctx context.Context, id string) (*domain.Tenan
|
||||
return s.repo.FindByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *tenantService) ListManageableTenants(ctx context.Context, userID string) ([]domain.Tenant, error) {
|
||||
if s.keto == nil {
|
||||
return nil, errors.New("keto service not initialized")
|
||||
}
|
||||
|
||||
// 1. Get directly managed tenants
|
||||
directTenantIDs, err := s.keto.ListObjects(ctx, "Tenant", "admins", userID)
|
||||
if err != nil {
|
||||
slog.Error("Failed to list directly managed tenants from Keto", "userID", userID, "error", err)
|
||||
}
|
||||
|
||||
// 2. Get managed tenant groups
|
||||
groupIDs, err := s.keto.ListObjects(ctx, "TenantGroup", "admins", userID)
|
||||
if err != nil {
|
||||
slog.Error("Failed to list managed tenant groups from Keto", "userID", userID, "error", err)
|
||||
}
|
||||
|
||||
// 3. Get tenants belonging to those groups
|
||||
var groupInheritedTenantIDs []string
|
||||
for _, groupID := range groupIDs {
|
||||
// In Keto, we defined: Tenant#parent_group@TenantGroup:GroupID#_
|
||||
// To find tenants in a group, we look for relations where namespace=Tenant, relation=parent_group, subject=TenantGroup:GroupID#_
|
||||
// Wait, my ListObjects lists objects given a subject.
|
||||
// So subject="TenantGroup:"+groupID+"#_"
|
||||
// Object is Tenant ID.
|
||||
ts, err := s.keto.ListRelations(ctx, "Tenant", "", "parent_group", "TenantGroup:"+groupID)
|
||||
if err == nil {
|
||||
for _, t := range ts {
|
||||
groupInheritedTenantIDs = append(groupInheritedTenantIDs, t.Object)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combine and deduplicate IDs
|
||||
allIDsMap := make(map[string]bool)
|
||||
for _, id := range directTenantIDs {
|
||||
allIDsMap[id] = true
|
||||
}
|
||||
for _, id := range groupInheritedTenantIDs {
|
||||
allIDsMap[id] = true
|
||||
}
|
||||
|
||||
allIDs := make([]string, 0, len(allIDsMap))
|
||||
for id := range allIDsMap {
|
||||
allIDs = append(allIDs, id)
|
||||
}
|
||||
|
||||
if len(allIDs) == 0 {
|
||||
return []domain.Tenant{}, nil
|
||||
}
|
||||
|
||||
return s.repo.FindByIDs(ctx, allIDs)
|
||||
}
|
||||
|
||||
func (s *tenantService) RegisterTenant(ctx context.Context, name, slug, description string, domains []string) (*domain.Tenant, error) {
|
||||
// Validate Slug
|
||||
if ok, msg := utils.ValidateSlug(slug); !ok {
|
||||
|
||||
Reference in New Issue
Block a user