You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2021/05/29 11:08:19 UTC
[servicecomb-service-center] branch master updated: SCB-2176 Fix:
targetResource label key not exist should be pass (#1019)
This is an automated email from the ASF dual-hosted git repository.
littlecui pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-service-center.git
The following commit(s) were added to refs/heads/master by this push:
new d9b8ba8 SCB-2176 Fix: targetResource label key not exist should be pass (#1019)
d9b8ba8 is described below
commit d9b8ba8fea32d852bdb5a79b04cb82e654169660
Author: little-cui <su...@qq.com>
AuthorDate: Sat May 29 19:08:12 2021 +0800
SCB-2176 Fix: targetResource label key not exist should be pass (#1019)
* SCB-2176 Fix: targetResource label key not exist should be pass
* SCB-2176 Refactor parse UTs
* SCB-2176 Resolve comments
---
pkg/rest/util.go | 19 ++
server/plugin/auth/buildin/parser.go | 34 ++-
server/plugin/auth/buildin/parser_test.go | 318 ++++++++++++++++++++-------
server/plugin/auth/buildin/service_parser.go | 231 +++++++++++++------
server/plugin/auth/types.go | 4 +-
server/response/response.go | 1 -
server/service/rbac/rbac.go | 2 +-
server/service/rbac/resource.go | 2 +-
8 files changed, 446 insertions(+), 165 deletions(-)
diff --git a/pkg/rest/util.go b/pkg/rest/util.go
index b5b108d..d707b55 100644
--- a/pkg/rest/util.go
+++ b/pkg/rest/util.go
@@ -18,7 +18,10 @@
package rest
import (
+ "bytes"
"encoding/json"
+ "errors"
+ "io/ioutil"
"net/http"
"github.com/apache/servicecomb-service-center/pkg/log"
@@ -26,6 +29,8 @@ import (
"github.com/go-chassis/cari/discovery"
)
+var errNilRequestBody = errors.New("request body is nil")
+
func WriteError(w http.ResponseWriter, code int32, detail string) {
err := discovery.NewError(code, detail)
w.Header().Set(HeaderContentType, ContentTypeJSON)
@@ -78,3 +83,17 @@ func WriteResponse(w http.ResponseWriter, r *http.Request, resp *discovery.Respo
func WriteSuccess(w http.ResponseWriter, r *http.Request) {
WriteResponse(w, r, nil, nil)
}
+
+// ReadBody can re-read the request body
+func ReadBody(r *http.Request) ([]byte, error) {
+ if r.Body == nil {
+ return nil, errNilRequestBody
+ }
+
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, err
+ }
+ r.Body = ioutil.NopCloser(bytes.NewReader(data))
+ return data, nil
+}
diff --git a/server/plugin/auth/buildin/parser.go b/server/plugin/auth/buildin/parser.go
index 821f251..1cd3e71 100644
--- a/server/plugin/auth/buildin/parser.go
+++ b/server/plugin/auth/buildin/parser.go
@@ -18,6 +18,7 @@
package buildin
import (
+ "errors"
"fmt"
"github.com/apache/servicecomb-service-center/pkg/log"
"github.com/apache/servicecomb-service-center/pkg/rest"
@@ -28,20 +29,23 @@ import (
"strings"
)
-var (
- //TODO ...
- APIAccountList = "/v4/accounts"
- APIRoleList = "/v4/roles"
- APIOps = "/v4/:project/admin"
- APIGov = "/v1/:project/gov"
-)
+var ErrCtxMatchPatternNotFound = errors.New("CtxMatchPattern not found")
var APIMapping = map[string]ParseFunc{}
-type ParseFunc func(r *http.Request) ([]map[string]string, error)
+type ParseFunc func(r *http.Request) (*auth.ResourceScope, error)
-func ApplyAll(_ *http.Request) ([]map[string]string, error) {
- return nil, nil
+// ApplyAll work when no api registered by RegisterParseFunc matched
+func ApplyAll(r *http.Request) (*auth.ResourceScope, error) {
+ apiPath, ok := r.Context().Value(rest.CtxMatchPattern).(string)
+ if !ok {
+ log.Error("CtxMatchPattern not found", nil)
+ return nil, ErrCtxMatchPatternNotFound
+ }
+ return &auth.ResourceScope{
+ Type: rbacmodel.GetResource(apiPath),
+ Verb: rbac.MethodToVerbs[r.Method],
+ }, nil
}
func FromRequest(r *http.Request) *auth.ResourceScope {
@@ -51,17 +55,11 @@ func FromRequest(r *http.Request) *auth.ResourceScope {
return nil
}
- resource := rbacmodel.GetResource(apiPath)
- labels, err := GetAPIParseFunc(apiPath)(r)
+ resource, err := GetAPIParseFunc(apiPath)(r)
if err != nil {
log.Error(fmt.Sprintf("parse from request failed"), err)
- return nil
- }
- return &auth.ResourceScope{
- Type: resource,
- Labels: labels,
- Verb: rbac.MethodToVerbs[r.Method],
}
+ return resource
}
func GetAPIParseFunc(apiPattern string) ParseFunc {
diff --git a/server/plugin/auth/buildin/parser_test.go b/server/plugin/auth/buildin/parser_test.go
index 418747e..fa7eeef 100644
--- a/server/plugin/auth/buildin/parser_test.go
+++ b/server/plugin/auth/buildin/parser_test.go
@@ -18,20 +18,26 @@
package buildin_test
import (
+ _ "github.com/apache/servicecomb-service-center/test"
+
"context"
"net/http"
"strings"
"testing"
- _ "github.com/apache/servicecomb-service-center/test"
-
"github.com/apache/servicecomb-service-center/datasource"
+ "github.com/apache/servicecomb-service-center/pkg/rest"
+ "github.com/apache/servicecomb-service-center/pkg/util"
+ "github.com/apache/servicecomb-service-center/server/plugin/auth"
"github.com/apache/servicecomb-service-center/server/plugin/auth/buildin"
+ "github.com/apache/servicecomb-service-center/server/service/rbac"
"github.com/go-chassis/cari/discovery"
"github.com/stretchr/testify/assert"
)
func TestGetAPIParseFunc(t *testing.T) {
+ rbac.InitResourceMap()
+
var serviceIDA, serviceIDB string
response, _ := datasource.Instance().RegisterService(context.Background(), &discovery.CreateServiceRequest{
@@ -49,85 +55,235 @@ func TestGetAPIParseFunc(t *testing.T) {
})
serviceIDB = response.ServiceId
- t.Run("get all services api should return no labels", func(t *testing.T) {
- request, err := http.NewRequest(http.MethodGet, "/v4/default/registry/microservices", nil)
- assert.NoError(t, err)
-
- labels, err := buildin.GetAPIParseFunc("/v4/:project/registry/microservices")(request)
- assert.NoError(t, err)
- assert.Nil(t, labels)
- })
-
- t.Run("create services api without body should return err", func(t *testing.T) {
- reader := strings.NewReader("{}")
-
- request, err := http.NewRequest(http.MethodPost, "/v4/default/registry/microservices", reader)
- assert.NoError(t, err)
-
- _, err = buildin.GetAPIParseFunc("/v4/:project/registry/microservices")(request)
- assert.Error(t, err)
- })
-
- t.Run("create services api with serviceName A should return A", func(t *testing.T) {
- reader := strings.NewReader("{\n \"service\": {\n \"serviceName\": \"A\"\n }\n}")
-
- request, err := http.NewRequest(http.MethodPost, "/v4/default/registry/microservices", reader)
- assert.NoError(t, err)
-
- labels, err := buildin.GetAPIParseFunc("/v4/:project/registry/microservices")(request)
- assert.NoError(t, err)
- assert.Equal(t, 1, len(labels))
- assert.Equal(t, "A", labels[0]["serviceName"])
- })
-
- t.Run("delete 2 services api should return 2 labels", func(t *testing.T) {
- reader := strings.NewReader("{\n \"serviceIds\": [\"" + serviceIDA + "\", \"" + serviceIDB + "\"]\n}")
-
- request, err := http.NewRequest(http.MethodDelete, "/v4/default/registry/microservices", reader)
- assert.NoError(t, err)
-
- labels, err := buildin.GetAPIParseFunc("/v4/:project/registry/microservices")(request)
- assert.NoError(t, err)
- assert.Equal(t, 2, len(labels))
- assert.Equal(t, "A", labels[0]["serviceName"])
- })
-
- t.Run("get service sub resource api should return service labels", func(t *testing.T) {
- request, err := http.NewRequest(http.MethodGet, "/v4/default/registry/microservices/"+serviceIDA+"/instances?:serviceId="+serviceIDA, nil)
- assert.NoError(t, err)
-
- labels, err := buildin.GetAPIParseFunc("/v4/:project/registry/microservices/:serviceId/instances")(request)
- assert.NoError(t, err)
- assert.Equal(t, 1, len(labels))
- assert.Equal(t, "A", labels[0]["serviceName"])
- })
-
- t.Run("discovery A instances api should return service A labels", func(t *testing.T) {
- request, err := http.NewRequest(http.MethodGet, "/v4/default/registry/instances?serviceName=A", nil)
- assert.NoError(t, err)
-
- labels, err := buildin.GetAPIParseFunc("/v4/:project/registry/instances")(request)
- assert.NoError(t, err)
- assert.Equal(t, 1, len(labels))
- assert.Equal(t, "A", labels[0]["serviceName"])
- })
-
- t.Run("govern query A api should return service A labels", func(t *testing.T) {
- request, err := http.NewRequest(http.MethodGet, "/v4/default/govern/microservices?serviceName=A", nil)
- assert.NoError(t, err)
-
- labels, err := buildin.GetAPIParseFunc("/v4/:project/govern/microservices")(request)
- assert.NoError(t, err)
- assert.Equal(t, 1, len(labels))
- assert.Equal(t, "A", labels[0]["serviceName"])
- })
+ newRequest := func(method, url string, body string) *http.Request {
+ request, _ := http.NewRequest(method, url, strings.NewReader(body))
+ util.SetRequestContext(request, rest.CtxMatchPattern, url)
+ return request
+ }
+ tests := []struct {
+ name string
+ request *http.Request
+ wantResource *auth.ResourceScope
+ wantErr bool
+ }{
+ {
+ "get all services api should return no labels",
+ newRequest(http.MethodGet, "/v4/:project/registry/microservices", ""),
+ &auth.ResourceScope{
+ Type: "service",
+ Verb: "get",
+ },
+ false,
+ },
+ {
+ "create services api without body should return err",
+ newRequest(http.MethodPost, "/v4/:project/registry/microservices", "{}"),
+ nil,
+ true,
+ },
+ {
+ "create services api with serviceName A should return A",
+ newRequest(http.MethodPost, "/v4/:project/registry/microservices",
+ "{\n \"service\": {\n \"serviceName\": \"A\"\n }\n}"),
+ &auth.ResourceScope{
+ Type: "service",
+ Labels: []map[string]string{
+ {
+ "environment": "",
+ "appId": "",
+ "serviceName": "A",
+ },
+ },
+ Verb: "create",
+ },
+ false,
+ },
+ {
+ "delete 2 services api should return 2 labels",
+ newRequest(http.MethodDelete, "/v4/:project/registry/microservices",
+ "{\n \"serviceIds\": [\""+serviceIDA+"\", \""+serviceIDB+"\"]\n}"),
+ &auth.ResourceScope{
+ Type: "service",
+ Labels: []map[string]string{
+ {
+ "environment": "",
+ "appId": "TestGetAPIParseFunc",
+ "serviceName": "A",
+ },
+ {
+ "environment": "",
+ "appId": "TestGetAPIParseFunc",
+ "serviceName": "B",
+ },
+ },
+ Verb: "delete",
+ },
+ false,
+ },
+ {
+ "get service sub resource api should return service labels",
+ newRequest(http.MethodGet, "/v4/:project/registry/microservices/:serviceId/instances?:serviceId="+serviceIDA, ""),
+ &auth.ResourceScope{
+ Type: "service",
+ Labels: []map[string]string{
+ {
+ "environment": "",
+ "appId": "TestGetAPIParseFunc",
+ "serviceName": "A",
+ },
+ },
+ Verb: "get",
+ },
+ false,
+ },
+ {
+ "discovery A instances api should return service A labels",
+ newRequest(http.MethodGet, "/v4/:project/registry/instances?serviceName=A", ""),
+ &auth.ResourceScope{
+ Type: "service",
+ Labels: []map[string]string{
+ {
+ "environment": "",
+ "appId": "",
+ "serviceName": "A",
+ },
+ },
+ Verb: "get",
+ },
+ false,
+ },
+ {
+ "govern query A api should return service A labels",
+ newRequest(http.MethodGet, "/v4/:project/govern/microservices?serviceName=A", ""),
+ &auth.ResourceScope{
+ Type: "service",
+ Verb: "get",
+ },
+ false,
+ },
+ {
+ "govern query all api should return nil labels",
+ newRequest(http.MethodGet, "/v4/:project/govern/microservices", ""),
+ &auth.ResourceScope{
+ Type: "service",
+ Verb: "get",
+ },
+ false,
+ },
+ {
+ "batch discovery A instances should return A labels",
+ newRequest(http.MethodPost, "/v4/:project/registry/instances/action",
+ "{\n \"consumerId\": \"\",\n \"instances\": [\n {\n \"instance\": {\n \"serviceId\": \""+serviceIDA+"\",\n \"instanceId\": \"\"\n },\n \"rev\": \"\"\n }\n ]\n}"),
+ &auth.ResourceScope{
+ Type: "service",
+ Labels: []map[string]string{
+ {
+ "environment": "",
+ "appId": "TestGetAPIParseFunc",
+ "serviceName": "A",
+ },
+ },
+ Verb: "get",
+ },
+ false,
+ },
+ {
+ "batch heartbeat A instances should return A labels",
+ newRequest(http.MethodPost, "/v4/:project/registry/heartbeats",
+ "{\n \"instances\": [\n {\n \"serviceId\": \""+serviceIDA+"\",\n \"instanceId\": \"\"\n }\n ]\n}"),
+ &auth.ResourceScope{
+ Type: "service",
+ Labels: []map[string]string{
+ {
+ "environment": "",
+ "appId": "TestGetAPIParseFunc",
+ "serviceName": "A",
+ },
+ },
+ Verb: "update",
+ },
+ false,
+ },
+ // not registered api
+ {
+ "govern statistics api should apply all",
+ newRequest(http.MethodGet, "/v4/:project/govern/statistics", ""),
+ &auth.ResourceScope{
+ Type: "service",
+ Verb: "get",
+ },
+ false,
+ },
+ {
+ "govern apps api should apply all",
+ newRequest(http.MethodGet, "/v4/:project/govern/apps", ""),
+ &auth.ResourceScope{
+ Type: "service",
+ Verb: "get",
+ },
+ false,
+ },
+ {
+ "account api should apply all",
+ newRequest(http.MethodGet, "/v4/accounts", ""),
+ &auth.ResourceScope{
+ Type: "account",
+ Verb: "get",
+ },
+ false,
+ },
+ {
+ "role api should apply all",
+ newRequest(http.MethodGet, "/v4/roles", ""),
+ &auth.ResourceScope{
+ Type: "role",
+ Verb: "get",
+ },
+ false,
+ },
+ {
+ "role api should apply all",
+ newRequest(http.MethodGet, "/v1/:project/gov/", ""),
+ &auth.ResourceScope{
+ Type: "governance",
+ Verb: "get",
+ },
+ false,
+ },
+ }
- t.Run("govern query all api should return nil labels", func(t *testing.T) {
- request, err := http.NewRequest(http.MethodGet, "/v4/default/govern/microservices", nil)
- assert.NoError(t, err)
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ resource, err := buildin.GetAPIParseFunc(tt.request.URL.Path)(tt.request)
+ assert.Equal(t, tt.wantErr, err != nil)
+ assert.Equal(t, tt.wantResource == nil, resource == nil)
+ if tt.wantResource == nil {
+ return
+ }
+ assert.Equal(t, tt.wantResource.Type, resource.Type)
+ assert.Equal(t, tt.wantResource.Verb, resource.Verb)
+ assert.Equal(t, tt.wantResource.Labels == nil, resource.Labels == nil)
+ for _, labels := range tt.wantResource.Labels {
+ checkLabels(t, labels, resource)
+ }
+ })
+ }
+}
- labels, err := buildin.GetAPIParseFunc("/v4/:project/govern/microservices")(request)
- assert.NoError(t, err)
- assert.Nil(t, labels)
- })
+func checkLabels(t *testing.T, labels map[string]string, resource *auth.ResourceScope) {
+ var (
+ targetLabelsLength int
+ found bool
+ )
+ for k, v := range labels {
+ for _, targetLabels := range resource.Labels {
+ targetLabelsLength = len(targetLabels)
+ found = v == targetLabels[k]
+ if found {
+ break
+ }
+ }
+ assert.True(t, found, "target label key value not matched %s=%s", k, v)
+ }
+ assert.Equal(t, len(labels), targetLabelsLength)
}
diff --git a/server/plugin/auth/buildin/service_parser.go b/server/plugin/auth/buildin/service_parser.go
index bfc168e..c0ae548 100644
--- a/server/plugin/auth/buildin/service_parser.go
+++ b/server/plugin/auth/buildin/service_parser.go
@@ -18,62 +18,88 @@
package buildin
import (
- "bytes"
"context"
"encoding/json"
- "errors"
"fmt"
- "io/ioutil"
- "net/http"
-
"github.com/apache/servicecomb-service-center/datasource"
+ "github.com/apache/servicecomb-service-center/pkg/rest"
+ "github.com/apache/servicecomb-service-center/server/plugin/auth"
+ "github.com/apache/servicecomb-service-center/server/service/rbac"
"github.com/go-chassis/cari/discovery"
+ rbacmodel "github.com/go-chassis/cari/rbac"
+ "net/http"
)
-var (
- errNilRequestBody = errors.New("request body is nil")
+const (
+ LabelEnvironment = "environment"
+ LabelAppId = "appId"
+ LabelServiceName = "serviceName"
+ QueryEnv = "env"
)
var (
+ // Apply by service key or serviceId
+ // - /v4/:project/registry/existence?env=xxx&appId=xxx&serviceName=xxx
+ // - /v4/:project/registry/existence?serviceId=xxx&schemaId=xxx
APIServiceExistence = "/v4/:project/registry/existence"
+ // Method GET: apply all by optional service key
+ // Method POST or DELETE: apply by request body
APIServicesList = "/v4/:project/registry/microservices"
APIServiceInfo = "/v4/:project/registry/microservices/:serviceId"
-
APIProConDependency = "/v4/:project/registry/microservices/:providerId/consumers"
APIConProDependency = "/v4/:project/registry/microservices/:consumerId/providers"
-
- APIInstancesList = "/v4/:project/registry/instances"
- APIHeartbeats = "/v4/:project/registry/heartbeats"
-
+ // Apply by service key
+ APIDiscovery = "/v4/:project/registry/instances"
+ // Apply by request body
+ APIBatchDiscovery = "/v4/:project/registry/instances/action"
+ // Apply by request body
+ APIHeartbeats = "/v4/:project/registry/heartbeats"
+ // Apply by optional service key
+ // - /v4/:project/govern/microservices?appId=xxx
+ // Apply all:
+ // - /v4/:project/govern/microservices?options=statistics
+ // - /v4/:project/govern/microservices/statistics
APIGovServicesList = "/v4/:project/govern/microservices"
APIGovServiceInfo = "/v4/:project/govern/microservices/:serviceId"
)
func init() {
- RegisterParseFunc(APIServiceInfo, serviceIdFunc)
- RegisterParseFunc(APIGovServiceInfo, serviceIdFunc)
- RegisterParseFunc(APIProConDependency, func(r *http.Request) ([]map[string]string, error) {
+ RegisterParseFunc(APIServiceInfo, ByServiceId)
+ RegisterParseFunc(APIGovServiceInfo, ByServiceId)
+ RegisterParseFunc(APIProConDependency, func(r *http.Request) (*auth.ResourceScope, error) {
return fromQueryKey(r, ":providerId")
})
- RegisterParseFunc(APIConProDependency, func(r *http.Request) ([]map[string]string, error) {
+ RegisterParseFunc(APIConProDependency, func(r *http.Request) (*auth.ResourceScope, error) {
return fromQueryKey(r, ":consumerId")
})
- RegisterParseFunc(APIInstancesList, serviceKeyFunc)
- RegisterParseFunc(APIServiceExistence, serviceKeyFunc)
- RegisterParseFunc(APIGovServicesList, serviceKeyFunc)
- RegisterParseFunc(APIServicesList, serviceInfoFunc)
+ RegisterParseFunc(APIDiscovery, ByServiceKey)
+ RegisterParseFunc(APIServiceExistence, ByServiceKey)
+ RegisterParseFunc(APIGovServicesList, ApplyAll)
+ RegisterParseFunc(APIServicesList, ByRequestBody)
+ RegisterParseFunc(APIBatchDiscovery, ByDiscoveryRequestBody)
+ RegisterParseFunc(APIHeartbeats, ByHeartbeatRequestBody)
}
-func serviceIdFunc(r *http.Request) ([]map[string]string, error) {
+func ByServiceId(r *http.Request) (*auth.ResourceScope, error) {
return fromQueryKey(r, ":serviceId")
}
-
-func fromQueryKey(r *http.Request, queryKey string) ([]map[string]string, error) {
+func fromQueryKey(r *http.Request, queryKey string) (*auth.ResourceScope, error) {
ctx := r.Context()
+ apiPath, ok := ctx.Value(rest.CtxMatchPattern).(string)
+ if !ok {
+ return nil, ErrCtxMatchPatternNotFound
+ }
serviceId := r.URL.Query().Get(queryKey)
- return serviceIdToLabels(ctx, serviceId)
+ labels, err := serviceIdToLabels(ctx, serviceId)
+ if err != nil {
+ return nil, err
+ }
+ return &auth.ResourceScope{
+ Type: rbacmodel.GetResource(apiPath),
+ Labels: labels,
+ Verb: rbac.MethodToVerbs[r.Method],
+ }, nil
}
-
func serviceIdToLabels(ctx context.Context, serviceId string) ([]map[string]string, error) {
response, err := datasource.Instance().GetService(ctx, &discovery.GetServiceRequest{ServiceId: serviceId})
if err != nil {
@@ -86,46 +112,71 @@ func serviceIdToLabels(ctx context.Context, serviceId string) ([]map[string]stri
}
return []map[string]string{{
- "environment": service.Environment,
- "appId": service.AppId,
- "serviceName": service.ServiceName,
+ LabelEnvironment: service.Environment,
+ LabelAppId: service.AppId,
+ LabelServiceName: service.ServiceName,
}}, nil
}
-func serviceKeyFunc(r *http.Request) ([]map[string]string, error) {
+func ByServiceKey(r *http.Request) (*auth.ResourceScope, error) {
query := r.URL.Query()
- serviceId := query.Get("serviceId")
- if len(serviceId) > 0 {
- return serviceIdToLabels(r.Context(), serviceId)
- }
- env := query.Get("env")
- appID := query.Get("appId")
- serviceName := query.Get("serviceName")
+ if _, ok := query["serviceId"]; ok {
+ return fromQueryKey(r, "serviceId")
+ }
- if len(env) == 0 && len(appID) == 0 && len(serviceName) == 0 {
- return ApplyAll(r)
+ apiPath, ok := r.Context().Value(rest.CtxMatchPattern).(string)
+ if !ok {
+ return nil, ErrCtxMatchPatternNotFound
}
- return []map[string]string{{
- "environment": env,
- "appId": appID,
- "serviceName": serviceName,
- }}, nil
+ return &auth.ResourceScope{
+ Type: rbacmodel.GetResource(apiPath),
+ Labels: []map[string]string{{
+ LabelEnvironment: query.Get(QueryEnv),
+ LabelAppId: query.Get(LabelAppId),
+ LabelServiceName: query.Get(LabelServiceName),
+ }},
+ Verb: rbac.MethodToVerbs[r.Method],
+ }, nil
}
-func serviceInfoFunc(r *http.Request) ([]map[string]string, error) {
+func ByRequestBody(r *http.Request) (*auth.ResourceScope, error) {
if r.Method == http.MethodGet {
+ // get or list by query string
return ApplyAll(r)
}
+ return fromRequestBody(r)
+}
+func fromRequestBody(r *http.Request) (*auth.ResourceScope, error) {
+ apiPath, ok := r.Context().Value(rest.CtxMatchPattern).(string)
+ if !ok {
+ return nil, ErrCtxMatchPatternNotFound
+ }
+
+ var (
+ labels []map[string]string
+ err error
+ )
if r.Method == http.MethodDelete {
- return deleteServicesToLabels(r)
+ // batch delete
+ labels, err = deleteServicesToLabels(r)
+ } else {
+ // create service
+ labels, err = createServiceToLabels(r)
+ }
+ if err != nil {
+ return nil, err
}
- return createServiceToLabels(r)
-}
+ return &auth.ResourceScope{
+ Type: rbacmodel.GetResource(apiPath),
+ Labels: labels,
+ Verb: rbac.MethodToVerbs[r.Method],
+ }, nil
+}
func createServiceToLabels(r *http.Request) ([]map[string]string, error) {
- message, err := ReadBody(r)
+ message, err := rest.ReadBody(r)
if err != nil {
return nil, err
}
@@ -133,7 +184,7 @@ func createServiceToLabels(r *http.Request) ([]map[string]string, error) {
request := &discovery.CreateServiceRequest{}
err = json.Unmarshal(message, request)
if err != nil {
- return nil, fmt.Errorf("unmarshal CreateServiceRequest failed")
+ return nil, err
}
service := request.Service
@@ -142,23 +193,22 @@ func createServiceToLabels(r *http.Request) ([]map[string]string, error) {
}
return []map[string]string{{
- "environment": service.Environment,
- "appId": service.AppId,
- "serviceName": service.ServiceName,
+ LabelEnvironment: service.Environment,
+ LabelAppId: service.AppId,
+ LabelServiceName: service.ServiceName,
}}, nil
}
-
func deleteServicesToLabels(r *http.Request) ([]map[string]string, error) {
- message, err := ReadBody(r)
+ message, err := rest.ReadBody(r)
if err != nil {
- return nil, fmt.Errorf("read request body failed")
+ return nil, err
}
request := &discovery.DelServicesRequest{}
err = json.Unmarshal(message, request)
if err != nil {
- return nil, fmt.Errorf("unmarshal DelServicesRequest failed")
+ return nil, err
}
ctx := r.Context()
@@ -173,15 +223,72 @@ func deleteServicesToLabels(r *http.Request) ([]map[string]string, error) {
return labels, nil
}
-func ReadBody(r *http.Request) ([]byte, error) {
- if r.Body == nil {
- return nil, errNilRequestBody
+func ByDiscoveryRequestBody(r *http.Request) (*auth.ResourceScope, error) {
+ apiPath, ok := r.Context().Value(rest.CtxMatchPattern).(string)
+ if !ok {
+ return nil, ErrCtxMatchPatternNotFound
}
- data, err := ioutil.ReadAll(r.Body)
+ message, err := rest.ReadBody(r)
if err != nil {
return nil, err
}
- r.Body = ioutil.NopCloser(bytes.NewReader(data))
- return data, nil
+
+ request := &discovery.BatchFindInstancesRequest{}
+
+ err = json.Unmarshal(message, request)
+ if err != nil {
+ return nil, err
+ }
+
+ ctx := r.Context()
+ var labels []map[string]string
+ for _, it := range request.Instances {
+ ls, err := serviceIdToLabels(ctx, it.Instance.ServiceId)
+ if err != nil {
+ return nil, err
+ }
+ labels = append(labels, ls...)
+ }
+
+ return &auth.ResourceScope{
+ Type: rbacmodel.GetResource(apiPath),
+ Labels: labels,
+ Verb: "get",
+ }, nil
+}
+
+func ByHeartbeatRequestBody(r *http.Request) (*auth.ResourceScope, error) {
+ apiPath, ok := r.Context().Value(rest.CtxMatchPattern).(string)
+ if !ok {
+ return nil, ErrCtxMatchPatternNotFound
+ }
+
+ message, err := rest.ReadBody(r)
+ if err != nil {
+ return nil, err
+ }
+
+ request := &discovery.HeartbeatSetRequest{}
+
+ err = json.Unmarshal(message, request)
+ if err != nil {
+ return nil, err
+ }
+
+ ctx := r.Context()
+ var labels []map[string]string
+ for _, instance := range request.Instances {
+ ls, err := serviceIdToLabels(ctx, instance.ServiceId)
+ if err != nil {
+ return nil, err
+ }
+ labels = append(labels, ls...)
+ }
+
+ return &auth.ResourceScope{
+ Type: rbacmodel.GetResource(apiPath),
+ Labels: labels,
+ Verb: "update",
+ }, nil
}
diff --git a/server/plugin/auth/types.go b/server/plugin/auth/types.go
index 035796c..0dbba46 100644
--- a/server/plugin/auth/types.go
+++ b/server/plugin/auth/types.go
@@ -19,7 +19,9 @@ package auth
// ResourceScope is the resource scope parsed from request
type ResourceScope struct {
- Type string
+ Type string
+ // Labels is a map used to filter resource permissions during pre verification.
+ // If a key of permission set is missing in the Labels, pre verification will pass this key
Labels []map[string]string
// Verb is the apply resource action, e.g. "get", "create"
Verb string
diff --git a/server/response/response.go b/server/response/response.go
index 20c52a4..74515a0 100644
--- a/server/response/response.go
+++ b/server/response/response.go
@@ -24,7 +24,6 @@ import (
func init() {
RegisterFilter("/v4/:project/registry/microservices", MicroserviceListFilter)
- //response.RegisterFilter("/v4/:project/registry/instances", )
RegisterFilter("/v4/:project/registry/microservices/:providerId/consumers", ProvidersListFilter)
RegisterFilter("/v4/:project/registry/microservices/:consumerId/providers", ConsumersListFilter)
// control panel apis
diff --git a/server/service/rbac/rbac.go b/server/service/rbac/rbac.go
index f7e5aa4..76c7258 100644
--- a/server/service/rbac/rbac.go
+++ b/server/service/rbac/rbac.go
@@ -56,7 +56,7 @@ func Init() {
log.Info("rbac is disabled")
return
}
- initResourceMap()
+ InitResourceMap()
err := authr.Init()
if err != nil {
log.Fatal("can not enable auth module", err)
diff --git a/server/service/rbac/resource.go b/server/service/rbac/resource.go
index edc5beb..71917a2 100644
--- a/server/service/rbac/resource.go
+++ b/server/service/rbac/resource.go
@@ -66,7 +66,7 @@ var (
APIServiceSchema = "/v4/:project/registry/microservices/:serviceId/schemas"
)
-func initResourceMap() {
+func InitResourceMap() {
rbac.PartialMapResource(APIAccountList, ResourceAccount)
rbac.PartialMapResource(APIRoleList, ResourceRole)