forked from baron/baron-sso
custom claim 권한체크 확인
This commit is contained in:
@@ -34,6 +34,7 @@ type DevHandler struct {
|
||||
SecretRepo domain.ClientSecretRepository
|
||||
AuditRepo domain.AuditRepository
|
||||
KratosAdmin service.KratosAdminService
|
||||
IdentityWriter service.IdentityWriteService
|
||||
ConsentRepo repository.ClientConsentRepository
|
||||
Keto service.KetoService
|
||||
KetoOutbox repository.KetoOutboxRepository
|
||||
@@ -78,13 +79,18 @@ func NewDevHandler(
|
||||
authProvider = auth[0]
|
||||
}
|
||||
|
||||
kratosAdmin := service.NewKratosAdminService()
|
||||
return &DevHandler{
|
||||
Hydra: service.NewHydraAdminService(),
|
||||
Redis: redis,
|
||||
HeadlessJWKS: service.NewHeadlessJWKSCacheService(redis, nil),
|
||||
SecretRepo: secretRepo,
|
||||
AuditRepo: nil,
|
||||
KratosAdmin: service.NewKratosAdminService(),
|
||||
KratosAdmin: kratosAdmin,
|
||||
IdentityWriter: service.NewIdentityWriteService(
|
||||
kratosAdmin,
|
||||
redis,
|
||||
),
|
||||
ConsentRepo: consentRepo,
|
||||
Keto: keto,
|
||||
KetoOutbox: ketoOutbox,
|
||||
@@ -233,6 +239,7 @@ type normalizedIDTokenClaim struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
ValueType string `json:"valueType"`
|
||||
Nullable bool `json:"nullable"`
|
||||
ReadPermission string `json:"readPermission"`
|
||||
WritePermission string `json:"writePermission"`
|
||||
}
|
||||
@@ -1659,7 +1666,17 @@ func (h *DevHandler) syncRPUserMetadataToKratos(ctx context.Context, userID stri
|
||||
}
|
||||
rawRPClaims[clientID] = metadata
|
||||
traits["rp_custom_claims"] = rawRPClaims
|
||||
_, err = h.KratosAdmin.UpdateIdentity(ctx, identity.ID, traits, identity.State)
|
||||
identityWriter := h.IdentityWriter
|
||||
if identityWriter == nil {
|
||||
identityWriter = service.NewIdentityWriteService(h.KratosAdmin, h.Redis)
|
||||
}
|
||||
_, err = identityWriter.UpdateIdentity(ctx, service.IdentityUpdateRequest{
|
||||
IdentityID: identity.ID,
|
||||
Traits: traits,
|
||||
State: identity.State,
|
||||
Reason: "rp_custom_claims_sync",
|
||||
Source: "dev_handler",
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update kratos rp user metadata: %w", err)
|
||||
}
|
||||
@@ -3459,8 +3476,11 @@ func normalizeIDTokenClaimsWithOptions(rawClaims any, allowTopLevel bool) ([]nor
|
||||
}
|
||||
|
||||
value := strings.TrimSpace(readInterfaceString(record["value"], ""))
|
||||
if _, err := parseConfiguredClaimValue(value, valueType); err != nil {
|
||||
return nil, fmt.Errorf("metadata.id_token_claims %s.%s is invalid: %w", namespace, key, err)
|
||||
nullable, _ := record["nullable"].(bool)
|
||||
if !(nullable && value == "") {
|
||||
if _, err := parseConfiguredClaimValue(value, valueType); err != nil {
|
||||
return nil, fmt.Errorf("metadata.id_token_claims %s.%s is invalid: %w", namespace, key, err)
|
||||
}
|
||||
}
|
||||
|
||||
signature := namespace + ":" + key
|
||||
@@ -3474,6 +3494,7 @@ func normalizeIDTokenClaimsWithOptions(rawClaims any, allowTopLevel bool) ([]nor
|
||||
Key: key,
|
||||
Value: value,
|
||||
ValueType: valueType,
|
||||
Nullable: nullable,
|
||||
ReadPermission: normalizeCustomClaimPermission(record["readPermission"]),
|
||||
WritePermission: normalizeCustomClaimPermission(record["writePermission"]),
|
||||
})
|
||||
@@ -3854,6 +3875,85 @@ func (h *DevHandler) countScopedDashboardAuditMetrics(
|
||||
return failureCount, int64(len(activeSessions)), nil
|
||||
}
|
||||
|
||||
func appendDevTenantUnique(tenants []domain.Tenant, tenant domain.Tenant) []domain.Tenant {
|
||||
tenantID := strings.TrimSpace(tenant.ID)
|
||||
tenantSlug := strings.TrimSpace(tenant.Slug)
|
||||
if tenantID == "" && tenantSlug == "" {
|
||||
return tenants
|
||||
}
|
||||
|
||||
for _, existing := range tenants {
|
||||
if tenantID != "" && strings.EqualFold(existing.ID, tenantID) {
|
||||
return tenants
|
||||
}
|
||||
if tenantSlug != "" && strings.EqualFold(existing.Slug, tenantSlug) {
|
||||
return tenants
|
||||
}
|
||||
}
|
||||
|
||||
return append(tenants, tenant)
|
||||
}
|
||||
|
||||
func shouldListDevManageableTenants(role string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(role)) {
|
||||
case "tenant_admin", "tenantadmin", "tenant-admin", "rp_admin", "admin":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func resolveDevProfileAppointmentTenants(ctx context.Context, tenantSvc service.TenantService, metadata map[string]any) []domain.Tenant {
|
||||
if tenantSvc == nil || metadata == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
appointments := userAppointmentSliceFromRaw(metadata["additionalAppointments"])
|
||||
if len(appointments) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
tenants := make([]domain.Tenant, 0, len(appointments))
|
||||
for _, raw := range appointments {
|
||||
appointment, ok := raw.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if tenantID := normalizeMetadataString(appointment["tenantId"]); tenantID != "" {
|
||||
if tenant, err := tenantSvc.GetTenant(ctx, tenantID); err == nil && tenant != nil {
|
||||
tenants = appendDevTenantUnique(tenants, *tenant)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if tenantID := normalizeMetadataString(appointment["tenant_id"]); tenantID != "" {
|
||||
if tenant, err := tenantSvc.GetTenant(ctx, tenantID); err == nil && tenant != nil {
|
||||
tenants = appendDevTenantUnique(tenants, *tenant)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if tenantSlug := normalizeMetadataString(appointment["tenantSlug"]); tenantSlug != "" {
|
||||
if tenant, err := tenantSvc.GetTenantBySlug(ctx, tenantSlug); err == nil && tenant != nil {
|
||||
tenants = appendDevTenantUnique(tenants, *tenant)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if tenantSlug := normalizeMetadataString(appointment["tenant_slug"]); tenantSlug != "" {
|
||||
if tenant, err := tenantSvc.GetTenantBySlug(ctx, tenantSlug); err == nil && tenant != nil {
|
||||
tenants = appendDevTenantUnique(tenants, *tenant)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if tenantSlug := normalizeMetadataString(appointment["slug"]); tenantSlug != "" {
|
||||
if tenant, err := tenantSvc.GetTenantBySlug(ctx, tenantSlug); err == nil && tenant != nil {
|
||||
tenants = appendDevTenantUnique(tenants, *tenant)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tenants
|
||||
}
|
||||
|
||||
// ListMyTenants returns the list of tenants the current user manages or belongs to.
|
||||
func (h *DevHandler) ListMyTenants(c *fiber.Ctx) error {
|
||||
profile, err := h.Auth.GetEnrichedProfile(c)
|
||||
@@ -3862,20 +3962,6 @@ func (h *DevHandler) ListMyTenants(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
role := normalizeUserRole(profile.Role)
|
||||
if role == domain.RoleUser {
|
||||
if profile.TenantID == nil || strings.TrimSpace(*profile.TenantID) == "" {
|
||||
return c.JSON([]domain.Tenant{})
|
||||
}
|
||||
tenant, err := h.TenantSvc.GetTenant(c.Context(), *profile.TenantID)
|
||||
if err != nil {
|
||||
return errorJSON(c, fiber.StatusInternalServerError, "failed to get tenant")
|
||||
}
|
||||
if tenant == nil {
|
||||
return c.JSON([]domain.Tenant{})
|
||||
}
|
||||
return c.JSON([]domain.Tenant{*tenant})
|
||||
}
|
||||
|
||||
if role == domain.RoleSuperAdmin {
|
||||
tenants, _, err := h.TenantSvc.ListTenants(c.Context(), 100, 0, "", "")
|
||||
if err != nil {
|
||||
@@ -3884,26 +3970,32 @@ func (h *DevHandler) ListMyTenants(c *fiber.Ctx) error {
|
||||
return c.JSON(tenants)
|
||||
}
|
||||
|
||||
tenants, err := h.TenantSvc.ListManageableTenants(c.Context(), profile.ID)
|
||||
if err != nil {
|
||||
return errorJSON(c, fiber.StatusInternalServerError, "failed to list manageable tenants: "+err.Error())
|
||||
tenants := make([]domain.Tenant, 0, 1+len(profile.JoinedTenants))
|
||||
if shouldListDevManageableTenants(profile.Role) {
|
||||
manageable, err := h.TenantSvc.ListManageableTenants(c.Context(), profile.ID)
|
||||
if err != nil {
|
||||
return errorJSON(c, fiber.StatusInternalServerError, "failed to list manageable tenants: "+err.Error())
|
||||
}
|
||||
for _, tenant := range manageable {
|
||||
tenants = appendDevTenantUnique(tenants, tenant)
|
||||
}
|
||||
}
|
||||
|
||||
if profile.TenantID != nil && *profile.TenantID != "" {
|
||||
found := false
|
||||
for _, t := range tenants {
|
||||
if t.ID == *profile.TenantID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
if primary, err := h.TenantSvc.GetTenant(c.Context(), *profile.TenantID); err == nil && primary != nil {
|
||||
tenants = append(tenants, *primary)
|
||||
}
|
||||
if primary, err := h.TenantSvc.GetTenant(c.Context(), *profile.TenantID); err != nil {
|
||||
return errorJSON(c, fiber.StatusInternalServerError, "failed to get tenant")
|
||||
} else if primary != nil {
|
||||
tenants = appendDevTenantUnique(tenants, *primary)
|
||||
}
|
||||
}
|
||||
|
||||
for _, tenant := range profile.JoinedTenants {
|
||||
tenants = appendDevTenantUnique(tenants, tenant)
|
||||
}
|
||||
for _, tenant := range resolveDevProfileAppointmentTenants(c.Context(), h.TenantSvc, profile.Metadata) {
|
||||
tenants = appendDevTenantUnique(tenants, tenant)
|
||||
}
|
||||
|
||||
return c.JSON(tenants)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user