Files
opsx-vpn/backend/internal/identityprovider/admin.go
T

115 lines
3.4 KiB
Go

package identityprovider
import (
"net"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"vpn-platform/backend/internal/nginxgateway"
"vpn-platform/backend/internal/store"
)
func (p *Provider) Status(c *gin.Context) {
cfg, err := current()
if err != nil && err != gorm.ErrRecordNotFound {
c.JSON(500, gin.H{"error": "读取身份配置失败"})
return
}
base, tlsError := issuer()
if tlsError != nil {
base = ""
}
issuerRoute, _ := nginxgateway.AuthRouteReady(0)
callback, vpnCallback := "", ""
if base != "" {
callback, vpnCallback = base+"/feishu/callback", strings.TrimSuffix(base, "/id")+"/oauth2/callback"
}
c.JSON(200, gin.H{
"enabled": cfg.Enabled, "app_id": cfg.AppID, "app_secret_configured": cfg.AppSecret != "",
"tenant_key": cfg.TenantKey, "client_id": cfg.ClientID, "client_secret_configured": cfg.ClientSecret != "",
"issuer": base, "feishu_callback": callback, "vpn_callback": vpnCallback,
"tls_ready": tlsError == nil, "gateway_ready": issuerRoute,
})
}
func (p *Provider) Configure(c *gin.Context) {
if c.Request.TLS == nil {
peer, _, err := net.SplitHostPort(c.Request.RemoteAddr)
if err != nil || net.ParseIP(peer) == nil || !net.ParseIP(peer).IsLoopback() || c.GetHeader("X-Forwarded-Proto") != "https" {
c.JSON(http.StatusForbidden, gin.H{"error": "请通过可信 HTTPS 管理入口保存飞书凭据"})
return
}
}
var req struct {
Enabled bool `json:"enabled"`
AppID string `json:"app_id"`
AppSecret string `json:"app_secret"`
TenantKey string `json:"tenant_key"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": "配置格式错误"})
return
}
req.AppID = strings.TrimSpace(req.AppID)
req.TenantKey = strings.TrimSpace(req.TenantKey)
if len(req.AppID) > 128 || strings.ContainsAny(req.AppID, " \r\n\t") || (req.Enabled && (req.AppID == "" || !validTenant(req.TenantKey))) {
c.JSON(400, gin.H{"error": "请输入有效的飞书 App ID 和租户标识"})
return
}
if req.Enabled {
if _, err := issuer(); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
}
cfg, err := current()
if err != nil && err != gorm.ErrRecordNotFound {
c.JSON(500, gin.H{"error": "读取身份配置失败"})
return
}
if req.AppSecret != "" {
if len(req.AppSecret) > 512 {
c.JSON(400, gin.H{"error": "密钥过长"})
return
}
cfg.AppSecret, err = store.EncryptSecret(req.AppSecret)
if err != nil {
c.JSON(500, gin.H{"error": "密钥保存失败"})
return
}
}
if req.Enabled && cfg.AppSecret == "" {
c.JSON(400, gin.H{"error": "飞书 App Secret 未配置"})
return
}
var newClientSecret string
if cfg.ClientID == "" {
newClientSecret, err = randomToken()
if err != nil {
c.JSON(500, gin.H{"error": "凭据生成失败"})
return
}
cfg.ClientID = "opsx-vpn"
cfg.ClientSecret, err = store.EncryptSecret(newClientSecret)
if err != nil {
c.JSON(500, gin.H{"error": "凭据保存失败"})
return
}
}
if req.Enabled {
if _, _, err := signingKey(); err != nil {
c.JSON(503, gin.H{"error": "签名密钥初始化失败"})
return
}
}
cfg.ID, cfg.AppID, cfg.TenantKey, cfg.Enabled = 1, req.AppID, req.TenantKey, req.Enabled
if err := store.DB.Save(&cfg).Error; err != nil {
c.JSON(500, gin.H{"error": "身份配置保存失败"})
return
}
store.Audit(c.GetString("username"), "identity_provider_configured", "feishu", "")
c.JSON(http.StatusOK, gin.H{"ok": true, "client_id": cfg.ClientID})
}