forked from baron/baron-sso
131 lines
4.1 KiB
Go
131 lines
4.1 KiB
Go
package service
|
|
|
|
import (
|
|
"baron-sso-backend/internal/domain"
|
|
"baron-sso-backend/internal/repository"
|
|
"context"
|
|
"log/slog"
|
|
)
|
|
|
|
type TenantGroupService interface {
|
|
CreateGroup(ctx context.Context, name, slug, description string) (*domain.TenantGroup, error)
|
|
GetGroup(ctx context.Context, id string) (*domain.TenantGroup, error)
|
|
ListGroups(ctx context.Context, limit, offset int) ([]domain.TenantGroup, int64, error)
|
|
UpdateGroup(ctx context.Context, id string, name, description string) (*domain.TenantGroup, error)
|
|
DeleteGroup(ctx context.Context, id string) error
|
|
AddTenantToGroup(ctx context.Context, groupID, tenantID string) error
|
|
RemoveTenantFromGroup(ctx context.Context, groupID, tenantID string) error
|
|
AddGroupAdmin(ctx context.Context, groupID, userID string) error
|
|
RemoveGroupAdmin(ctx context.Context, groupID, userID string) error
|
|
ListGroupAdmins(ctx context.Context, groupID string) ([]string, error)
|
|
}
|
|
|
|
type tenantGroupService struct {
|
|
repo repository.TenantGroupRepository
|
|
keto KetoService
|
|
}
|
|
|
|
func NewTenantGroupService(repo repository.TenantGroupRepository, keto KetoService) TenantGroupService {
|
|
return &tenantGroupService{repo: repo, keto: keto}
|
|
}
|
|
|
|
func (s *tenantGroupService) CreateGroup(ctx context.Context, name, slug, description string) (*domain.TenantGroup, error) {
|
|
group := &domain.TenantGroup{
|
|
Name: name,
|
|
Slug: slug,
|
|
Description: description,
|
|
}
|
|
if err := s.repo.Create(ctx, group); err != nil {
|
|
return nil, err
|
|
}
|
|
return group, nil
|
|
}
|
|
|
|
func (s *tenantGroupService) GetGroup(ctx context.Context, id string) (*domain.TenantGroup, error) {
|
|
return s.repo.FindByID(ctx, id)
|
|
}
|
|
|
|
func (s *tenantGroupService) ListGroups(ctx context.Context, limit, offset int) ([]domain.TenantGroup, int64, error) {
|
|
return s.repo.List(ctx, limit, offset)
|
|
}
|
|
|
|
func (s *tenantGroupService) UpdateGroup(ctx context.Context, id string, name, description string) (*domain.TenantGroup, error) {
|
|
group, err := s.repo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
group.Name = name
|
|
group.Description = description
|
|
if err := s.repo.Update(ctx, group); err != nil {
|
|
return nil, err
|
|
}
|
|
return group, nil
|
|
}
|
|
|
|
func (s *tenantGroupService) DeleteGroup(ctx context.Context, id string) error {
|
|
return s.repo.Delete(ctx, id)
|
|
}
|
|
|
|
func (s *tenantGroupService) AddTenantToGroup(ctx context.Context, groupID, tenantID string) error {
|
|
if err := s.repo.AddTenant(ctx, groupID, tenantID); err != nil {
|
|
return err
|
|
}
|
|
|
|
// [Keto] ReBAC: Tenant -> Group membership
|
|
if s.keto != nil {
|
|
err := s.keto.CreateRelation(ctx, "Tenant", tenantID, "parent_group", groupID)
|
|
if err != nil {
|
|
slog.Error("Failed to sync Keto relation for tenant group", "tenantID", tenantID, "groupID", groupID, "error", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *tenantGroupService) RemoveTenantFromGroup(ctx context.Context, groupID, tenantID string) error {
|
|
if err := s.repo.RemoveTenant(ctx, groupID, tenantID); err != nil {
|
|
return err
|
|
}
|
|
|
|
// [Keto] ReBAC: Remove Tenant -> Group membership
|
|
if s.keto != nil {
|
|
err := s.keto.DeleteRelation(ctx, "Tenant", tenantID, "parent_group", groupID)
|
|
if err != nil {
|
|
slog.Error("Failed to remove Keto relation for tenant group", "tenantID", tenantID, "groupID", groupID, "error", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *tenantGroupService) AddGroupAdmin(ctx context.Context, groupID, userID string) error {
|
|
if s.keto == nil {
|
|
return nil
|
|
}
|
|
return s.keto.CreateRelation(ctx, "TenantGroup", groupID, "admins", "User:"+userID)
|
|
}
|
|
|
|
func (s *tenantGroupService) RemoveGroupAdmin(ctx context.Context, groupID, userID string) error {
|
|
if s.keto == nil {
|
|
return nil
|
|
}
|
|
return s.keto.DeleteRelation(ctx, "TenantGroup", groupID, "admins", "User:"+userID)
|
|
}
|
|
|
|
func (s *tenantGroupService) ListGroupAdmins(ctx context.Context, groupID string) ([]string, error) {
|
|
if s.keto == nil {
|
|
return []string{}, nil
|
|
}
|
|
tuples, err := s.keto.ListRelations(ctx, "TenantGroup", groupID, "admins", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
userIDs := make([]string, 0, len(tuples))
|
|
for _, t := range tuples {
|
|
// subject_id is "User:uuid"
|
|
if len(t.SubjectID) > 5 && t.SubjectID[:5] == "User:" {
|
|
userIDs = append(userIDs, t.SubjectID[5:])
|
|
}
|
|
}
|
|
return userIDs, nil
|
|
}
|