1
0
forked from baron/baron-sso

Merge branch 'feature/user-group' into dev

This commit is contained in:
2026-02-13 14:22:32 +09:00
31 changed files with 2690 additions and 1009 deletions

View File

@@ -39,6 +39,74 @@ 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. 직접 관리자인 테넌트 ID 목록 (Tenant:ID#admins@User:ID)
directTenantIDs, err := s.keto.ListObjects(ctx, "Tenant", "admins", "User:"+userID)
if err != nil {
slog.Error("Failed to list direct tenants", "userID", userID, "error", err)
}
// 2. 관리 권한이 있는 유저 그룹 목록 (UserGroup:ID#owners@User:ID)
// 정책: 그룹장은 해당 그룹(테넌트)의 어드민이 된다.
ownedGroupIDs, err := s.keto.ListObjects(ctx, "UserGroup", "owners", "User:"+userID)
if err != nil {
slog.Error("Failed to list owned groups", "userID", userID, "error", err)
}
// 3. 멤버로 속한 유저 그룹 목록 (UserGroup:ID#members@User:ID)
memberGroupIDs, err := s.keto.ListObjects(ctx, "UserGroup", "members", "User:"+userID)
if err != nil {
slog.Error("Failed to list group memberships", "userID", userID, "error", err)
}
// 4. 유저 그룹을 통해 상속받은 테넌트 목록 조회 (Tenant:ID#manage@UserGroup:ID#members)
var inheritedTenantIDs []string
allMyGroups := append(ownedGroupIDs, memberGroupIDs...)
for _, groupID := range allMyGroups {
// 해당 그룹에 부여된 테넌트 관리 권한 역추적
relations, err := s.keto.ListRelations(ctx, "Tenant", "", "manage", "UserGroup:"+groupID+"#members")
if err == nil {
for _, r := range relations {
inheritedTenantIDs = append(inheritedTenantIDs, r.Object)
}
}
// view 권한도 관리 가능 목록에 포함 (필요 시)
relationsView, err := s.keto.ListRelations(ctx, "Tenant", "", "view", "UserGroup:"+groupID+"#members")
if err == nil {
for _, r := range relationsView {
inheritedTenantIDs = append(inheritedTenantIDs, r.Object)
}
}
}
// 합산 및 중복 제거
allIDsMap := make(map[string]bool)
for _, id := range directTenantIDs {
allIDsMap[id] = true
}
for _, id := range ownedGroupIDs {
allIDsMap[id] = true // 그룹 자체도 테넌트이므로 포함
}
for _, id := range inheritedTenantIDs {
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 {