forked from baron/baron-sso
145 lines
3.8 KiB
Go
145 lines
3.8 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/descope/go-sdk/descope"
|
|
"github.com/descope/go-sdk/descope/client"
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
type AdminHandler struct {
|
|
DescopeClient *client.DescopeClient
|
|
}
|
|
|
|
func NewAdminHandler() *AdminHandler {
|
|
projectID := os.Getenv("DESCOPE_PROJECT_ID")
|
|
managementKey := os.Getenv("DESCOPE_MANAGEMENT_KEY")
|
|
|
|
var descopeClient *client.DescopeClient
|
|
var err error
|
|
|
|
if projectID != "" && managementKey != "" {
|
|
descopeClient, err = client.NewWithConfig(&client.Config{
|
|
ProjectID: projectID,
|
|
ManagementKey: managementKey,
|
|
})
|
|
if err != nil {
|
|
log.Printf("Warning: Failed to initialize Descope Client for Admin: %v", err)
|
|
}
|
|
} else {
|
|
log.Println("Warning: DESCOPE_PROJECT_ID or DESCOPE_MANAGEMENT_KEY missing. Admin functions will fail.")
|
|
}
|
|
|
|
return &AdminHandler{
|
|
DescopeClient: descopeClient,
|
|
}
|
|
}
|
|
|
|
func boolPtr(b bool) *bool {
|
|
return &b
|
|
}
|
|
|
|
type CreateUserRequest struct {
|
|
LoginID string `json:"loginId"`
|
|
Email string `json:"email"`
|
|
Phone string `json:"phone"`
|
|
DisplayName string `json:"displayName"`
|
|
Roles []string `json:"roles"`
|
|
Tenants map[string][]string `json:"tenants"` // tenantId -> roles
|
|
}
|
|
|
|
func (h *AdminHandler) CreateUser(c *fiber.Ctx) error {
|
|
// 1. Simple Password Check
|
|
adminPass := os.Getenv("ADMIN_PASSWORD")
|
|
if adminPass == "" {
|
|
adminPass = "admin" // Default fallback
|
|
}
|
|
|
|
reqPass := c.Get("X-Admin-Password")
|
|
if reqPass != adminPass {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid Admin Password"})
|
|
}
|
|
|
|
if h.DescopeClient == nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Descope Client not configured"})
|
|
}
|
|
|
|
var req CreateUserRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"})
|
|
}
|
|
|
|
if req.LoginID == "" {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "LoginID is required"})
|
|
}
|
|
|
|
// Normalize Phone
|
|
normalizedPhone := req.Phone
|
|
if normalizedPhone != "" {
|
|
if strings.HasPrefix(normalizedPhone, "010") {
|
|
normalizedPhone = "+82" + normalizedPhone[1:]
|
|
} else if strings.HasPrefix(normalizedPhone, "82") {
|
|
normalizedPhone = "+" + normalizedPhone
|
|
}
|
|
}
|
|
|
|
userObj := &descope.UserRequest{
|
|
User: descope.User{
|
|
Email: req.Email,
|
|
Phone: normalizedPhone,
|
|
Name: req.DisplayName,
|
|
},
|
|
VerifiedEmail: boolPtr(req.Email != ""),
|
|
VerifiedPhone: boolPtr(normalizedPhone != ""),
|
|
}
|
|
|
|
// Add Roles if provided
|
|
if len(req.Roles) > 0 {
|
|
userObj.Roles = req.Roles
|
|
}
|
|
|
|
// Add Tenants if provided
|
|
if len(req.Tenants) > 0 {
|
|
// Convert map[string][]string to []*descope.AssociatedTenant
|
|
userTenants := []*descope.AssociatedTenant{}
|
|
for tenantID, roles := range req.Tenants {
|
|
userTenants = append(userTenants, &descope.AssociatedTenant{
|
|
TenantID: tenantID,
|
|
Roles: roles,
|
|
})
|
|
}
|
|
userObj.Tenants = userTenants
|
|
}
|
|
|
|
log.Printf("[Admin] Creating user: %s (Email: %s, Phone: %s)", req.LoginID, req.Email, normalizedPhone)
|
|
|
|
res, err := h.DescopeClient.Management.User().Create(context.Background(), req.LoginID, userObj)
|
|
if err != nil {
|
|
log.Printf("[Admin] Failed to create user: %v", err)
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"message": "User created successfully",
|
|
"user": res,
|
|
})
|
|
}
|
|
|
|
func (h *AdminHandler) CheckAuth(c *fiber.Ctx) error {
|
|
adminPass := os.Getenv("ADMIN_PASSWORD")
|
|
if adminPass == "" {
|
|
adminPass = "admin"
|
|
}
|
|
|
|
reqPass := c.Get("X-Admin-Password")
|
|
if reqPass != adminPass {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid Admin Password"})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "ok"})
|
|
}
|