test: (rbac) validate index and cluster unit test

This commit is contained in:
xushuhui 2022-04-27 14:22:12 +08:00
parent 598c655a44
commit e865ee5f67
8 changed files with 173 additions and 222 deletions

View File

@ -1,8 +1,8 @@
{
"DELETE-/_ingest/pipeline/:id": "ingest.delete_pipeline",
"DELETE-/_scripts/:id": "script.delete",
"DELETE-/_search/scroll": "clear_scroll",
"DELETE-/_search/scroll/:scroll_id": "clear_scroll",
"DELETE-/_search/scroll": "scroll.delete",
"DELETE-/_search/scroll/:scroll_id":"scroll.delete",
"DELETE-/_snapshot/:repository": "snapshot.delete_repository",
"DELETE-/_snapshot/:repository/:snapshot": "snapshot.delete",
"DELETE-/_template/:name": "indices.delete_template",
@ -102,10 +102,10 @@
"GET-/_scripts/painless/_execute": "scripts.painless_execute",
"GET-/_scripts/:id": "scripts.get",
"GET-/_search": "cluster.search",
"GET-/_search/scroll": "scroll",
"GET-/_search/scroll/:scroll_id": "scroll",
"GET-/_search/scroll": "scroll.get",
"GET-/_search/scroll/:scroll_id": "scroll.get",
"GET-/_search/template": "search_template",
"GET-/_search_shards": "search_shards",
"GET-/_search_shards": "cluster.search_shards",
"GET-/_segments": "indices.segments",
"GET-/_settings": "indices.get_settings",
"GET-/_settings/:name": "indices.get_settings",
@ -192,16 +192,16 @@
"POST-/_refresh": "indices.refresh",
"POST-/_reindex": "reindex",
"POST-/_reindex/:task_id/_rethrottle": "reindex_rethrottle",
"POST-/_render/template": "render_search_template",
"POST-/_render/template/:id": "render_search_template",
"POST-/_render/template": "render_search_template.create",
"POST-/_render/template/:id": "render_search_template.get",
"POST-/_scripts/painless/_execute": "scripts_painless_execute",
"POST-/_scripts/:id": "put_script",
"POST-/_scripts/:id/:context": "put_script",
"POST-/_search": "search",
"POST-/_search/scroll": "scroll",
"POST-/_search/scroll/:scroll_id": "scroll",
"POST-/_scripts/:id": "scripts.put",
"POST-/_scripts/:id/:context": "scripts.put",
"POST-/_search/scroll": "scroll.create",
"POST-/_search/scroll/:scroll_id": "scroll.create",
"POST-/_search/template": "search_template",
"POST-/_search_shards": "search_shards",
"POST-/_snapshot/:repository": "snapshot.create_repository",
"POST-/_snapshot/:repository/_verify": "snapshot.verify_repository",
"POST-/_snapshot/:repository/:snapshot": "snapshot.create",
@ -217,53 +217,53 @@
"POST-/:index/_alias/:name": "indices.put_alias",
"POST-/:index/_aliases/:name": "indices.put_alias",
"POST-/:index/_analyze": "indices.analyze",
"POST-/:index/_bulk": "bulk",
"POST-/:index/_bulk": "indices.bulk",
"POST-/:index/_cache/clear": "indices.clear_cache",
"POST-/:index/_close": "indices.close",
"POST-/:index/_count": "count",
"POST-/:index/_count": "indices.count",
"POST-/:index/_delete_by_query": "indices.delete_by_query",
"POST-/:index/_doc": "doc.create",
"POST-/:index/_doc/:id": "doc.put",
"POST-/:index/_doc/:id": "doc.update",
"POST-/:index/_doc/:id/_update": "doc.update",
"POST-/:index/_field_caps": "field_caps",
"POST-/:index/_field_caps": "indices.field_caps",
"POST-/:index/_flush": "indices.flush",
"POST-/:index/_flush/synced": "indices.flush_synced",
"POST-/:index/_forcemerge": "indices.forcemerge",
"POST-/:index/_mget": "mget",
"POST-/:index/_msearch": "msearch",
"POST-/:index/_msearch/template": "msearch_template",
"POST-/:index/_mtermvectors": "mtermvectors",
"POST-/:index/_mget": "indices.mget",
"POST-/:index/_msearch": "indices.msearch",
"POST-/:index/_msearch/template": "indices.msearch_template",
"POST-/:index/_mtermvectors": "indices.mtermvectors",
"POST-/:index/_open": "indices.open",
"POST-/:index/_rank_eval": "rank_eval",
"POST-/:index/_rank_eval": "indices.rank_eval",
"POST-/:index/_refresh": "indices.refresh",
"POST-/:index/_search": "search",
"POST-/:index/_search/template": "search_template",
"POST-/:index/_search_shards": "search_shards",
"POST-/:index/_search": "indices.search",
"POST-/:index/_search/template": "indices.search_template",
"POST-/:index/_search_shards": "indices.search_shards",
"POST-/:index/_shrink/:target": "indices.shrink",
"POST-/:index/_split/:target": "indices.split",
"POST-/:index/_update_by_query": "update_by_query",
"POST-/:index/_update_by_query": "indices.update_by_query",
"POST-/:index/_upgrade": "indices.upgrade",
"POST-/:index/_validate/query": "indices.validate_query",
"POST-/:index/_mapping": "indices.put_mapping",
"POST-/:index/_mappings": "indices.put_mapping",
"PUT-/_bulk": "bulk",
"PUT-/_bulk": "cluster.bulk",
"PUT-/_cluster/settings": "cluster.put_settings",
"PUT-/_ingest/pipeline/:id": "ingest.put_pipeline",
"PUT-/_scripts/:id": "put_script",
"PUT-/_scripts/:id/:context": "put_script",
"PUT-/_settings": "indices.put_settings",
"PUT-/_scripts/:id": "scripts.put",
"PUT-/_scripts/:id/:context": "scripts.put",
"PUT-/_settings": "cluster.settings_put",
"PUT-/_snapshot/:repository": "snapshot.create_repository",
"PUT-/_snapshot/:repository/:snapshot": "snapshot.create",
"PUT-/_template/:name": "indices.put_template",
"PUT-/:index": "indices.create",
"PUT-/:index": "indices.put",
"PUT-/:index/_alias/:name": "indices.put_alias",
"PUT-/:index/_aliases/:name": "indices.put_alias",
"PUT-/:index/_bulk": "bulk",
"PUT-/:index/_doc": "index",
"PUT-/:index/_doc/:id": "index",
"PUT-/:index/_bulk": "indices.put_bulk",
"PUT-/:index/_doc/:id": "doc.put",
"PUT-/:index/_settings": "indices.put_settings",
"PUT-/:index/_shrink/:target": "indices.shrink",

View File

@ -43,13 +43,14 @@
"cluster.msearch_template",
"cluster.mtermvectors",
"cluster.rank_eval",
"cluster.search"
"cluster.search",
"cluster.search_shards"
],
"doc": [
"doc.*",
"doc.update",
"doc.put",
"doc.create",
"doc.delete",
"doc.get",
@ -71,6 +72,7 @@
"indices.get_alias",
"indices.recovery",
"indices.delete",
"indices.put",
"indices.clear_cache",
"indices.update_by_query",
"indices.shrink",
@ -143,6 +145,8 @@
],
"render_search_template": [
"render_search_template.*",
"render_search_template.create",
"render_search_template.*"
],
"scripts": [
@ -154,7 +158,10 @@
],
"scroll": [
"scroll.*"
"scroll.*",
"scroll.delete",
"scroll.get",
"scroll.create"
],
"snapshot": [

View File

@ -10,13 +10,14 @@ const UserAll = "system.user:all"
const RoleRead = "system.role:read"
const RoleAll = "system.role:all"
var RuleRead = []string{"rule::read"}
var RuleAll = []string{"rule::read", "rule::write"}
const RuleRead = "alerting.rule:read"
const RuleAll = "alerting.rule:all"
const InstanceRead = "gateway.instance:read"
const InstanceAll = "gateway.instance:all"
var InstanceRead = []string{"instance::read"}
var InstanceAll = []string{"instance::read", "instance::write"}
var AdminPrivilege = []string{
"system.role:read", "system.role:all", "system.user:read", "system.user:all",
UserRead, UserAll, RoleRead, RoleAll,
}
var BuildRoles = make(map[string]map[string]interface{}, 0)
@ -32,16 +33,4 @@ func init() {
"created": time.Now(),
}
//自定义角色=》 =》permissionKey
// userrole=> [cluster::all,clust] => permissionValue [cluster::read,cluster::write]
// login=> userrole=> cluster::all =>permissionList[]
// cluster search api require = (cluster::read)
//Permission = map[string][]string{
//
// UserRead : {UserRead},
// UserAll: {UserRead, UserWrite},
//}
//zhangsan userrole [cluster::read,cluster::write]
// cluster/_search reqire(cluster::read)
}

View File

@ -3,7 +3,7 @@ package biz
import "infini.sh/console/internal/core"
var ClusterApis = make(map[string][]string)
var IndexApis = make([]string, 0)
var IndexApis = make([]string, 50)
var RoleMap = make(map[string]Role)
var EsApiRoutes = core.NewRouter()
@ -25,7 +25,7 @@ type RolePermission struct {
Platform []string `json:"platform,omitempty"`
Cluster []string `json:"cluster"`
ClusterPrivilege []string `json:"cluster_privilege"`
Index []string `json:"index"`
IndexPrivilege map[string][]string `json:"index_privilege"`
}
type ConsolePermisson struct {

View File

@ -3,6 +3,7 @@ package biz
import (
"errors"
httprouter "infini.sh/framework/core/api/router"
"infini.sh/framework/core/util"
"strings"
)
@ -39,24 +40,7 @@ func NewClusterRequest(ps httprouter.Params, privilege []string) ClusterRequest
}
}
//func ValidateEsPermission(req EsRequest, userRole RolePermission) (err error) {
//
// route, err := EsApiRoutes.Handle(req.Method, req.Path)
// if err != nil {
//
// return
// }
// if len(req.Index) > 0 {
// err = ValidateIndex(req, userRole, route)
// if err != nil {
// return err
// }
// }
// err = ValidateCluster(req, userRole, route)
// return
//}
func ValidateIndex(req IndexRequest, userRole RolePermission) (err error) {
userIndexMap := make(map[string]struct{})
userClusterMap := make(map[string]struct{})
for _, v := range userRole.Cluster {
@ -68,36 +52,31 @@ func ValidateIndex(req IndexRequest, userRole RolePermission) (err error) {
return
}
}
for _, v := range userRole.Index {
userIndexMap[v] = struct{}{}
}
for _, v := range req.Index {
if _, ok := userIndexMap[v]; !ok {
err = errors.New("no index permission")
return
}
}
for _, val := range req.Privilege {
prefix := val[:strings.Index(val, ".")]
position := strings.Index(val, ".")
if position == -1 {
err = errors.New("invalid privilege parmeter")
return err
}
prefix := val[:position]
for _, v := range req.Index {
privilege, ok := userRole.IndexPrivilege[v]
if !ok {
err = errors.New("no index api permission in user role")
err = errors.New("no index permission")
return err
}
for _, p := range privilege {
if p == prefix+".*" {
if util.StringInArray(privilege, prefix+".*") {
return nil
}
if p == val {
if util.StringInArray(privilege, val) {
return nil
}
}
}
}
return errors.New("no index api permission in user role")
return errors.New("no index api permission")
}
func ValidateCluster(req ClusterRequest, userRole RolePermission) (err error) {
userClusterMap := make(map[string]struct{})
@ -110,19 +89,18 @@ func ValidateCluster(req ClusterRequest, userRole RolePermission) (err error) {
return
}
}
// if include api.* for example: cat.* , return nil
for _, privilege := range req.Privilege {
prefix := privilege[:strings.Index(privilege, ".")]
for _, v := range userRole.ClusterPrivilege {
if v == prefix+".*" {
if util.StringInArray(userRole.ClusterPrivilege, prefix+".*") {
return nil
}
if v == privilege {
if util.StringInArray(userRole.ClusterPrivilege, privilege) {
return nil
}
}
}
return errors.New("no cluster api permission")
}
@ -142,7 +120,7 @@ func CombineUserRoles(roleNames []string) RolePermission {
newRole.Platform = append(newRole.Platform, v)
}
for _, v := range role.Index {
newRole.Index = append(newRole.Index, v.Name...)
for _, name := range v.Name {
if _, ok := m[name]; ok {
m[name] = append(m[name], v.Privilege...)

View File

@ -9,65 +9,57 @@ func Test_validateIndex(t *testing.T) {
type args struct {
req IndexRequest
userRole RolePermission
route string
}
tests := []struct {
name string
args args
want string
}{
//{"no index permission",
// args{
// req: EsRequest{
// Method: "GET",
// Cluster: []string{"cluster1"},
// Index: []string{"index2"},
// Path: "/index1/_mapping",
// },
// userRole: RolePermission{
// Cluster: []string{
// "cluster1",
// },
// Index: []string{
// "index1",
// },
// ClusterPrivilege: []string{
// "cat.*",
// },
// IndexPrivilege: []string{
// "indices.get_mapping",
// },
// },
// route: "indices.get_mapping",
// }, "no index permission",
//},
//{"no index api permission",
// args{
// req: EsRequest{
// Method: "GET",
// Cluster: []string{"cluster1"},
// Index: []string{"index1"},
// Path: "/index1/_mapping",
// },
// userRole: RolePermission{
// Cluster: []string{
// "cluster1",
// },
// Index: []string{
//
// "index1",
// },
// ClusterPrivilege: []string{
// "cat.*",
// },
// IndexPrivilege: []string{
// "indices.delete",
// },
// },
// route: "indices.get_mapping",
// },
// "no index api permission",
//},
{"no index permission",
args{
req: IndexRequest{
Cluster: []string{"cluster1"},
Index: []string{"index2"},
Privilege: []string{"indices.mapping"},
},
userRole: RolePermission{
Cluster: []string{
"cluster1",
},
ClusterPrivilege: []string{
"cat.*",
},
IndexPrivilege: map[string][]string{
"index1": []string{"indices.delete"},
},
},
}, "no index permission",
},
{"no index api permission",
args{
req: IndexRequest{
Cluster: []string{"cluster1"},
Index: []string{"index1"},
Privilege: []string{"indices.mapping"},
},
userRole: RolePermission{
Cluster: []string{
"cluster1",
},
ClusterPrivilege: []string{
"cat.*",
},
IndexPrivilege: map[string][]string{
"index1": []string{"indices.delete"},
},
},
},
"no index api permission",
},
}
for _, tt := range tests {
@ -89,7 +81,7 @@ func Test_validateCluster(t *testing.T) {
args args
want string
}{
{"no cluster permission",
{"no cluster",
args{
req: ClusterRequest{
@ -100,16 +92,14 @@ func Test_validateCluster(t *testing.T) {
Cluster: []string{
"cluster2",
},
Index: []string{
"index1",
},
ClusterPrivilege: []string{
"cat.*",
},
},
}, "no cluster permission",
},
{"no cluster api permission",
{"no cluster api",
args{
req: ClusterRequest{
@ -120,10 +110,7 @@ func Test_validateCluster(t *testing.T) {
Cluster: []string{
"cluster1",
},
Index: []string{
"index1",
},
ClusterPrivilege: []string{
"cat.*",
},

47
internal/middleware/es.go Normal file
View File

@ -0,0 +1,47 @@
package middleware
import (
"infini.sh/console/internal/biz"
httprouter "infini.sh/framework/core/api/router"
"net/http"
)
func IndexRequired(h httprouter.Handle, route ...string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
if err != nil {
w = handleError(w, http.StatusUnauthorized, err)
return
}
newRole := biz.CombineUserRoles(claims.Roles)
indexReq := biz.NewIndexRequest(ps, route)
err = biz.ValidateIndex(indexReq, newRole)
if err != nil {
w = handleError(w, http.StatusForbidden, err)
return
}
h(w, r, ps)
}
}
func ClusterRequired(h httprouter.Handle, route ...string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
if err != nil {
w = handleError(w, http.StatusUnauthorized, err)
return
}
newRole := biz.CombineUserRoles(claims.Roles)
clusterReq := biz.NewClusterRequest(ps, route)
err = biz.ValidateCluster(clusterReq, newRole)
if err != nil {
w = handleError(w, http.StatusForbidden, err)
return
}
h(w, r, ps)
}
}

View File

@ -19,63 +19,6 @@ func LoginRequired(h httprouter.Handle) httprouter.Handle {
h(w, r, ps)
}
}
func IndexRequired(h httprouter.Handle, route ...string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
if err != nil {
w = handleError(w, http.StatusUnauthorized, err)
return
}
newRole := biz.CombineUserRoles(claims.Roles)
indexReq := biz.NewIndexRequest(ps, route)
err = biz.ValidateIndex(indexReq, newRole)
if err != nil {
w = handleError(w, http.StatusForbidden, err)
return
}
h(w, r, ps)
}
}
func ClusterRequired(h httprouter.Handle, route ...string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
if err != nil {
w = handleError(w, http.StatusUnauthorized, err)
return
}
newRole := biz.CombineUserRoles(claims.Roles)
clusterReq := biz.NewClusterRequest(ps, route)
err = biz.ValidateCluster(clusterReq, newRole)
if err != nil {
w = handleError(w, http.StatusForbidden, err)
return
}
h(w, r, ps)
}
}
func EsPermissionRequired(h httprouter.Handle) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
//claims, err := biz.ValidateLogin(r.Header.Get("Authorization"))
//if err != nil {
// w = handleError(w, http.StatusUnauthorized, err)
// return
//}
//req := biz.NewEsRequest(r, ps)
//newRole := biz.CombineUserRoles(claims.Roles)
//err = biz.ValidateEsPermission(req, newRole)
//if err != nil {
// w = handleError(w, http.StatusForbidden, err)
// return
//}
h(w, r, ps)
}
}
func PermissionRequired(h httprouter.Handle, permissions ...string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {