forked from baron/baron-sso
fix: improve keto sync reliability and initial rebac permissions for super admin
This commit is contained in:
@@ -2,52 +2,91 @@ package bootstrap
|
||||
|
||||
import (
|
||||
"baron-sso-backend/internal/domain"
|
||||
"baron-sso-backend/internal/service"
|
||||
"baron-sso-backend/internal/repository"
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// SyncKetoRelations synchronizes all existing DB users and tenants to Ory Keto.
|
||||
// SyncKetoRelations synchronizes all existing DB users, tenants and RPs to Ory Keto via Outbox.
|
||||
// This ensures data consistency for existing data when ReBAC is introduced.
|
||||
func SyncKetoRelations(db *gorm.DB, keto service.KetoService) error {
|
||||
slog.Info("🚀 Starting Keto ReBAC relation synchronization...")
|
||||
func SyncKetoRelations(db *gorm.DB, outbox repository.KetoOutboxRepository) error {
|
||||
slog.Info("🚀 Starting Keto ReBAC relation synchronization (via Outbox)...")
|
||||
ctx := context.Background()
|
||||
|
||||
// 1. Sync All Tenants (Ensure they exist in Keto if needed)
|
||||
// 1. Sync All Tenants
|
||||
var tenants []domain.Tenant
|
||||
if err := db.Find(&tenants).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
slog.Info("Syncing tenants to Keto", "count", len(tenants))
|
||||
slog.Info("Syncing tenants to Keto Outbox", "count", len(tenants))
|
||||
for _, t := range tenants {
|
||||
// Global Super Admin access to every tenant
|
||||
_ = outbox.Create(ctx, &domain.KetoOutbox{
|
||||
Namespace: "Tenant",
|
||||
Object: t.ID,
|
||||
Relation: "admins",
|
||||
Subject: "System:global#super_admins",
|
||||
Action: domain.KetoOutboxActionCreate,
|
||||
})
|
||||
|
||||
if t.ParentID != nil {
|
||||
_ = keto.CreateRelation(ctx, "Tenant", t.ID, "parents", "Tenant:"+*t.ParentID)
|
||||
_ = outbox.Create(ctx, &domain.KetoOutbox{
|
||||
Namespace: "Tenant",
|
||||
Object: t.ID,
|
||||
Relation: "parents",
|
||||
Subject: "Tenant:" + *t.ParentID,
|
||||
Action: domain.KetoOutboxActionCreate,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Sync All Users
|
||||
// 2. Sync All RelyingParties (if needed)
|
||||
// Note: We'll need a way to list them from Hydra or local DB if we had them.
|
||||
// Assuming they are in a table domain.RelyingParty (though it was removed, let's see)
|
||||
// Actually, the comment said SSOT is Hydra. But we might have them in a local table for metadata.
|
||||
// If not, we skip for now or fetch from Hydra.
|
||||
|
||||
// 3. Sync All Users Roles and Tenant Memberships
|
||||
var users []domain.User
|
||||
if err := db.Find(&users).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
slog.Info("Syncing users to Keto", "count", len(users))
|
||||
slog.Info("Syncing users to Keto Outbox", "count", len(users))
|
||||
for _, u := range users {
|
||||
role := domain.NormalizeRole(u.Role)
|
||||
// Membership
|
||||
// Tenant Membership
|
||||
if u.TenantID != nil {
|
||||
_ = keto.CreateRelation(ctx, "Tenant", *u.TenantID, "members", "User:"+u.ID)
|
||||
_ = outbox.Create(ctx, &domain.KetoOutbox{
|
||||
Namespace: "Tenant",
|
||||
Object: *u.TenantID,
|
||||
Relation: "members",
|
||||
Subject: "User:" + u.ID,
|
||||
Action: domain.KetoOutboxActionCreate,
|
||||
})
|
||||
}
|
||||
|
||||
// Roles
|
||||
role := domain.NormalizeRole(u.Role)
|
||||
if role == domain.RoleSuperAdmin {
|
||||
_ = keto.CreateRelation(ctx, "System", "global", "super_admins", "User:"+u.ID)
|
||||
_ = outbox.Create(ctx, &domain.KetoOutbox{
|
||||
Namespace: "System",
|
||||
Object: "global",
|
||||
Relation: "super_admins",
|
||||
Subject: "User:" + u.ID,
|
||||
Action: domain.KetoOutboxActionCreate,
|
||||
})
|
||||
} else if role == domain.RoleTenantAdmin && u.TenantID != nil {
|
||||
_ = keto.CreateRelation(ctx, "Tenant", *u.TenantID, "admins", "User:"+u.ID)
|
||||
_ = outbox.Create(ctx, &domain.KetoOutbox{
|
||||
Namespace: "Tenant",
|
||||
Object: *u.TenantID,
|
||||
Relation: "admins",
|
||||
Subject: "User:" + u.ID,
|
||||
Action: domain.KetoOutboxActionCreate,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("✅ Keto ReBAC synchronization completed.")
|
||||
slog.Info("✅ Keto ReBAC synchronization items added to Outbox.")
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user