package handler import ( "baron-sso-backend/internal/domain" "baron-sso-backend/internal/repository" "errors" "github.com/gofiber/fiber/v2" "gorm.io/gorm" ) // FederationHandler handles API requests for IdP federation configurations. type FederationHandler struct { Repo *repository.FederationRepository DB *gorm.DB // For tenant existence checks } // NewFederationHandler creates a new FederationHandler. func NewFederationHandler(repo *repository.FederationRepository, db *gorm.DB) *FederationHandler { return &FederationHandler{Repo: repo, DB: db} } // CreateIdpConfig handles the creation of a new IdP configuration. func (h *FederationHandler) CreateIdpConfig(c *fiber.Ctx) error { var req domain.IdentityProviderConfig if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid request body"}) } // Basic validation if req.TenantID == "" || req.DisplayName == "" || req.ProviderType == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "tenant_id, display_name, and provider_type are required"}) } // Check if tenant exists var tenant domain.Tenant if err := h.DB.First(&tenant, "id = ?", req.TenantID).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "tenant not found"}) } return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } if err := h.Repo.Create(&req); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.Status(fiber.StatusCreated).JSON(req) } // GetIdpConfigByID handles retrieving a single IdP configuration. func (h *FederationHandler) GetIdpConfigByID(c *fiber.Ctx) error { id := c.Params("id") config, err := h.Repo.GetByID(id) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } if config == nil { return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "identity provider configuration not found"}) } return c.JSON(config) } // ListIdpConfigsForTenant handles listing all IdP configurations for a tenant. func (h *FederationHandler) ListIdpConfigsForTenant(c *fiber.Ctx) error { tenantID := c.Params("tenantId") if tenantID == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "tenantId is required"}) } configs, err := h.Repo.ListByTenantID(tenantID) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(configs) } // UpdateIdpConfig handles updating an IdP configuration. func (h *FederationHandler) UpdateIdpConfig(c *fiber.Ctx) error { id := c.Params("id") existingConfig, err := h.Repo.GetByID(id) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } if existingConfig == nil { return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "identity provider configuration not found"}) } var req domain.IdentityProviderConfig if err := c.BodyParser(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid request body"}) } // Overwrite fields existingConfig.DisplayName = req.DisplayName existingConfig.Status = req.Status existingConfig.IssuerURL = req.IssuerURL existingConfig.ClientID = req.ClientID existingConfig.ClientSecret = req.ClientSecret existingConfig.Scopes = req.Scopes existingConfig.MetadataURL = req.MetadataURL existingConfig.MetadataXML = req.MetadataXML existingConfig.EntityID = req.EntityID existingConfig.AcsURL = req.AcsURL if err := h.Repo.Update(existingConfig); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.JSON(existingConfig) } // DeleteIdpConfig handles deleting an IdP configuration. func (h *FederationHandler) DeleteIdpConfig(c *fiber.Ctx) error { id := c.Params("id") if err := h.Repo.Delete(id); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return c.SendStatus(fiber.StatusNoContent) }