You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ti...@apache.org on 2021/05/26 15:10:08 UTC
[servicecomb-service-center] branch master updated: add rbac logic
(#1014)
This is an automated email from the ASF dual-hosted git repository.
tianxiaoliang 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 f8cbf0f add rbac logic (#1014)
f8cbf0f is described below
commit f8cbf0fe6d1b93eddc7e2c5a1152880b213c7d8f
Author: humingcheng <hu...@163.com>
AuthorDate: Wed May 26 23:09:57 2021 +0800
add rbac logic (#1014)
---
go.mod | 2 +-
go.sum | 2 +
server/handler/auth/auth.go | 1 +
server/plugin/auth/buildin/buildin.go | 117 ++++++++++++++-------
server/resource/v4/auth_resource.go | 4 +-
server/service/rbac/decision.go | 114 ++++++++++++++++----
server/service/rbac/decision_test.go | 191 +++++++++++++++++++++++++++-------
server/service/rbac/resource.go | 4 +-
8 files changed, 335 insertions(+), 100 deletions(-)
diff --git a/go.mod b/go.mod
index 1d807a3..2d9ae3f 100644
--- a/go.mod
+++ b/go.mod
@@ -15,7 +15,7 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/elithrar/simple-scrypt v1.3.0
github.com/ghodss/yaml v1.0.0
- github.com/go-chassis/cari v0.4.1-0.20210525100133-33b23132d6f0
+ github.com/go-chassis/cari v0.4.1-0.20210526130437-0685eaf85b3a
github.com/go-chassis/foundation v0.3.1-0.20210513015331-b54416b66bcd
github.com/go-chassis/go-archaius v1.5.1
github.com/go-chassis/go-chassis/v2 v2.1.2-0.20210310004133-c9bc42149a18
diff --git a/go.sum b/go.sum
index ddcf679..dc7fe01 100644
--- a/go.sum
+++ b/go.sum
@@ -272,6 +272,8 @@ github.com/go-chassis/cari v0.4.1-0.20210522033018-d228d49d7d61 h1:gVgeg1lmX1mpr
github.com/go-chassis/cari v0.4.1-0.20210522033018-d228d49d7d61/go.mod h1:av/19fqwEP4eOC8unL/z67AAbFDwXUCko6SKa4Avrd8=
github.com/go-chassis/cari v0.4.1-0.20210525100133-33b23132d6f0 h1:cxI44jhmc1yzyDm6MQ4oYutZroHlaPkpJLrmsLQJybY=
github.com/go-chassis/cari v0.4.1-0.20210525100133-33b23132d6f0/go.mod h1:av/19fqwEP4eOC8unL/z67AAbFDwXUCko6SKa4Avrd8=
+github.com/go-chassis/cari v0.4.1-0.20210526130437-0685eaf85b3a h1:YQH/VGLB9eveB39JH818nTD9HObV5tU7C+ALieupaX0=
+github.com/go-chassis/cari v0.4.1-0.20210526130437-0685eaf85b3a/go.mod h1:av/19fqwEP4eOC8unL/z67AAbFDwXUCko6SKa4Avrd8=
github.com/go-chassis/foundation v0.2.2-0.20201210043510-9f6d3de40234/go.mod h1:2PjwqpVwYEVaAldl5A58a08viH8p27pNeYaiE3ZxOBA=
github.com/go-chassis/foundation v0.2.2/go.mod h1:2PjwqpVwYEVaAldl5A58a08viH8p27pNeYaiE3ZxOBA=
github.com/go-chassis/foundation v0.3.0/go.mod h1:2PjwqpVwYEVaAldl5A58a08viH8p27pNeYaiE3ZxOBA=
diff --git a/server/handler/auth/auth.go b/server/handler/auth/auth.go
index f1b1053..034acc4 100644
--- a/server/handler/auth/auth.go
+++ b/server/handler/auth/auth.go
@@ -32,6 +32,7 @@ import (
const (
CtxResourceLabels util.CtxKey = "_resource_labels"
CtxResourceScopes util.CtxKey = "_resource_scopes"
+ CtxRequestClaims util.CtxKey = "_request_claims"
)
type Handler struct {
diff --git a/server/plugin/auth/buildin/buildin.go b/server/plugin/auth/buildin/buildin.go
index 69001e2..3117e30 100644
--- a/server/plugin/auth/buildin/buildin.go
+++ b/server/plugin/auth/buildin/buildin.go
@@ -30,6 +30,7 @@ import (
errorsEx "github.com/apache/servicecomb-service-center/pkg/errors"
"github.com/apache/servicecomb-service-center/pkg/log"
"github.com/apache/servicecomb-service-center/pkg/rest"
+ authHandler "github.com/apache/servicecomb-service-center/server/handler/auth"
"github.com/apache/servicecomb-service-center/server/plugin/auth"
rbacsvc "github.com/apache/servicecomb-service-center/server/service/rbac"
"github.com/go-chassis/go-chassis/v2/security/authr"
@@ -52,73 +53,102 @@ func (ba *TokenAuthenticator) Identify(req *http.Request) error {
return nil
}
pattern, ok := req.Context().Value(rest.CtxMatchPattern).(string)
- if ok && !mustAuth(pattern) {
- return nil
- }
- v := req.Header.Get(restful.HeaderAuth)
- if v == "" {
- return rbac.ErrNoHeader
+ if !ok {
+ pattern = req.URL.Path
+ log.Warn("can not find api pattern")
}
- s := strings.Split(v, " ")
- if len(s) != 2 {
- return rbac.ErrInvalidHeader
+
+ if !mustAuth(pattern) {
+ return nil
}
- to := s[1]
- claims, err := authr.Authenticate(req.Context(), to)
+ claims, err := ba.VerifyToken(req)
if err != nil {
- log.Errorf(err, "authenticate request failed, %s %s", req.Method, req.RequestURI)
+ log.Errorf(err, "verify request token failed, %s %s", req.Method, req.RequestURI)
return err
}
+
m, ok := claims.(map[string]interface{})
if !ok {
log.Error("claims convert failed", rbac.ErrConvertErr)
return rbac.ErrConvertErr
}
-
- roleList, err := rbac.GetRolesList(m)
+ account, err := rbac.GetAccount(m)
if err != nil {
- log.Error("get role list failed", err)
+ log.Error("get account failed", err)
return err
}
+ util.SetRequestContext(req, authHandler.CtxRequestClaims, m)
+ // user can change self password
+ if isChangeSelfPassword(pattern, account, req) {
+ return nil
+ }
- var apiPattern string
- a := req.Context().Value(rest.CtxMatchPattern)
- if a == nil { //handle exception
- apiPattern = req.URL.Path
- log.Warn("can not find api pattern")
- } else {
- apiPattern = a.(string)
+ if len(account.Roles) == 0 {
+ log.Error("no role found in token", nil)
+ return errors.New(errorsEx.MsgNoPerm)
}
project := req.URL.Query().Get(":project")
- verbs := rbacsvc.MethodToVerbs[req.Method]
- err = checkPerm(roleList, project, apiPattern, verbs)
+ allow, matchedLabels, err := checkPerm(account.Roles, project, req, pattern, req.Method)
if err != nil {
return err
}
- req2 := req.WithContext(rbac.NewContext(req.Context(), m))
- *req = *req2
+ if !allow {
+ return errors.New(errorsEx.MsgNoPerm)
+ }
+
+ util.SetRequestContext(req, authHandler.CtxResourceLabels, matchedLabels)
return nil
}
-//this method decouple business code and perm checks
-func checkPerm(roleList []string, project, apiPattern, verbs string) error {
- resource := rbac.GetResource(apiPattern)
- if resource == "" {
- //fast fail, no need to access role storage
- return errors.New(errorsEx.MsgNoPerm)
+func isChangeSelfPassword(pattern string, a *rbac.Account, req *http.Request) bool {
+ if pattern != rbacsvc.APIAccountPassword {
+ return false
}
- //TODO add verbs,project
- allow, err := rbacsvc.Allow(context.TODO(), roleList, project, resource, verbs)
- if err != nil {
- log.Error("", err)
- return errors.New(errorsEx.MsgRolePerm)
+ changerName := a.Name
+ targetName := req.URL.Query().Get(":name")
+ return changerName == targetName
+}
+
+func filterRoles(roleList []string) (hasAdmin bool, normalRoles []string) {
+ for _, r := range roleList {
+ if r == rbac.RoleAdmin {
+ hasAdmin = true
+ return
+ }
+ normalRoles = append(normalRoles, r)
}
- if !allow {
- return errors.New(errorsEx.MsgNoPerm)
+ return
+}
+
+func (ba *TokenAuthenticator) VerifyToken(req *http.Request) (interface{}, error) {
+ v := req.Header.Get(restful.HeaderAuth)
+ if v == "" {
+ return nil, rbac.ErrNoHeader
}
- return nil
+ s := strings.Split(v, " ")
+ if len(s) != 2 {
+ return nil, rbac.ErrInvalidHeader
+ }
+ to := s[1]
+
+ return authr.Authenticate(req.Context(), to)
+}
+
+//this method decouple business code and perm checks
+func checkPerm(roleList []string, project string, req *http.Request, apiPattern, method string) (bool, []map[string]string, error) {
+ hasAdmin, normalRoles := filterRoles(roleList)
+ if hasAdmin {
+ return true, nil, nil
+ }
+ //todo fast check for dev role
+ targetResource, ok := req.Context().Value(authHandler.CtxResourceScopes).(*auth.ResourceScope)
+ if !ok || targetResource == nil {
+ return false, nil, errors.New("no valid resouce scope")
+ }
+ //TODO add project
+ return rbacsvc.Allow(context.TODO(), project, normalRoles, targetResource)
}
func mustAuth(pattern string) bool {
@@ -134,3 +164,10 @@ func (ba *TokenAuthenticator) ResourceScopes(r *http.Request) *auth.ResourceScop
}
return FromRequest(r)
}
+func AccountFromContext(ctx context.Context) (*rbac.Account, error) {
+ m, ok := ctx.Value(authHandler.CtxRequestClaims).(map[string]interface{})
+ if !ok {
+ return nil, errors.New("no claims from request context")
+ }
+ return rbac.GetAccount(m)
+}
diff --git a/server/resource/v4/auth_resource.go b/server/resource/v4/auth_resource.go
index 19ede1d..6eda172 100644
--- a/server/resource/v4/auth_resource.go
+++ b/server/resource/v4/auth_resource.go
@@ -29,6 +29,7 @@ import (
"github.com/apache/servicecomb-service-center/pkg/log"
"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/buildin"
rbacsvc "github.com/apache/servicecomb-service-center/server/service/rbac"
"github.com/apache/servicecomb-service-center/server/service/rbac/dao"
"github.com/apache/servicecomb-service-center/server/service/validator"
@@ -173,7 +174,8 @@ func (ar *AuthResource) ChangePassword(w http.ResponseWriter, req *http.Request)
rest.WriteError(w, discovery.ErrInvalidParams, err.Error())
return
}
- changer, err := rbac.AccountFromContext(req.Context())
+
+ changer, err := buildin.AccountFromContext(req.Context())
if err != nil {
rest.WriteError(w, discovery.ErrInternal, "can not parse account info")
return
diff --git a/server/service/rbac/decision.go b/server/service/rbac/decision.go
index ddf0650..545f99b 100644
--- a/server/service/rbac/decision.go
+++ b/server/service/rbac/decision.go
@@ -19,25 +19,74 @@ package rbac
import (
"context"
-
"github.com/go-chassis/cari/rbac"
"github.com/apache/servicecomb-service-center/datasource"
"github.com/apache/servicecomb-service-center/pkg/log"
+ "github.com/apache/servicecomb-service-center/server/plugin/auth"
)
-func Allow(ctx context.Context, roleList []string, project, resource, verbs string) (bool, error) {
+// return: allow, matched labels(empty if no label defined), error
+func Allow(ctx context.Context, project string, roleList []string,
+ targetResouce *auth.ResourceScope) (bool, []map[string]string, error) {
//TODO check project
- if ableToOperateResource(roleList, "admin") {
- return true, nil
+ allPerms, err := getPermsByRoles(ctx, roleList)
+ if err != nil {
+ log.Error("get role list errors", err)
+ return false, nil, err
+ }
+ if len(allPerms) == 0 {
+ log.Warn("role list has no any permissions")
+ return false, nil, nil
+ }
+ allow, labelList := GetLabel(allPerms, targetResouce.Type, targetResouce.Verb)
+ if !allow {
+ return false, nil, nil
+ }
+ // allow, but no label found, means we can ignore the labels
+ if len(labelList) == 0 {
+ return true, nil, nil
+ }
+ // target resource needs no label, return without filter
+ if len(targetResouce.Labels) == 0 {
+ return true, labelList, nil
+ }
+ // allow, and labels found, filter the labels
+ filteredLabelList := FilterLabel(targetResouce.Labels, labelList)
+ // target resource label matches no label in permission, means not allow
+ if len(filteredLabelList) == 0 {
+ return false, nil, nil
+ }
+ return true, filteredLabelList, nil
+}
+
+func FilterLabel(targetResourceLabel []map[string]string, permLabelList []map[string]string) []map[string]string {
+ l := make([]map[string]string, 0)
+ for _, resourceLabel := range targetResourceLabel {
+ for _, label := range permLabelList {
+ if LabelMatched(resourceLabel, label) {
+ l = append(l, label)
+ }
+ }
}
- // allPerms combines the roleList permission
+ return l
+}
+
+func LabelMatched(targetResourceLabel map[string]string, permLabel map[string]string) bool {
+ for k, v := range permLabel {
+ if vv := targetResourceLabel[k]; vv != v {
+ return false
+ }
+ }
+ return true
+}
+
+func getPermsByRoles(ctx context.Context, roleList []string) ([]*rbac.Permission, error) {
var allPerms = make([]*rbac.Permission, 0)
for i := 0; i < len(roleList); i++ {
r, err := datasource.Instance().GetRole(ctx, roleList[i])
if err != nil {
- log.Error("get role list errors", err)
- return false, err
+ return nil, err
}
if r == nil {
log.Warnf("role [%s] has no any permissions", roleList[i])
@@ -45,22 +94,38 @@ func Allow(ctx context.Context, roleList []string, project, resource, verbs stri
}
allPerms = append(allPerms, r.Perms...)
}
+ return allPerms, nil
+}
- if len(allPerms) == 0 {
- log.Warn("role list has no any permissions")
- return false, nil
- }
- for i := 0; i < len(allPerms); i++ {
- if ableToAccessResource(allPerms[i].Resources, resource) && ableToOperateResource(allPerms[i].Verbs, verbs) {
+// GetLabel checks if the perms have permission to operate the resource(ignore label),
+// if one perm have the permission, add it's label to the result.
+func GetLabel(perms []*rbac.Permission, targetResource, verb string) (allow bool, labelList []map[string]string) {
+ for _, perm := range perms {
+ a, l := GetLabelFromSinglePerm(perm, targetResource, verb)
+ if !a {
+ continue
+ }
+ allow = true
+ // allow and has no label, return fast
+ if len(l) == 0 {
return true, nil
}
+ labelList = append(labelList, l...)
}
+ return
+}
- log.Warn("role is not allowed to operate resource")
- return false, nil
+// GetLabel checks if the perm have permission to operate the resource(ignore label),
+// if the perm have the permission, return it's label.
+func GetLabelFromSinglePerm(perm *rbac.Permission, targetResource, verb string) (allow bool, labelList []map[string]string) {
+ if !allowVerb(perm.Verbs, verb) {
+ return false, nil
+ }
+
+ return getResourceLabel(perm.Resources, targetResource)
}
-func ableToOperateResource(haystack []string, needle string) bool {
+func allowVerb(haystack []string, needle string) bool {
for _, e := range haystack {
if e == "*" || e == needle {
return true
@@ -69,11 +134,18 @@ func ableToOperateResource(haystack []string, needle string) bool {
return false
}
-func ableToAccessResource(haystack []*rbac.Resource, needle string) bool {
- for _, e := range haystack {
- if e.Type == needle {
- return true
+func getResourceLabel(resources []*rbac.Resource, needle string) (allow bool, labelList []map[string]string) {
+ for _, resource := range resources {
+ // filter the same resource
+ if resource.Type != needle {
+ continue
+ }
+ // has no label, return fast
+ if len(resource.Labels) == 0 {
+ return true, nil
}
+ labelList = append(labelList, resource.Labels)
+ allow = true
}
- return false
+ return
}
diff --git a/server/service/rbac/decision_test.go b/server/service/rbac/decision_test.go
index acc9cf4..20cbdd1 100644
--- a/server/service/rbac/decision_test.go
+++ b/server/service/rbac/decision_test.go
@@ -18,55 +18,174 @@
package rbac_test
import (
- "context"
- "io/ioutil"
"testing"
- "github.com/go-chassis/go-archaius"
- "github.com/go-chassis/go-chassis/v2/security/secret"
+ "github.com/go-chassis/cari/rbac"
"github.com/stretchr/testify/assert"
- "github.com/apache/servicecomb-service-center/server/service/rbac"
- "github.com/apache/servicecomb-service-center/server/service/rbac/dao"
+ rbacsvc "github.com/apache/servicecomb-service-center/server/service/rbac"
)
-func TestAllow(t *testing.T) {
- err := archaius.Init(archaius.WithMemorySource(), archaius.WithENVSource())
- assert.NoError(t, err)
+func TestGetLabel(t *testing.T) {
+ perms := []*rbac.Permission{
+ &rbac.Permission{
+ Resources: []*rbac.Resource{
+ {
+ Type: rbacsvc.ResourceAccount,
+ Labels: map[string]string{"environment": "production"},
+ },
+ {
+ Type: rbacsvc.ResourceService,
+ Labels: map[string]string{"serviceName": "service-center"},
+ },
+ },
+ Verbs: []string{"get"},
+ },
+ &rbac.Permission{
+ Resources: []*rbac.Resource{
+ {
+ Type: rbacsvc.ResourceService,
+ Labels: map[string]string{"appId": "default"},
+ },
+ },
+ Verbs: []string{"*"},
+ },
+ &rbac.Permission{
+ Resources: []*rbac.Resource{
+ {
+ Type: rbacsvc.ResourceService,
+ },
+ },
+ Verbs: []string{"delete"},
+ },
+ }
+ t.Run("resource and verb matched, should allow", func(t *testing.T) {
+ allow, labelList := rbacsvc.GetLabel(perms, rbacsvc.ResourceService, "create")
+ assert.True(t, allow)
+ assert.Equal(t, 1, len(labelList))
+ })
- pri, pub, err := secret.GenRSAKeyPair(4096)
- assert.NoError(t, err)
+ t.Run("nums of resource matched, should allow and combine their labels", func(t *testing.T) {
+ allow, labelList := rbacsvc.GetLabel(perms, rbacsvc.ResourceService, "get")
+ assert.True(t, allow)
+ assert.Equal(t, 2, len(labelList))
+ })
- b, err := secret.RSAPrivate2Bytes(pri)
- assert.NoError(t, err)
- ioutil.WriteFile("./private.key", b, 0600)
- b, err = secret.RSAPublicKey2Bytes(pub)
- err = ioutil.WriteFile("./rbac.pub", b, 0600)
- assert.NoError(t, err)
+ t.Run("nums of resource matched, one of them has no label, should allow and no label", func(t *testing.T) {
+ allow, labelList := rbacsvc.GetLabel(perms, rbacsvc.ResourceService, "delete")
+ assert.True(t, allow)
+ assert.Equal(t, 0, len(labelList))
+ })
+ t.Run("resource not matched, should not allow", func(t *testing.T) {
+ allow, labelList := rbacsvc.GetLabel(perms, rbacsvc.ResourceRole, "delete")
+ assert.False(t, allow)
+ assert.Equal(t, 0, len(labelList))
+ })
+ t.Run("Verb not matched, should not allow", func(t *testing.T) {
+ allow, labelList := rbacsvc.GetLabel(perms, rbacsvc.ResourceAccount, "delete")
+ assert.False(t, allow)
+ assert.Equal(t, 0, len(labelList))
+ })
+}
- archaius.Set(rbac.InitPassword, "Complicated_password1")
+func TestGetLabelFromSinglePerm(t *testing.T) {
+ t.Run("resource and verb match, should allow", func(t *testing.T) {
+ perms := &rbac.Permission{
+ Resources: []*rbac.Resource{
+ {
+ Type: rbacsvc.ResourceAccount,
+ Labels: map[string]string{"environment": "production"},
+ },
+ },
+ Verbs: []string{"*"},
+ }
+ allow, labelList := rbacsvc.GetLabelFromSinglePerm(perms, rbacsvc.ResourceAccount, "create")
+ assert.True(t, allow)
+ assert.Equal(t, 1, len(labelList))
+ assert.Equal(t, "production", labelList[0]["environment"])
+ })
- dao.DeleteAccount(context.Background(), "root")
- dao.DeleteAccount(context.Background(), "a")
- dao.DeleteAccount(context.Background(), "b")
+ t.Run("resource not match, should no allow", func(t *testing.T) {
+ perms := &rbac.Permission{
+ Resources: []*rbac.Resource{
+ {
+ Type: rbacsvc.ResourceAccount,
+ Labels: map[string]string{"environment": "production"},
+ },
+ },
+ Verbs: []string{"*"},
+ }
+ allow, labelList := rbacsvc.GetLabelFromSinglePerm(perms, rbacsvc.ResourceService, "create")
+ assert.False(t, allow)
+ assert.Equal(t, 0, len(labelList))
+ })
- rbac.Init()
- a, err := dao.GetAccount(context.Background(), "root")
- assert.NoError(t, err)
- assert.Equal(t, "root", a.Name)
+ t.Run("verb not match, should no allow", func(t *testing.T) {
+ perms := &rbac.Permission{
+ Resources: []*rbac.Resource{
+ {
+ Type: rbacsvc.ResourceAccount,
+ Labels: map[string]string{"environment": "production"},
+ },
+ },
+ Verbs: []string{"get"},
+ }
+ allow, labelList := rbacsvc.GetLabelFromSinglePerm(perms, rbacsvc.ResourceAccount, "create")
+ assert.False(t, allow)
+ assert.Equal(t, 0, len(labelList))
+ })
+}
- t.Run("admin can operate any resource", func(t *testing.T) {
- ok, _ := rbac.Allow(context.TODO(), []string{"admin"}, "default", "account", "create")
- assert.True(t, ok)
- ok, _ = rbac.Allow(context.TODO(), []string{"admin"}, "default", "service", "create")
- assert.True(t, ok)
+func TestLabelMatched(t *testing.T) {
+ targetResourceLabel := map[string]string{
+ "environment": "production",
+ "appId": "default",
+ }
+ t.Run("value not match, should not match", func(t *testing.T) {
+ permResourceLabel := map[string]string{
+ "environment": "testing",
+ }
+ assert.False(t, rbacsvc.LabelMatched(targetResourceLabel, permResourceLabel))
})
- t.Run("developer can not operate account", func(t *testing.T) {
- ok, _ := rbac.Allow(context.TODO(), []string{"developer"}, "default", "account", "create")
- assert.False(t, ok)
+ t.Run("key not match, should not match", func(t *testing.T) {
+ permResourceLabel := map[string]string{
+ "serviceName": "default",
+ }
+ assert.False(t, rbacsvc.LabelMatched(targetResourceLabel, permResourceLabel))
})
- t.Run("developer can operate service", func(t *testing.T) {
- ok, _ := rbac.Allow(context.TODO(), []string{"developer"}, "default", "service", "create")
- assert.True(t, ok)
+ t.Run("target resource label matches no permission resource label, should not match", func(t *testing.T) {
+ permResourceLabel := map[string]string{
+ "version": "1.0.0",
+ }
+ assert.False(t, rbacsvc.LabelMatched(targetResourceLabel, permResourceLabel))
})
+ t.Run("target resource label matches part permission resource label, should not match", func(t *testing.T) {
+ permResourceLabel := map[string]string{
+ "version": "1.0.0",
+ "environment": "production",
+ }
+ assert.False(t, rbacsvc.LabelMatched(targetResourceLabel, permResourceLabel))
+ })
+ t.Run("target resource label matches permission resource label, should not match", func(t *testing.T) {
+ permResourceLabel := map[string]string{
+ "environment": "production",
+ }
+ assert.True(t, rbacsvc.LabelMatched(targetResourceLabel, permResourceLabel))
+ })
+}
+func TestFilterLabel(t *testing.T) {
+ targetResourceLabel := []map[string]string{
+ {"environment": "production", "appId": "default"},
+ {"serviceName": "service-center"},
+ }
+ permResourceLabel := []map[string]string{
+ {"environment": "production", "appId": "default"},
+ {"appId": "default"},
+ {"environment": "production", "serviceName": "service-center"},
+ {"serviceName": "service-center", "version": "1.0.0"},
+ {"serviceName": "service-center"},
+ {"environment": "testing"},
+ }
+ l := rbacsvc.FilterLabel(targetResourceLabel, permResourceLabel)
+ assert.Equal(t, 3, len(l))
}
diff --git a/server/service/rbac/resource.go b/server/service/rbac/resource.go
index 8043ffc..edc5beb 100644
--- a/server/service/rbac/resource.go
+++ b/server/service/rbac/resource.go
@@ -26,7 +26,7 @@ const (
ResourceRole = "role"
ResourceService = "service"
ResourceGovern = "governance"
- ResourceSchema = "schema"
+ ResourceSchema = "service/schema"
ResourceOps = "ops"
)
@@ -37,6 +37,8 @@ var (
APIRoleList = "/v4/roles"
+ APIAccountPassword = "/v4/accounts/:name/password"
+
APIOps = "/v4/:project/admin"
APIGov = "/v1/:project/gov/"