mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-04 10:13:53 +08:00
Fix: Issue with invalid apikey parameter in service MCP path
This commit is contained in:
+29
-9
@@ -6,6 +6,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
application_authorization "github.com/APIParkLab/APIPark/module/application-authorization"
|
||||
|
||||
mcp_server "github.com/APIParkLab/APIPark/mcp-server"
|
||||
"github.com/APIParkLab/APIPark/module/mcp"
|
||||
"github.com/APIParkLab/APIPark/module/system"
|
||||
@@ -18,11 +20,12 @@ import (
|
||||
var _ IMcpController = (*imlMcpController)(nil)
|
||||
|
||||
type imlMcpController struct {
|
||||
settingModule system.ISettingModule `autowired:""`
|
||||
mcpModule mcp.IMcpModule `autowired:""`
|
||||
sessionKeys sync.Map
|
||||
server http.Handler
|
||||
openServer http.Handler
|
||||
settingModule system.ISettingModule `autowired:""`
|
||||
authorizationModule application_authorization.IAuthorizationModule `autowired:""`
|
||||
mcpModule mcp.IMcpModule `autowired:""`
|
||||
sessionKeys sync.Map
|
||||
server http.Handler
|
||||
openServer http.Handler
|
||||
}
|
||||
|
||||
var mcpDefaultConfig = `{
|
||||
@@ -85,11 +88,12 @@ func (i *imlMcpController) GlobalMCPHandle(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
func (i *imlMcpController) GlobalHandleSSE(ctx *gin.Context) {
|
||||
i.handleSSE(ctx, i.openServer)
|
||||
apikey := ctx.Request.URL.Query().Get("apikey")
|
||||
i.handleSSE(ctx, i.openServer, apikey)
|
||||
}
|
||||
|
||||
func (i *imlMcpController) handleSSE(ctx *gin.Context, server http.Handler) {
|
||||
apikey := ctx.Request.URL.Query().Get("apikey")
|
||||
func (i *imlMcpController) handleSSE(ctx *gin.Context, server http.Handler, apikey string) {
|
||||
|
||||
writer := &ResponseWriter{
|
||||
Writer: ctx.Writer,
|
||||
sessionId: make(chan string),
|
||||
@@ -120,7 +124,23 @@ func (i *imlMcpController) MCPHandle(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
func (i *imlMcpController) ServiceHandleSSE(ctx *gin.Context) {
|
||||
i.handleSSE(ctx, mcp_server.DefaultMCPServer())
|
||||
apikey := ctx.Request.URL.Query().Get("apikey")
|
||||
serviceId := ctx.Param("serviceId")
|
||||
if serviceId == "" {
|
||||
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid service id", "success": "fail"})
|
||||
return
|
||||
}
|
||||
ok, err := i.authorizationModule.CheckAPIKeyAuthorization(ctx, serviceId, apikey)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": err.Error(), "success": "fail"})
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
ctx.AbortWithStatusJSON(403, gin.H{"code": -1, "msg": "invalid apikey", "success": "fail"})
|
||||
return
|
||||
}
|
||||
|
||||
i.handleSSE(ctx, mcp_server.DefaultMCPServer(), apikey)
|
||||
}
|
||||
|
||||
func (i *imlMcpController) ServiceHandleMessage(ctx *gin.Context) {
|
||||
|
||||
@@ -16,6 +16,7 @@ type IAPIKeyController interface {
|
||||
Search(ctx *gin.Context, keyword string) ([]*system_apikey_dto.Item, error)
|
||||
SimpleList(ctx *gin.Context) ([]*system_apikey_dto.SimpleItem, error)
|
||||
MyAPIKeys(ctx *gin.Context) ([]*system_apikey_dto.SimpleItem, error)
|
||||
MyAPIKeysByService(ctx *gin.Context, serviceId string) ([]*system_apikey_dto.SimpleItem, error)
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -12,6 +12,10 @@ type imlAPIKeyController struct {
|
||||
apikeyModule system_apikey.IAPIKeyModule `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlAPIKeyController) MyAPIKeysByService(ctx *gin.Context, serviceId string) ([]*system_apikey_dto.SimpleItem, error) {
|
||||
return i.apikeyModule.MyAPIKeysByService(ctx, serviceId)
|
||||
}
|
||||
|
||||
func (i *imlAPIKeyController) MyAPIKeys(ctx *gin.Context) ([]*system_apikey_dto.SimpleItem, error) {
|
||||
return i.apikeyModule.MyAPIKeys(ctx)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package auth_driver
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
|
||||
application_authorization_dto "github.com/APIParkLab/APIPark/module/application-authorization/dto"
|
||||
)
|
||||
|
||||
@@ -83,6 +83,6 @@ func generateStruct[T any](cfg interface{}) (*T, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ package oauth2
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
|
||||
auth_driver "github.com/APIParkLab/APIPark/module/application-authorization/auth-driver"
|
||||
|
||||
|
||||
application_authorization_dto "github.com/APIParkLab/APIPark/module/application-authorization/dto"
|
||||
)
|
||||
|
||||
@@ -33,7 +33,7 @@ func (cfg *Config) ID() string {
|
||||
}
|
||||
|
||||
func (cfg *Config) Valid() ([]byte, error) {
|
||||
|
||||
|
||||
if cfg.HashSecret && !cfg.Hashed {
|
||||
// 未加密
|
||||
secret, err := hashSecret([]byte(cfg.ClientSecret), 0, 0, 0)
|
||||
@@ -48,9 +48,9 @@ func (cfg *Config) Valid() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (cfg *Config) Detail() []application_authorization_dto.DetailItem {
|
||||
|
||||
|
||||
redirectURLs, _ := json.Marshal(cfg.RedirectUrls)
|
||||
|
||||
|
||||
return []application_authorization_dto.DetailItem{
|
||||
{Key: "客户端ID", Value: cfg.ClientId},
|
||||
{Key: "客户端密钥", Value: cfg.ClientSecret},
|
||||
|
||||
@@ -2,9 +2,10 @@ package application_authorization
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/APIParkLab/APIPark/module/system"
|
||||
"reflect"
|
||||
|
||||
"github.com/APIParkLab/APIPark/module/system"
|
||||
|
||||
application_authorization_dto "github.com/APIParkLab/APIPark/module/application-authorization/dto"
|
||||
|
||||
"github.com/APIParkLab/APIPark/gateway"
|
||||
@@ -31,6 +32,9 @@ type IAuthorizationModule interface {
|
||||
Detail(ctx context.Context, appId string, aid string) ([]application_authorization_dto.DetailItem, error)
|
||||
// Info 获取项目鉴权详情
|
||||
Info(ctx context.Context, appId string, aid string) (*application_authorization_dto.Authorization, error)
|
||||
|
||||
CheckAPIKeyAuthorization(ctx context.Context, serviceId string, apikey string) (bool, error)
|
||||
|
||||
//ExportAll(ctx context.Context) ([]*application_authorization_dto.ExportAuthorization, error)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/APIParkLab/APIPark/service/subscribe"
|
||||
|
||||
application_authorization "github.com/APIParkLab/APIPark/service/application-authorization"
|
||||
|
||||
"github.com/eolinker/eosc/log"
|
||||
@@ -36,11 +38,80 @@ var (
|
||||
|
||||
type imlAuthorizationModule struct {
|
||||
serviceService service.IServiceService `autowired:""`
|
||||
subscribeService subscribe.ISubscribeService `autowired:""`
|
||||
authorizationService application_authorization.IAuthorizationService `autowired:""`
|
||||
clusterService cluster.IClusterService `autowired:""`
|
||||
transaction store.ITransaction `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlAuthorizationModule) CheckAPIKeyAuthorization(ctx context.Context, serviceId string, apikey string) (bool, error) {
|
||||
list, err := i.subscribeService.ListBySubscribeStatus(ctx, serviceId, subscribe.ApplyStatusSubscribe)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(list) < 1 {
|
||||
return false, fmt.Errorf("no application found")
|
||||
}
|
||||
appIds := utils.SliceToSlice(list, func(s *subscribe.Subscribe) string {
|
||||
return s.Application
|
||||
})
|
||||
authorizations, err := i.authorizationService.ListByApp(ctx, appIds...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, a := range authorizations {
|
||||
if a.Type != "apikey" {
|
||||
continue
|
||||
}
|
||||
cfg := make(map[string]interface{})
|
||||
if a.Config != "" {
|
||||
json.Unmarshal([]byte(a.Config), &cfg)
|
||||
}
|
||||
if cfg["apikey"] == apikey {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (i *imlAuthorizationModule) AuthorizationsByService(ctx context.Context, serviceId string, authorizationType string) ([]*application_authorization_dto.Authorization, error) {
|
||||
list, err := i.subscribeService.ListBySubscribeStatus(ctx, serviceId, subscribe.ApplyStatusSubscribe)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(list) < 1 {
|
||||
return nil, fmt.Errorf("no application found")
|
||||
}
|
||||
appIds := utils.SliceToSlice(list, func(s *subscribe.Subscribe) string {
|
||||
return s.Application
|
||||
})
|
||||
authorizations, err := i.authorizationService.ListByApp(ctx, appIds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]*application_authorization_dto.Authorization, 0, len(authorizations))
|
||||
for _, a := range authorizations {
|
||||
if authorizationType != "" && a.Type != authorizationType {
|
||||
continue
|
||||
}
|
||||
cfg := make(map[string]interface{})
|
||||
if a.Config != "" {
|
||||
json.Unmarshal([]byte(a.Config), &cfg)
|
||||
}
|
||||
result = append(result, &application_authorization_dto.Authorization{
|
||||
UUID: a.UUID,
|
||||
Name: a.Name,
|
||||
Driver: a.Type,
|
||||
Position: a.Position,
|
||||
TokenName: a.TokenName,
|
||||
Config: cfg,
|
||||
ExpireTime: a.ExpireTime,
|
||||
HideCredential: a.HideCredential,
|
||||
})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (i *imlAuthorizationModule) ExportAll(ctx context.Context) ([]*application_authorization_dto.ExportAuthorization, error) {
|
||||
list, err := i.authorizationService.List(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -3,8 +3,11 @@ package system_apikey
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/APIParkLab/APIPark/service/subscribe"
|
||||
|
||||
application_authorization "github.com/APIParkLab/APIPark/service/application-authorization"
|
||||
|
||||
"github.com/APIParkLab/APIPark/service/service"
|
||||
@@ -34,9 +37,71 @@ type imlAPIKeyModule struct {
|
||||
teamMemberService team_member.ITeamMemberService `autowired:""`
|
||||
serviceService service.IServiceService `autowired:""`
|
||||
applicationAuthorizationService application_authorization.IAuthorizationService `autowired:""`
|
||||
subscribeService subscribe.ISubscribeService `autowired:""`
|
||||
transaction store.ITransaction `autowired:""`
|
||||
}
|
||||
|
||||
func (i *imlAPIKeyModule) MyAPIKeysByService(ctx context.Context, serviceId string) ([]*system_apikey_dto.SimpleItem, error) {
|
||||
list, err := i.subscribeService.ListBySubscribeStatus(ctx, serviceId, subscribe.ApplyStatusSubscribe)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(list) < 1 {
|
||||
return nil, fmt.Errorf("no subscriber found")
|
||||
}
|
||||
appMap := utils.SliceToMapO(list, func(a *subscribe.Subscribe) (string, struct{}) {
|
||||
return a.Application, struct{}{}
|
||||
})
|
||||
members, err := i.teamMemberService.Members(ctx, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(members) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
teamIds := utils.SliceToSlice(members, func(m *team_member.Member) string {
|
||||
return m.Come
|
||||
})
|
||||
apps, err := i.serviceService.AppListByTeam(ctx, teamIds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appIds := utils.SliceToSlice(apps, func(a *service.Service) string {
|
||||
return a.Id
|
||||
}, func(s *service.Service) bool {
|
||||
if _, ok := appMap[s.Id]; !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if len(appIds) < 1 {
|
||||
return nil, fmt.Errorf("no app found")
|
||||
}
|
||||
auths, err := i.applicationAuthorizationService.ListByApp(ctx, appIds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]*system_apikey_dto.SimpleItem, 0, len(auths))
|
||||
for _, a := range auths {
|
||||
if a.Type != "apikey" {
|
||||
continue
|
||||
}
|
||||
m := make(map[string]string)
|
||||
json.Unmarshal([]byte(a.Config), &m)
|
||||
if m["apikey"] == "" {
|
||||
continue
|
||||
}
|
||||
result = append(result, &system_apikey_dto.SimpleItem{
|
||||
Id: a.UUID,
|
||||
Name: a.Name,
|
||||
Value: m["apikey"],
|
||||
Expired: a.ExpireTime,
|
||||
})
|
||||
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (i *imlAPIKeyModule) MyAPIKeys(ctx context.Context) ([]*system_apikey_dto.SimpleItem, error) {
|
||||
members, err := i.teamMemberService.Members(ctx, nil, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -18,6 +18,7 @@ type IAPIKeyModule interface {
|
||||
Search(ctx context.Context, keyword string) ([]*system_apikey_dto.Item, error)
|
||||
SimpleList(ctx context.Context) ([]*system_apikey_dto.SimpleItem, error)
|
||||
MyAPIKeys(ctx context.Context) ([]*system_apikey_dto.SimpleItem, error)
|
||||
MyAPIKeysByService(ctx context.Context, serviceId string) ([]*system_apikey_dto.SimpleItem, error)
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -23,7 +23,8 @@ func (p *plugin) systemApikeyApis() []pm3.Api {
|
||||
pm3.CreateApiWidthDoc(http.MethodPut, "/api/v1/system/apikey", []string{"context", "query:apikey", "body"}, nil, p.systemAPIKeyController.Update),
|
||||
pm3.CreateApiWidthDoc(http.MethodDelete, "/api/v1/system/apikey", []string{"context", "query:apikey"}, nil, p.systemAPIKeyController.Delete),
|
||||
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/system/apikeys", []string{"context", "query:keyword"}, []string{"apikeys"}, p.systemAPIKeyController.Search),
|
||||
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/my/apikeys/", []string{"context"}, []string{"apikeys"}, p.systemAPIKeyController.MyAPIKeys),
|
||||
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/my/apikeys", []string{"context"}, []string{"apikeys"}, p.systemAPIKeyController.MyAPIKeys),
|
||||
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/my/apikeys/:serviceId", []string{"context", "path:serviceId"}, []string{"apikeys"}, p.systemAPIKeyController.MyAPIKeysByService),
|
||||
pm3.CreateApiWidthDoc(http.MethodGet, "/api/v1/simple/system/apikeys", []string{"context"}, []string{"apikeys"}, p.systemAPIKeyController.SimpleList),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,16 @@ import (
|
||||
func (p *plugin) mcpAPIs() []pm3.Api {
|
||||
globalMessagePath := fmt.Sprintf("/openapi/v1/%s/message", strings.Trim(mcp_server.GlobalBasePath, "/"))
|
||||
serviceMessagePath := fmt.Sprintf("/openapi/v1/%s/:serviceId/message", strings.Trim(mcp_server.ServiceBasePath, "/"))
|
||||
serviceSSEPath := fmt.Sprintf("/openapi/v1/%s/:serviceId/sse", strings.Trim(mcp_server.ServiceBasePath, "/"))
|
||||
ignore.IgnorePath("openapi", http.MethodPost, globalMessagePath)
|
||||
|
||||
ignore.IgnorePath("openapi", http.MethodGet, serviceSSEPath)
|
||||
ignore.IgnorePath("openapi", http.MethodPost, serviceMessagePath)
|
||||
|
||||
return []pm3.Api{
|
||||
pm3.CreateApiSimple(http.MethodGet, fmt.Sprintf("/openapi/v1/%s/sse", strings.Trim(mcp_server.GlobalBasePath, "/")), p.mcpController.GlobalHandleSSE),
|
||||
pm3.CreateApiSimple(http.MethodPost, globalMessagePath, p.mcpController.GlobalHandleMessage),
|
||||
pm3.CreateApiSimple(http.MethodGet, fmt.Sprintf("/openapi/v1/%s/:serviceId/sse", strings.Trim(mcp_server.ServiceBasePath, "/")), p.mcpController.ServiceHandleSSE),
|
||||
pm3.CreateApiSimple(http.MethodGet, serviceSSEPath, p.mcpController.ServiceHandleSSE),
|
||||
pm3.CreateApiSimple(http.MethodPost, serviceMessagePath, p.mcpController.ServiceHandleMessage),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ type ISubscribeService interface {
|
||||
|
||||
MySubscribeServices(ctx context.Context, application string, serviceIDs []string) ([]*Subscribe, error)
|
||||
UpdateSubscribeStatus(ctx context.Context, application string, service string, status int) error
|
||||
ListBySubscribeStatus(ctx context.Context, projectId string, status int) ([]*Subscribe, error)
|
||||
SubscribersByProject(ctx context.Context, projectIds ...string) ([]*Subscribe, error)
|
||||
ListBySubscribeStatus(ctx context.Context, serviceId string, status int) ([]*Subscribe, error)
|
||||
SubscribersByProject(ctx context.Context, serviceIds ...string) ([]*Subscribe, error)
|
||||
Subscribers(ctx context.Context, project string, status int) ([]*Subscribe, error)
|
||||
SubscriptionsByApplication(ctx context.Context, applicationIds ...string) ([]*Subscribe, error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user