forked from baron/baron-sso
usergroup
This commit is contained in:
@@ -246,10 +246,12 @@ func main() {
|
|||||||
// 2. Initialize Handlers
|
// 2. Initialize Handlers
|
||||||
tenantRepo := repository.NewTenantRepository(db)
|
tenantRepo := repository.NewTenantRepository(db)
|
||||||
tenantGroupRepo := repository.NewTenantGroupRepository(db)
|
tenantGroupRepo := repository.NewTenantGroupRepository(db)
|
||||||
|
userGroupRepo := repository.NewUserGroupRepository(db)
|
||||||
|
userRepo := repository.NewUserRepository(db)
|
||||||
tenantService := service.NewTenantService(tenantRepo)
|
tenantService := service.NewTenantService(tenantRepo)
|
||||||
tenantGroupService := service.NewTenantGroupService(tenantGroupRepo, ketoService)
|
tenantGroupService := service.NewTenantGroupService(tenantGroupRepo, ketoService)
|
||||||
|
userGroupService := service.NewUserGroupService(userGroupRepo, userRepo, ketoService)
|
||||||
tenantService.SetKetoService(ketoService) // Keto 주입
|
tenantService.SetKetoService(ketoService) // Keto 주입
|
||||||
userRepo := repository.NewUserRepository(db)
|
|
||||||
// relyingPartyRepo removed as SSOT is now Hydra+Keto
|
// relyingPartyRepo removed as SSOT is now Hydra+Keto
|
||||||
hydraService := service.NewHydraAdminService()
|
hydraService := service.NewHydraAdminService()
|
||||||
relyingPartyService := service.NewRelyingPartyService(hydraService, ketoService)
|
relyingPartyService := service.NewRelyingPartyService(hydraService, ketoService)
|
||||||
@@ -265,6 +267,7 @@ func main() {
|
|||||||
devHandler := handler.NewDevHandler(redisService, secretRepo, consentRepo, relyingPartyService)
|
devHandler := handler.NewDevHandler(redisService, secretRepo, consentRepo, relyingPartyService)
|
||||||
tenantHandler := handler.NewTenantHandler(db, tenantService, ketoService, kratosAdminService)
|
tenantHandler := handler.NewTenantHandler(db, tenantService, ketoService, kratosAdminService)
|
||||||
tenantGroupHandler := handler.NewTenantGroupHandler(tenantGroupService, kratosAdminService)
|
tenantGroupHandler := handler.NewTenantGroupHandler(tenantGroupService, kratosAdminService)
|
||||||
|
userGroupHandler := handler.NewUserGroupHandler(userGroupService)
|
||||||
relyingPartyHandler := handler.NewRelyingPartyHandler(relyingPartyService, kratosAdminService)
|
relyingPartyHandler := handler.NewRelyingPartyHandler(relyingPartyService, kratosAdminService)
|
||||||
userHandler := handler.NewUserHandler(kratosAdminService, oryAdminProvider, tenantService, ketoService, userRepo)
|
userHandler := handler.NewUserHandler(kratosAdminService, oryAdminProvider, tenantService, ketoService, userRepo)
|
||||||
apiKeyHandler := handler.NewApiKeyHandler(db)
|
apiKeyHandler := handler.NewApiKeyHandler(db)
|
||||||
@@ -585,6 +588,18 @@ func main() {
|
|||||||
admin.Post("/tenant-groups/:id/admins/:userId", requireSuperAdmin, tenantGroupHandler.AddAdmin)
|
admin.Post("/tenant-groups/:id/admins/:userId", requireSuperAdmin, tenantGroupHandler.AddAdmin)
|
||||||
admin.Delete("/tenant-groups/:id/admins/:userId", requireSuperAdmin, tenantGroupHandler.RemoveAdmin)
|
admin.Delete("/tenant-groups/:id/admins/:userId", requireSuperAdmin, tenantGroupHandler.RemoveAdmin)
|
||||||
|
|
||||||
|
// User Group Management (Tenant Admin/Super Admin)
|
||||||
|
userGroups := admin.Group("/tenants/:tenantId/user-groups", requireAdmin, middleware.RequireKetoPermission(middleware.RBACConfig{AuthHandler: authHandler, KetoService: ketoService}, "Tenant", "manage"))
|
||||||
|
userGroups.Get("/", userGroupHandler.List)
|
||||||
|
userGroups.Post("/", userGroupHandler.Create)
|
||||||
|
userGroups.Get("/:id", userGroupHandler.Get)
|
||||||
|
userGroups.Put("/:id", userGroupHandler.Update)
|
||||||
|
userGroups.Delete("/:id", userGroupHandler.Delete)
|
||||||
|
userGroups.Post("/:id/members", userGroupHandler.AddMember)
|
||||||
|
userGroups.Delete("/:id/members/:userId", userGroupHandler.RemoveMember)
|
||||||
|
userGroups.Post("/:id/roles", userGroupHandler.AssignRole)
|
||||||
|
userGroups.Delete("/:id/roles/:tenantId/:relation", userGroupHandler.RemoveRole)
|
||||||
|
|
||||||
// Relying Party Management (Global List)
|
// Relying Party Management (Global List)
|
||||||
admin.Get("/relying-parties", requireAdmin, relyingPartyHandler.ListAll)
|
admin.Get("/relying-parties", requireAdmin, relyingPartyHandler.ListAll)
|
||||||
admin.Get("/relying-parties/:id/owners", requireAdmin, middleware.RequireKetoPermission(middleware.RBACConfig{AuthHandler: authHandler, KetoService: ketoService}, "RelyingParty", "manage"), relyingPartyHandler.ListOwners)
|
admin.Get("/relying-parties/:id/owners", requireAdmin, middleware.RequireKetoPermission(middleware.RBACConfig{AuthHandler: authHandler, KetoService: ketoService}, "RelyingParty", "manage"), relyingPartyHandler.ListOwners)
|
||||||
|
|||||||
@@ -93,3 +93,30 @@ func (h *UserGroupHandler) RemoveMember(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
return c.SendStatus(fiber.StatusNoContent)
|
return c.SendStatus(fiber.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *UserGroupHandler) AssignRole(c *fiber.Ctx) error {
|
||||||
|
groupID := c.Params("id")
|
||||||
|
var req struct {
|
||||||
|
TenantID string `json:"tenantId"`
|
||||||
|
Relation string `json:"relation"`
|
||||||
|
}
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid body"})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.Service.AssignRoleToTenant(c.Context(), groupID, req.TenantID, req.Relation); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||||
|
}
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *UserGroupHandler) RemoveRole(c *fiber.Ctx) error {
|
||||||
|
groupID := c.Params("id")
|
||||||
|
tenantID := c.Params("tenantId")
|
||||||
|
relation := c.Params("relation")
|
||||||
|
|
||||||
|
if err := h.Service.RemoveRoleFromTenant(c.Context(), groupID, tenantID, relation); err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||||
|
}
|
||||||
|
return c.SendStatus(fiber.StatusNoContent)
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ type UserGroupService interface {
|
|||||||
// Member Management with Keto Sync
|
// Member Management with Keto Sync
|
||||||
AddMember(ctx context.Context, groupID, userID string) error
|
AddMember(ctx context.Context, groupID, userID string) error
|
||||||
RemoveMember(ctx context.Context, groupID, userID string) error
|
RemoveMember(ctx context.Context, groupID, userID string) error
|
||||||
|
|
||||||
|
// Permission Management
|
||||||
|
AssignRoleToTenant(ctx context.Context, groupID, tenantID, relation string) error
|
||||||
|
RemoveRoleFromTenant(ctx context.Context, groupID, tenantID, relation string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type userGroupService struct {
|
type userGroupService struct {
|
||||||
@@ -119,3 +123,25 @@ func (s *userGroupService) RemoveMember(ctx context.Context, groupID, userID str
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *userGroupService) AssignRoleToTenant(ctx context.Context, groupID, tenantID, relation string) error {
|
||||||
|
// Keto: Tenant:<tenantID>#<relation>@UserGroup:<groupID>#members
|
||||||
|
// This means all members of the group have the relation on the tenant.
|
||||||
|
subject := "UserGroup:" + groupID + "#members"
|
||||||
|
err := s.ketoService.CreateRelation(ctx, "Tenant", tenantID, relation, subject)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to assign group role to tenant in keto", "error", err, "group", groupID, "tenant", tenantID, "relation", relation)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *userGroupService) RemoveRoleFromTenant(ctx context.Context, groupID, tenantID, relation string) error {
|
||||||
|
subject := "UserGroup:" + groupID + "#members"
|
||||||
|
err := s.ketoService.DeleteRelation(ctx, "Tenant", tenantID, relation, subject)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to remove group role from tenant in keto", "error", err, "group", groupID, "tenant", tenantID, "relation", relation)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ class UserGroup implements Namespace {
|
|||||||
|
|
||||||
class Tenant implements Namespace {
|
class Tenant implements Namespace {
|
||||||
related: {
|
related: {
|
||||||
admins: User[]
|
admins: (User | SubjectSet<UserGroup, "members">)[]
|
||||||
members: User[]
|
members: (User | SubjectSet<UserGroup, "members">)[]
|
||||||
parent: Tenant[]
|
parent: Tenant[]
|
||||||
parent_group: TenantGroup[]
|
parent_group: TenantGroup[]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user