From 75af89f33d03451cbb6176bb0566c1a1de2de09f Mon Sep 17 00:00:00 2001 From: zhanghan Date: Fri, 8 Aug 2025 09:40:58 +0800 Subject: [PATCH] Integrate and debug the plug-in service token authentication --- cmd/server/app/network/controller/plugin.go | 202 ------------------ .../network/controller/pluginapi/script.go | 16 -- cmd/server/app/network/gateway.go | 4 +- cmd/server/app/network/httpserver.go | 86 +------- cmd/server/app/network/jwt/jwt.go | 40 +--- cmd/server/app/network/jwt/jwtPlugin.go | 51 ----- .../app/network/middleware/pluginauth.go | 31 +++ sdk/go-micro/registry/etcd.go | 2 +- sdk/plugin/client/machine.go | 12 +- 9 files changed, 44 insertions(+), 400 deletions(-) delete mode 100644 cmd/server/app/network/controller/plugin.go delete mode 100644 cmd/server/app/network/jwt/jwtPlugin.go create mode 100644 cmd/server/app/network/middleware/pluginauth.go diff --git a/cmd/server/app/network/controller/plugin.go b/cmd/server/app/network/controller/plugin.go deleted file mode 100644 index 0aed48d9..00000000 --- a/cmd/server/app/network/controller/plugin.go +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) KylinSoft Co., Ltd. 2024.All rights reserved. - * PilotGo licensed under the Mulan Permissive Software License, Version 2. - * See LICENSE file for more details. - * Author: linjieren - * Date: Thu Jul 25 16:18:53 2024 +0800 - */ -package controller - -import ( - "crypto/tls" - "net/http" - "net/http/httputil" - "net/url" - "strings" - "time" - - eventSDK "gitee.com/openeuler/PilotGo-plugins/event/sdk" - "gitee.com/openeuler/PilotGo/cmd/server/app/service/plugin" - commonSDK "gitee.com/openeuler/PilotGo/sdk/common" - "gitee.com/openeuler/PilotGo/sdk/logger" - "gitee.com/openeuler/PilotGo/sdk/response" - "gitee.com/openeuler/PilotGo/sdk/utils/httputils" - "github.com/gin-gonic/gin" -) - -// 查询插件清单 -func GetPluginsHandler(c *gin.Context) { - plugins, err := plugin.GetPlugins() - if err != nil { - response.Fail(c, nil, "查询插件错误:"+err.Error()) - return - } - - logger.Info("find %d plugins", len(plugins)) - response.Success(c, plugins, "插件查询成功") -} - -// 分页查询插件清单 -func GetPluginsPagedHandler(c *gin.Context) { - query := &response.PaginationQ{} - err := c.ShouldBindQuery(query) - if err != nil { - response.Fail(c, gin.H{"status": false}, err.Error()) - return - } - - num := query.PageSize * (query.Page - 1) - total, data, err := plugin.GetPluginPaged(num, query.PageSize) - if err != nil { - response.Fail(c, gin.H{"status": false}, err.Error()) - return - } - response.DataPagination(c, data, int(total), query) -} - -// 添加插件 -func AddPluginHandler(c *gin.Context) { - param := plugin.PluginParam{} - if err := c.BindJSON(¶m); err != nil { - response.Fail(c, nil, "参数错误") - return - } - - p, err := plugin.AddPlugin(¶m) - if err != nil { - response.Fail(c, nil, "add plugin failed:"+err.Error()) - return - } - - // 发布“插件添加”事件 - msgData := commonSDK.MessageData{ - MsgType: eventSDK.MsgPluginAdd, - MessageType: eventSDK.GetMessageTypeString(eventSDK.MsgPluginAdd), - TimeStamp: time.Now(), - Data: eventSDK.MDPluginChange{ - PluginName: p.Name, - Version: p.Version, - Url: p.Url, - Description: p.Description, - Status: true, - }, - } - msgDataString, err := msgData.ToMessageDataString() - if err != nil { - response.Fail(c, nil, err.Error()) - return - } - ms := commonSDK.EventMessage{ - MessageType: eventSDK.MsgPluginAdd, - MessageData: msgDataString, - } - plugin.PublishEvent(ms) - - response.Success(c, nil, "插件添加成功") -} - -// 停用/启动插件 -func TogglePluginHandler(c *gin.Context) { - param := struct { - UUID string `json:"uuid"` - Enable int `json:"enable"` - }{} - - if err := c.BindJSON(¶m); err != nil { - response.Fail(c, nil, "参数错误") - return - } - - logger.Info("toggle plugin:%s to enable %d", param.UUID, param.Enable) - if err := plugin.TogglePlugin(param.UUID, param.Enable); err != nil { - response.Fail(c, nil, "toggle plugin error:"+err.Error()) - return - } - //根据uuid从pluginmanage中获取本插件信息,并返回插件扩展点信息 - plugin, err := plugin.GetPluginByUUID(param.UUID) - if err != nil { - response.Fail(c, nil, "get plugin by uuid error:"+err.Error()) - } - response.Success(c, plugin.Extentions, "插件信息更新成功") -} - -// 卸载插件 -func UnloadPluginHandler(c *gin.Context) { - uuid := c.Param("uuid") - if uuid == "undefined" { - response.Fail(c, nil, "参数错误") - return - } - - p, err := plugin.GetPluginByUUID(uuid) //获取插件信息 - if err != nil { - logger.Error("get plugin by uuid error:%s", err.Error()) - response.Fail(c, nil, err.Error()) - return - } - - // 发布“插件卸载”事件 - msgData := commonSDK.MessageData{ - MsgType: eventSDK.MsgPluginRemove, - MessageType: eventSDK.GetMessageTypeString(eventSDK.MsgPluginRemove), - TimeStamp: time.Now(), - Data: eventSDK.MDPluginChange{ - PluginName: p.Name, - Version: p.Version, - Url: p.Url, - Description: p.Description, - }, - } - msgDataString, err := msgData.ToMessageDataString() - if err != nil { - response.Fail(c, nil, err.Error()) - return - } - ms := commonSDK.EventMessage{ - MessageType: eventSDK.MsgPluginRemove, - MessageData: msgDataString, - } - plugin.PublishEvent(ms) - - logger.Info("unload plugin:%s", uuid) - if err := plugin.DeletePlugin(uuid, p); err != nil { - return - } - response.Success(c, nil, "插件信息更新成功") -} - -func PluginGatewayHandler(c *gin.Context) { - name := c.Param("plugin_name") - p, err := plugin.GetPlugin(name) - if err != nil { - c.String(http.StatusNotFound, "plugin not found: "+err.Error()) - return - } - - s := strings.Replace(p.Url, "/plugin/"+name, "", 1) - ishttp, err := httputils.ServerIsHttp(s) - if err != nil { - c.String(http.StatusNotFound, "parse plugin url error: "+err.Error()) - return - } - if ishttp && strings.Split(s, "://")[0] == "https" { - s = "http://" + strings.Split(s, "://")[1] - } - if !ishttp && strings.Split(s, "://")[0] == "http" { - s = "https://" + strings.Split(s, "://")[1] - } - - target, err := url.Parse(s) - if err != nil { - c.String(http.StatusNotFound, "parse plugin url error: "+err.Error()) - return - } - logger.Debug("proxy plugin request to: %s", target) - c.Request.Host = target.Host - - proxy := httputil.NewSingleHostReverseProxy(target) - proxy.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - proxy.ServeHTTP(c.Writer, c.Request) -} diff --git a/cmd/server/app/network/controller/pluginapi/script.go b/cmd/server/app/network/controller/pluginapi/script.go index e7e0ff1e..cb2433fc 100644 --- a/cmd/server/app/network/controller/pluginapi/script.go +++ b/cmd/server/app/network/controller/pluginapi/script.go @@ -10,13 +10,11 @@ package pluginapi import ( - "net/http" "net/url" "strings" "time" "gitee.com/openeuler/PilotGo/cmd/server/app/agentmanager" - "gitee.com/openeuler/PilotGo/cmd/server/app/network/jwt" "gitee.com/openeuler/PilotGo/cmd/server/app/service/batch" "gitee.com/openeuler/PilotGo/cmd/server/app/service/plugin" "gitee.com/openeuler/PilotGo/cmd/server/app/service/script" @@ -29,20 +27,6 @@ import ( "github.com/gin-gonic/gin" ) -// 检查plugin接口调用权限 -func AuthCheck(c *gin.Context) { - _, err := jwt.ParsePluginClaims(c) - if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{ - "code": 401, - "msg": "plugin token check error:" + err.Error()}) - c.Abort() - return - } - - c.Next() -} - // 远程运行脚本 func RunCommandHandler(c *gin.Context) { logger.Debug("process get agent request") diff --git a/cmd/server/app/network/gateway.go b/cmd/server/app/network/gateway.go index ddc763f8..0ebc0ccd 100644 --- a/cmd/server/app/network/gateway.go +++ b/cmd/server/app/network/gateway.go @@ -114,7 +114,7 @@ func HttpGatewayServerInit(conf *options.ServerConfig, stopCh <-chan struct{}) e } func startGateway(ctx context.Context, conf *options.ServerConfig, addr *net.TCPAddr) error { - reg, err := registry.NewServiceRegistrar(®istry.Options{ + sr, err := registry.NewServiceRegistrar(®istry.Options{ Endpoints: conf.Etcd.Endpoints, ServiceAddr: addr.String(), ServiceName: conf.Etcd.ServiveName, @@ -150,7 +150,7 @@ func startGateway(ctx context.Context, conf *options.ServerConfig, addr *net.TCP } } - global.GW = gateway.NewCaddyGateway(reg, conf.HttpServer.Addr, watchCallback) + global.GW = gateway.NewCaddyGateway(sr.Registry, conf.HttpServer.Addr, watchCallback) go func() { if err := global.GW.Run(); err != nil { diff --git a/cmd/server/app/network/httpserver.go b/cmd/server/app/network/httpserver.go index 63518ced..f3294b6e 100644 --- a/cmd/server/app/network/httpserver.go +++ b/cmd/server/app/network/httpserver.go @@ -8,101 +8,17 @@ package network import ( - "context" - "net/http" - "strings" - - "gitee.com/openeuler/PilotGo/cmd/server/app/cmd/options" "gitee.com/openeuler/PilotGo/cmd/server/app/network/controller" "gitee.com/openeuler/PilotGo/cmd/server/app/network/controller/agentcontroller" "gitee.com/openeuler/PilotGo/cmd/server/app/network/controller/pluginapi" "gitee.com/openeuler/PilotGo/cmd/server/app/network/middleware" - "gitee.com/openeuler/PilotGo/cmd/server/app/network/websocket" "gitee.com/openeuler/PilotGo/cmd/server/app/resource" "gitee.com/openeuler/PilotGo/sdk/logger" "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" - "k8s.io/klog/v2" ) -func HttpServerInit(conf *options.HttpServer, stopCh <-chan struct{}) error { - if err := SessionManagerInit(conf); err != nil { - return err - } - - go func() { - r := SetupRouter() - // start websocket server - go websocket.CliManager.Start(stopCh) - - shutdownCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - - srv := &http.Server{ - Addr: conf.Addr, - Handler: r, - } - go func() { - <-stopCh - klog.Warningln("httpserver prepare stop") - _ = srv.Shutdown(shutdownCtx) - }() - // start http server - if conf.UseHttps { - if conf.CertFile == "" || conf.KeyFile == "" { - logger.Error("https cert or key not configd") - return - } - - logger.Info("start http service on: https://%s", conf.Addr) - - if err := srv.ListenAndServeTLS(conf.CertFile, conf.KeyFile); err != nil { - if err != http.ErrServerClosed { - logger.Error("ListenAndServeTLS start http server failed:%v", err) - return - } - } - } else { - logger.Info("start http service on: http://%s", conf.Addr) - if err := srv.ListenAndServe(); err != nil { - if err != http.ErrServerClosed { - logger.Error("ListenAndServe start http server failed:%v", err) - - } - - } - } - }() - - if conf.Debug { - go func() { - // pprof - portIndex := strings.Index(conf.Addr, ":") - addr := conf.Addr[:portIndex] + ":6060" - logger.Debug("start pprof service on: %s", addr) - if conf.UseHttps { - if conf.CertFile == "" || conf.KeyFile == "" { - logger.Error("https cert or key not configd") - return - } - - err := http.ListenAndServeTLS(addr, conf.CertFile, conf.KeyFile, nil) - if err != nil { - logger.Error("failed to start pprof, error:%v", err) - } - } else { - err := http.ListenAndServe(addr, nil) - if err != nil { - logger.Error("failed to start pprof, error:%v", err) - } - } - }() - } - - return nil -} - func SetupRouter() *gin.Engine { gin.SetMode(gin.ReleaseMode) router := gin.New() @@ -332,7 +248,7 @@ func registerAPIs(router *gin.Engine) { func registerPluginApi(router *gin.Engine) { api := router.Group("/api/v1") pluginAPI := api.Group("/pluginapi") - pluginAPI.Use(pluginapi.AuthCheck) + pluginAPI.Use(middleware.PluginAuthServiceCheck) { pluginAPI.POST("/upload", controller.Upload) diff --git a/cmd/server/app/network/jwt/jwt.go b/cmd/server/app/network/jwt/jwt.go index 089ad43b..a8272397 100644 --- a/cmd/server/app/network/jwt/jwt.go +++ b/cmd/server/app/network/jwt/jwt.go @@ -79,47 +79,9 @@ func parseMyClaims(c *gin.Context) (*UserClaims, error) { return m, nil } -type PluginClaims struct { - jwt.StandardClaims - - Name string - UUID string -} - func GeneratePluginToken(name, uuid string) (string, error) { - claims := &PluginClaims{ - Name: name, - UUID: uuid, - - StandardClaims: jwt.StandardClaims{ - IssuedAt: time.Now().Unix(), - Issuer: Issue, - Subject: "plugin token", - }, - } - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - tokenString, err := token.SignedString([]byte(config.OptionsConfig.JWT.SecretKey)) - if err != nil { - return "", err - } - return tokenString, nil -} -func ParsePluginClaims(c *gin.Context) (*PluginClaims, error) { - cookie, err := c.Request.Cookie("PluginToken") //Get authorization header - if err != nil { - return nil, err - } - - claims, err := parseClaims(cookie.Value, &PluginClaims{}) - if err != nil { - return nil, err - } - m, ok := claims.(*PluginClaims) - if !ok { - return nil, errors.New("invalid plugin claims") - } - return m, nil + return "", nil } func parseToken(tokenString string, clames jwt.Claims) (*jwt.Token, error) { diff --git a/cmd/server/app/network/jwt/jwtPlugin.go b/cmd/server/app/network/jwt/jwtPlugin.go deleted file mode 100644 index 37e8cf58..00000000 --- a/cmd/server/app/network/jwt/jwtPlugin.go +++ /dev/null @@ -1,51 +0,0 @@ -package jwt - -import ( - "errors" - "time" - - "gitee.com/openeuler/PilotGo/cmd/server/app/config" - "github.com/dgrijalva/jwt-go" - "github.com/gin-gonic/gin" -) - -type PluginServiceClaims struct { - jwt.StandardClaims - - ServiceName string -} - -func GeneratePluginServiceToken(serviceName string) (string, error) { - claims := &PluginServiceClaims{ - ServiceName: serviceName, - - StandardClaims: jwt.StandardClaims{ - IssuedAt: time.Now().Unix(), - Issuer: Issue, - Subject: "plugin token", - }, - } - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - tokenString, err := token.SignedString([]byte(config.OptionsConfig.JWT.SecretKey)) - if err != nil { - return "", err - } - return tokenString, nil -} - -func ParsePluginServiceClaims(c *gin.Context) (*PluginServiceClaims, error) { - cookie, err := c.Request.Cookie("PluginToken") - if err != nil { - return nil, err - } - - claims, err := parseClaims(cookie.Value, &PluginServiceClaims{}) - if err != nil { - return nil, err - } - m, ok := claims.(*PluginServiceClaims) - if !ok { - return nil, errors.New("invalid plugin claims") - } - return m, nil -} diff --git a/cmd/server/app/network/middleware/pluginauth.go b/cmd/server/app/network/middleware/pluginauth.go new file mode 100644 index 00000000..dee1d79e --- /dev/null +++ b/cmd/server/app/network/middleware/pluginauth.go @@ -0,0 +1,31 @@ +/* + * Copyright (c) KylinSoft Co., Ltd. 2024.All rights reserved. + * PilotGo licensed under the Mulan Permissive Software License, Version 2. + * See LICENSE file for more details. + * Author: zhanghan + * Date: Thu Aug 07 16:18:53 2025 +0800 + */ +package middleware + +import ( + "net/http" + + "gitee.com/openeuler/PilotGo/sdk/logger" + "gitee.com/openeuler/PilotGo/sdk/plugin/jwt" + "github.com/gin-gonic/gin" +) + +// 检查plugin接口调用权限 +func PluginAuthServiceCheck(c *gin.Context) { + _, err := jwt.ParsePluginServiceClaims(c) + if err != nil { + c.JSON(http.StatusUnauthorized, gin.H{ + "code": 401, + "msg": "plugin token check error:" + err.Error()}) + c.Abort() + logger.Info("ssss %v", err.Error()) + return + } + + c.Next() +} diff --git a/sdk/go-micro/registry/etcd.go b/sdk/go-micro/registry/etcd.go index 927a4fab..770dae9c 100644 --- a/sdk/go-micro/registry/etcd.go +++ b/sdk/go-micro/registry/etcd.go @@ -99,7 +99,7 @@ func (e *etcdRegistry) Deregister() error { } func (e *etcdRegistry) Get(key string) (*ServiceInfo, error) { - resp, err := e.client.Get(e.ctx, key) + resp, err := e.client.Get(e.ctx, "/services/"+key) if err != nil { return &ServiceInfo{}, err } diff --git a/sdk/plugin/client/machine.go b/sdk/plugin/client/machine.go index 85bc2294..8d0a3df1 100644 --- a/sdk/plugin/client/machine.go +++ b/sdk/plugin/client/machine.go @@ -10,16 +10,20 @@ package client import ( "encoding/json" "errors" + "fmt" "gitee.com/openeuler/PilotGo/sdk/common" "gitee.com/openeuler/PilotGo/sdk/utils/httputils" ) -func (c *Client) MachineList() ([]*common.MachineNode, error) { - if !c.IsBind() { - return nil, errors.New("unbind PilotGo-server platform") +func (c *CClient) MachineList() ([]*common.MachineNode, error) { + serverInfo, err := c.Registry.Get("pilotgo-server") + if err != nil { + return nil, err } - url := "http://" + c.Server() + "/api/v1/pluginapi/machine_list" + + url := fmt.Sprintf("http://%s:%s/api/v1/pluginapi/machine_list", serverInfo.Address, serverInfo.Port) + r, err := httputils.Get(url, &httputils.Params{ Cookie: map[string]string{ TokenCookie: c.token, -- Gitee