forked from baron/baron-sso
fix(backend): fix CSV export authentication by moving role validation inside the handler
This commit is contained in:
@@ -643,7 +643,7 @@ func main() {
|
||||
|
||||
// Admin User Management
|
||||
admin.Get("/users", requireAdmin, userHandler.ListUsers)
|
||||
admin.Get("/users/export", requireAdmin, userHandler.ExportUsersCSV)
|
||||
admin.Get("/users/export", userHandler.ExportUsersCSV) // Removed requireAdmin to handle mock role in query param
|
||||
admin.Post("/users", requireAdmin, userHandler.CreateUser)
|
||||
admin.Post("/users/bulk", requireAdmin, userHandler.BulkCreateUsers)
|
||||
admin.Put("/users/bulk", requireAdmin, userHandler.BulkUpdateUsers)
|
||||
|
||||
@@ -549,30 +549,46 @@ func (h *UserHandler) ExportUsersCSV(c *fiber.Ctx) error {
|
||||
|
||||
var requesterRole string
|
||||
var manageableSlugs []string
|
||||
|
||||
profile, _ := c.Locals("user_profile").(*domain.UserProfileResponse)
|
||||
|
||||
// [New] Support Role Mocking for Download (which doesn't have custom headers)
|
||||
if profile == nil {
|
||||
appEnv := strings.ToLower(os.Getenv("APP_ENV"))
|
||||
isDev := appEnv == "dev" || appEnv == "development" || appEnv == ""
|
||||
mockRole := c.Query("x-test-role")
|
||||
if isDev && mockRole != "" {
|
||||
slog.Info("🔑 [AUTH] Using mock role from query for export", "role", mockRole)
|
||||
requesterRole = mockRole
|
||||
// For tenant_admin, we might need more data, but let's assume super_admin for full export in dev
|
||||
} else {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "invalid session (trace:export_profile)")
|
||||
var profile *domain.UserProfileResponse
|
||||
|
||||
// [New] Manual profile resolution to support query-param role mocking
|
||||
// This is needed because browsers cannot send custom headers for direct downloads
|
||||
mockRole := c.Query("x-test-role")
|
||||
appEnv := strings.ToLower(os.Getenv("APP_ENV"))
|
||||
isDev := appEnv == "dev" || appEnv == "development" || appEnv == ""
|
||||
|
||||
if isDev && mockRole != "" {
|
||||
slog.Info("🔑 [AUTH] Using mock role from query for export", "role", mockRole)
|
||||
requesterRole = mockRole
|
||||
// In dev mocking, we might not have a full profile, but we need to know the manageable tenants if it's a tenant_admin
|
||||
if requesterRole == domain.RoleTenantAdmin {
|
||||
// Try to get actual profile if possible to get manageableTenants
|
||||
p, _ := c.Locals("user_profile").(*domain.UserProfileResponse)
|
||||
if p != nil {
|
||||
profile = p
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Use real profile from middleware
|
||||
p, ok := c.Locals("user_profile").(*domain.UserProfileResponse)
|
||||
if !ok || p == nil {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "invalid session (trace:export_auth)")
|
||||
}
|
||||
profile = p
|
||||
requesterRole = profile.Role
|
||||
if requesterRole == domain.RoleTenantAdmin {
|
||||
for _, t := range profile.ManageableTenants {
|
||||
manageableSlugs = append(manageableSlugs, strings.ToLower(t.Slug))
|
||||
}
|
||||
if profile.CompanyCode != "" {
|
||||
manageableSlugs = append(manageableSlugs, strings.ToLower(profile.CompanyCode))
|
||||
}
|
||||
}
|
||||
|
||||
// [New] Access Control: only admin roles can export
|
||||
if requesterRole != domain.RoleSuperAdmin && requesterRole != domain.RoleTenantAdmin {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: insufficient permissions for export")
|
||||
}
|
||||
|
||||
if profile != nil && requesterRole == domain.RoleTenantAdmin {
|
||||
for _, t := range profile.ManageableTenants {
|
||||
manageableSlugs = append(manageableSlugs, strings.ToLower(t.Slug))
|
||||
}
|
||||
if profile.CompanyCode != "" {
|
||||
manageableSlugs = append(manageableSlugs, strings.ToLower(profile.CompanyCode))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user