Files
opsx-vpn/backend/internal/api/identity_gateway.go
T

63 lines
1.9 KiB
Go

package api
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
"vpn-platform/backend/internal/model"
"vpn-platform/backend/internal/nginxgateway"
"vpn-platform/backend/internal/service"
"vpn-platform/backend/internal/store"
"vpn-platform/backend/internal/tlsservice"
)
// Only a single OpenVPN WebAuth instance may own /oauth2/ on the management
// hostname. Never route an arbitrary user-supplied address to a local port.
func authGatewayPort(domain string) (int, error) {
var tunnels []model.Tunnel
if err := store.DB.Where("protocol = ? AND state = ?", "openvpn", "running").Find(&tunnels).Error; err != nil {
return 0, err
}
port := 0
for _, tunnel := range tunnels {
cfg, err := store.TunnelConfig(&tunnel)
if err != nil {
return 0, err
}
if service.Str(cfg, "auth_mode") != "oidc" || !strings.EqualFold(strings.TrimRight(service.Str(cfg, "oidc_base_url"), "/"), "https://"+domain) {
continue
}
if port != 0 {
return 0, &gatewayConflict{}
}
port = int(service.Num(cfg, "oidc_http_port", 0))
}
return port, nil
}
type gatewayConflict struct{}
func (*gatewayConflict) Error() string {
return "当前域名存在多条运行中的 OIDC 专线,请先保留一条"
}
func (s *Server) identityGateway(c *gin.Context) {
status := tlsservice.Status()
if !status.Valid || status.Mode != "nginx" || status.RestartRequired || nginxgateway.Stage() != "https" {
c.JSON(http.StatusBadRequest, gin.H{"error": "请先完成 Nginx HTTPS 入口配置"})
return
}
port, err := authGatewayPort(status.Domain)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if err := nginxgateway.RefreshAuth(status.Domain, s.router.Routes(), port); err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
store.Audit(c.GetString("username"), "identity_gateway_updated", status.Domain, "")
c.JSON(200, gin.H{"ok": true, "identity_route": true, "auth_route": port != 0, "auth_port": port})
}