Add opt-in built-in Feishu OIDC issuer for OpenVPN
This commit is contained in:
1 parent
6ca609fde4
commit
63cdda4ae1
23 files changed
+1244
-17
No files matched your search
@@ -0,0 +1,114 @@
|
||||
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})
|
||||
}
|
||||
Reference in new issue
Block a user