forked from baron/baron-sso
삭제된 사용자 RP 관계 정리
This commit is contained in:
@@ -1768,6 +1768,11 @@ func (h *UserHandler) BulkDeleteUsers(c *fiber.Ctx) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.enqueueDeletedUserRelyingPartyCleanup(c.Context(), id); err != nil {
|
||||
results = append(results, map[string]any{"id": id, "success": false, "message": err.Error()})
|
||||
continue
|
||||
}
|
||||
|
||||
err = h.KratosAdmin.DeleteIdentity(c.Context(), id)
|
||||
if err != nil {
|
||||
results = append(results, map[string]any{"id": id, "success": false, "message": err.Error()})
|
||||
@@ -2222,6 +2227,10 @@ func (h *UserHandler) DeleteUser(c *fiber.Ctx) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.enqueueDeletedUserRelyingPartyCleanup(c.Context(), userID); err != nil {
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
if err := h.KratosAdmin.DeleteIdentity(c.Context(), userID); err != nil {
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
@@ -2255,6 +2264,102 @@ func (h *UserHandler) DeleteUser(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
|
||||
func (h *UserHandler) enqueueDeletedUserRelyingPartyCleanup(ctx context.Context, userID string) error {
|
||||
if h.KetoService == nil || h.KetoOutboxRepo == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
subject := "User:" + strings.TrimSpace(userID)
|
||||
tuples, err := h.listDeletedUserRelyingPartyRelations(ctx, subject)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list relying party relations for user %s: %w", userID, err)
|
||||
}
|
||||
|
||||
if len(tuples) == 0 {
|
||||
slog.Info("[UserHandler] No relying party relations found for deleted user cleanup", "userID", userID)
|
||||
return nil
|
||||
}
|
||||
|
||||
seen := make(map[string]struct{}, len(tuples))
|
||||
for _, tuple := range tuples {
|
||||
if strings.TrimSpace(tuple.Object) == "" || strings.TrimSpace(tuple.Relation) == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
relSubject := strings.TrimSpace(tuple.SubjectID)
|
||||
if relSubject == "" {
|
||||
relSubject = subject
|
||||
}
|
||||
|
||||
key := tuple.Namespace + "\x00" + tuple.Object + "\x00" + tuple.Relation + "\x00" + relSubject
|
||||
if _, exists := seen[key]; exists {
|
||||
continue
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
|
||||
namespace := strings.TrimSpace(tuple.Namespace)
|
||||
if namespace == "" {
|
||||
namespace = "RelyingParty"
|
||||
}
|
||||
|
||||
if err := h.KetoService.DeleteRelation(ctx, namespace, tuple.Object, tuple.Relation, relSubject); err != nil {
|
||||
slog.Warn("[UserHandler] Failed to delete RelyingParty relation immediately", "userID", userID, "namespace", namespace, "object", tuple.Object, "relation", tuple.Relation, "subject", relSubject, "error", err)
|
||||
}
|
||||
|
||||
if err := h.KetoOutboxRepo.Create(ctx, &domain.KetoOutbox{
|
||||
Namespace: namespace,
|
||||
Object: tuple.Object,
|
||||
Relation: tuple.Relation,
|
||||
Subject: relSubject,
|
||||
Action: domain.KetoOutboxActionDelete,
|
||||
}); err != nil {
|
||||
slog.Warn("[UserHandler] Failed to enqueue RelyingParty relation cleanup", "userID", userID, "namespace", namespace, "object", tuple.Object, "relation", tuple.Relation, "subject", relSubject, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *UserHandler) listDeletedUserRelyingPartyRelations(ctx context.Context, subject string) ([]service.RelationTuple, error) {
|
||||
var tuples []service.RelationTuple
|
||||
var err error
|
||||
|
||||
for attempt := 0; attempt < 3; attempt++ {
|
||||
tuples, err = h.KetoService.ListRelations(ctx, "RelyingParty", "", "", subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(tuples) > 0 {
|
||||
return tuples, nil
|
||||
}
|
||||
if attempt == 2 {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Duration(attempt+1) * 100 * time.Millisecond)
|
||||
}
|
||||
|
||||
fallbackEntries, err := h.KetoOutboxRepo.ListCurrentBySubject(ctx, "RelyingParty", subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(fallbackEntries) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tuples = make([]service.RelationTuple, 0, len(fallbackEntries))
|
||||
for _, entry := range fallbackEntries {
|
||||
tuples = append(tuples, service.RelationTuple{
|
||||
Namespace: entry.Namespace,
|
||||
Object: entry.Object,
|
||||
Relation: entry.Relation,
|
||||
SubjectID: entry.Subject,
|
||||
})
|
||||
}
|
||||
|
||||
slog.Warn("[UserHandler] Falling back to keto_outbox history for deleted user RP cleanup", "subject", subject, "tuples", len(tuples))
|
||||
return tuples, nil
|
||||
}
|
||||
|
||||
func (h *UserHandler) mapIdentitySummary(ctx context.Context, identity service.KratosIdentity) userSummary {
|
||||
traits := identity.Traits
|
||||
role := roleFromTraits(traits)
|
||||
|
||||
Reference in New Issue
Block a user