From 2e8f39f9b587e2702b2f954a9df73a17c3e3f542 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Tue, 12 Apr 2022 11:15:31 +0800 Subject: [PATCH 01/75] fix: (util) TestGetMonitorPeriod time parameter pointer --- service/alerting/util/period_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service/alerting/util/period_test.go b/service/alerting/util/period_test.go index d72f06e4..ddc1370b 100644 --- a/service/alerting/util/period_test.go +++ b/service/alerting/util/period_test.go @@ -9,7 +9,7 @@ import ( func TestGetMonitorPeriod(t *testing.T) { now := time.Now() - periods := GetMonitorPeriod(&now, &alerting.Schedule{ + periods := GetMonitorPeriod(now, &alerting.Schedule{ Cron: &alerting.Cron{ Expression: "0 0 1 */1 *", }, @@ -19,4 +19,4 @@ func TestGetMonitorPeriod(t *testing.T) { //}, }) fmt.Println(periods) -} \ No newline at end of file +} From a377918e9d97ca35bb7f5f70237341a4c01279d9 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 13 Apr 2022 11:42:16 +0800 Subject: [PATCH 02/75] fear: (rbac) init load permission json file. register list permission router --- config/permission.json | 206 ++++++++++++++++++++++++++++++ plugin/api/rbac/biz/permission.go | 35 +++++ plugin/api/rbac/init.go | 40 ++++++ plugin/api/rbac/permission.go | 22 ++++ 4 files changed, 303 insertions(+) create mode 100644 config/permission.json create mode 100644 plugin/api/rbac/biz/permission.go create mode 100644 plugin/api/rbac/init.go create mode 100644 plugin/api/rbac/permission.go diff --git a/config/permission.json b/config/permission.json new file mode 100644 index 00000000..b651c014 --- /dev/null +++ b/config/permission.json @@ -0,0 +1,206 @@ +{ + "list": [ + "msearch", + "info", + "bulk", + "count", + "delete", + "termvectors", + "ping", + "mtermvectors", + "exists", + "explain", + "index", + "search", + "scroll", + "update", + "get", + "create", + "reindex", + "scripts", + "mget" + ], + "bulk": [ + "bulk" + ], + "cat": [ + "cat.indices", + "cat.help", + "cat.repositories", + "cat.pending_tasks", + "cat.tasks", + "cat.allocation", + "cat.count", + "cat.shards", + "cat.aliases", + "cat.nodeattrs", + "cat.templates", + "cat.thread_pool", + "cat.health", + "cat.recovery", + "cat.fielddata", + "cat.nodes", + "cat.plugins", + "cat.segments", + "cat.snapshots", + "cat.master" + ], + "cluster": [ + "cluster.health", + "cluster.get_settings", + "cluster.pending_tasks", + "cluster.stats", + "cluster.remote_info", + "cluster.allocation_explain", + "cluster.put_settings", + "cluster.reroute", + "cluster.state" + ], + "count": [ + "count" + ], + "doc": [ + "doc.update", + "doc.put", + "doc.create", + "doc.delete" + ], + "exists": [ + "exists" + ], + "explain": [ + "explain" + ], + "field_caps": [ + "field_caps" + ], + "get": [ + "get" + ], + "indices": [ + "indices.exists_alias", + "indices.get_alias", + "indices.recovery", + "indices.delete", + "indices.clear_cache", + "indices.update_by_query", + "indices.shrink", + "indices.forcemerge", + "indices.put_alias", + "indices.create", + "indices.split", + "indices.flush", + "indices.get_mapping", + "indices.upgrade", + "indices.validate_query", + "indices.exists_template", + "indices.get_upgrade", + "indices.update_aliases", + "indices.analyze", + "indices.exists", + "indices.close", + "indices.delete_template", + "indices.get_field_mapping", + "indices.delete_alias", + "indices.exists_type", + "indices.get_template", + "indices.put_template", + "indices.refresh", + "indices.segments", + "indices.termvectors", + "indices.flush_synced", + "indices.put_mapping", + "indices.get", + "indices.get_settings", + "indices.open", + "indices.put_settings", + "indices.stats", + "indices.delete_by_query", + "indices.rollover", + "indices.shard_stores" + ], + "info": [ + "info" + ], + "ingest": [ + "ingest.delete_pipeline", + "ingest.put_pipeline", + "ingest.simulate", + "ingest.get_pipeline", + "ingest.processor_grok" + ], + "mget": [ + "mget" + ], + "msearch": [ + "msearch" + ], + "msearch_template": [ + "msearch_template" + ], + "mtermvectors": [ + "mtermvectors" + ], + "nodes": [ + "nodes.info", + "nodes.stats", + "nodes.reload_secure_settings", + "nodes.usage", + "nodes.hot_threads" + ], + "ping": [ + "ping" + ], + "rank_eval": [ + "rank_eval" + ], + "reindex": [ + "reindex" + ], + "reindex_rethrottle": [ + "reindex_rethrottle" + ], + "render_search_template": [ + "render_search_template" + ], + "scripts": [ + "scripts.get", + "scripts.put", + "scripts.delete" + ], + "scripts_painless_execute": [ + "scripts_painless_execute" + ], + "scroll": [ + "scroll.delete" + ], + "search": [ + "search" + ], + "search_shards": [ + "search_shards" + ], + "search_template": [ + "search_template" + ], + "snapshot": [ + "snapshot.get_repository", + "snapshot.create_repository", + "snapshot.create", + "snapshot.restore", + "snapshot.status", + "snapshot.delete", + "snapshot.delete_repository", + "snapshot.verify_repository", + "snapshot.get" + ], + "source": [ + "source.head", + "source.get" + ], + "tasks": [ + "tasks.list", + "tasks.cancel", + "tasks.get" + ] +} \ No newline at end of file diff --git a/plugin/api/rbac/biz/permission.go b/plugin/api/rbac/biz/permission.go new file mode 100644 index 00000000..b610fa2a --- /dev/null +++ b/plugin/api/rbac/biz/permission.go @@ -0,0 +1,35 @@ +package biz + +var CategoryApi = make(map[string][]string) + +type ConsolePermisson struct { + Id string `json:"id"` + Name string `json:"name"` +} + +func ListConsolePermisson() (list []ConsolePermisson, err error) { + list = []ConsolePermisson{ + { + Id: "1", + Name: "数据管理", + }, + { + Id: "2", + Name: "网关管理", + }, + } + return +} + +type ElasticsearchPermisson struct { + IndexPrivileges []string `json:"index_privileges"` + ClusterPrivileges []string `json:"cluster_privileges"` +} + +func ListElasticsearchPermisson() (permisson ElasticsearchPermisson, err error) { + + permisson = ElasticsearchPermisson{ + ClusterPrivileges: CategoryApi["list"], + } + return +} diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go new file mode 100644 index 00000000..d52d14ac --- /dev/null +++ b/plugin/api/rbac/init.go @@ -0,0 +1,40 @@ +package rbac + +import ( + "encoding/json" + "infini.sh/console/plugin/api/rbac/biz" + "infini.sh/framework/core/api" + "infini.sh/framework/core/util" + "os" + "path" +) + +type Permisson struct { + api.Handler +} + +func registerRouter() { + p := Permisson{} + + api.HandleAPIMethod(api.GET, "/permission/:type", p.ListPermission) + +} +func loadJsonConfig() { + pwd, _ := os.Getwd() + + bytes, err := util.FileGetContent(path.Join(pwd, "/config/permission.json")) + if err != nil { + panic("load json file err " + err.Error()) + + } + + err = json.Unmarshal(bytes, &biz.CategoryApi) + if err != nil { + panic("json config unmarshal err " + err.Error()) + + } +} +func init() { + registerRouter() + loadJsonConfig() +} diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go new file mode 100644 index 00000000..02fec501 --- /dev/null +++ b/plugin/api/rbac/permission.go @@ -0,0 +1,22 @@ +package rbac + +import ( + httprouter "infini.sh/framework/core/api/router" + "net/http" +) + +type RoleType = string + +const ( + Console RoleType = "console" + Elastisearch RoleType = "elasticsearch" +) + +type Response struct { + Hit interface{} `json:"hit"` +} + +func (h Permisson) ListPermission(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + + return +} From 844f091a1347eb37a9727400478692482bdb2f11 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 14 Apr 2022 09:38:12 +0800 Subject: [PATCH 03/75] feat: (rbac) list permission api. fix: (model/alerting) tag syntax error --- model/alerting/monitor.go | 60 +++++++++++++++---------------- plugin/api/rbac/biz/permission.go | 1 + plugin/api/rbac/permission.go | 23 ++++++++++++ 3 files changed, 53 insertions(+), 31 deletions(-) diff --git a/model/alerting/monitor.go b/model/alerting/monitor.go index f9fbada8..53434fe0 100644 --- a/model/alerting/monitor.go +++ b/model/alerting/monitor.go @@ -1,15 +1,15 @@ package alerting type Monitor struct { - Enabled bool `json:"enabled" elastic_mapping:"enabled: {type:boolean}"` - EnabledTime int64 `json:"enabled_time" elastic_mapping:"enabled_time:{type:date,format:strict_date_time||epoch_millis}"` - Inputs []MonitorInput `json:"inputs" elastic_mapping:"inputs:{type:nested}"` - LastUpdateTime int64 `json:"last_update_time" elastic_mapping:"last_update_time:{type:date,format:strict_date_time||epoch_millis}"` - Name string `json:"name" elastic_mapping:"name:{type:text,fields: {keyword: {type: keyword, ignore_above: 256}}}"` - Schedule Schedule `json:"schedule" elastic_mapping:"schedule:{type:object}"` - SchemaVersion int `json:"schema_version" elastic_mapping:"schema_version:{type:integer}"` - Triggers []Trigger `json:"triggers" elastic_mapping:"triggers:{type:nested}"` - Type string `json:"type" elastic_mapping:"type:{type:keyword}` + Enabled bool `json:"enabled" elastic_mapping:"enabled: {type:boolean}"` + EnabledTime int64 `json:"enabled_time" elastic_mapping:"enabled_time:{type:date,format:strict_date_time||epoch_millis}"` + Inputs []MonitorInput `json:"inputs" elastic_mapping:"inputs:{type:nested}"` + LastUpdateTime int64 `json:"last_update_time" elastic_mapping:"last_update_time:{type:date,format:strict_date_time||epoch_millis}"` + Name string `json:"name" elastic_mapping:"name:{type:text,fields: {keyword: {type: keyword, ignore_above: 256}}}"` + Schedule Schedule `json:"schedule" elastic_mapping:"schedule:{type:object}"` + SchemaVersion int `json:"schema_version" elastic_mapping:"schema_version:{type:integer}"` + Triggers []Trigger `json:"triggers" elastic_mapping:"triggers:{type:nested}"` + Type string `json:"type" elastic_mapping:"type:{type:keyword}"` } type MonitorInput struct { @@ -17,47 +17,45 @@ type MonitorInput struct { } type MonitorSearch struct { - Indices []string `json:"indices" elastic_mapping:"indices:{type:text,fields: {keyword: {type: keyword, ignore_above: 256}}}"` - Query map[string]interface{} `json:"query" elastic_mapping:"query:{type:object,enabled:false}"` + Indices []string `json:"indices" elastic_mapping:"indices:{type:text,fields: {keyword: {type: keyword, ignore_above: 256}}}"` + Query map[string]interface{} `json:"query" elastic_mapping:"query:{type:object,enabled:false}"` } type Cron struct { Expression string `json:"expression" elastic_mapping:"expression:{type:text}"` - Timezone string `json:"timezone" elastic_mapping:"timezone:{type:keyword}"` + Timezone string `json:"timezone" elastic_mapping:"timezone:{type:keyword}"` } type Period struct { - Interval int `json:"interval" elastic_mapping:"interval:{type:integer}"` - Unit string `json:"unit" elastic_mapping:"unit:{type:keyword}"` + Interval int `json:"interval" elastic_mapping:"interval:{type:integer}"` + Unit string `json:"unit" elastic_mapping:"unit:{type:keyword}"` } - type Schedule struct { - Cron *Cron `json:"cron,omitempty" elastic_mapping:"cron:{type:object}"` + Cron *Cron `json:"cron,omitempty" elastic_mapping:"cron:{type:object}"` Period *Period `json:"period,omitempty" elastic_mapping:"period:{type:object}"` } - type Throttle struct { - Unit string `json:"unit" elastic_mapping:"unit:{type:keyword}"` - Value int `json:"value" elastic_mapping:"value:{type:integer}"` + Unit string `json:"unit" elastic_mapping:"unit:{type:keyword}"` + Value int `json:"value" elastic_mapping:"value:{type:integer}"` } type Action struct { - ID string `json:"id"` - DestinationId string `json:"destination_id" elastic_mapping:"destination_id:{type:keyword}"` + ID string `json:"id"` + DestinationId string `json:"destination_id" elastic_mapping:"destination_id:{type:keyword}"` MessageTemplate map[string]interface{} `json:"message_template" elastic_mapping:"message_template:{type:object}"` - Name string `json:"name" elastic_mapping:"name:{type:text,fields: {keyword: {type: keyword, ignore_above: 256}}}"` + Name string `json:"name" elastic_mapping:"name:{type:text,fields: {keyword: {type: keyword, ignore_above: 256}}}"` SubjectTemplate map[string]interface{} `json:"subject_template" elastic_mapping:"subject_template:{type:object}"` - ThrottleEnabled bool `json:"throttle_enabled" elastic_mapping:"throttle_enabled:{type:boolean}"` - Throttle *Throttle `json:"throttle,omitempty" elastic_mapping:"throttle:{type:object}"` + ThrottleEnabled bool `json:"throttle_enabled" elastic_mapping:"throttle_enabled:{type:boolean}"` + Throttle *Throttle `json:"throttle,omitempty" elastic_mapping:"throttle:{type:object}"` } type Trigger struct { - ID string `json:"id"` - Severity string `json:"severity" elastic_mapping:"severity:{type:keyword}"` - Name string `json:"name" elastic_mapping:"name:{type:text,fields: {keyword: {type: keyword, ignore_above: 256}}}"` - Condition map[string]interface{} `json:"condition" elastic_mapping:"condition:{type:object, enabled:false}"` - Actions []Action `json:"actions" elastic_mapping:"actions:{type:nested}"` - MinTimeBetweenExecutions int `json:"min_time_between_executions" elastic_mapping:"min_time_between_executions:{type:integer}"` -} \ No newline at end of file + ID string `json:"id"` + Severity string `json:"severity" elastic_mapping:"severity:{type:keyword}"` + Name string `json:"name" elastic_mapping:"name:{type:text,fields: {keyword: {type: keyword, ignore_above: 256}}}"` + Condition map[string]interface{} `json:"condition" elastic_mapping:"condition:{type:object, enabled:false}"` + Actions []Action `json:"actions" elastic_mapping:"actions:{type:nested}"` + MinTimeBetweenExecutions int `json:"min_time_between_executions" elastic_mapping:"min_time_between_executions:{type:integer}"` +} diff --git a/plugin/api/rbac/biz/permission.go b/plugin/api/rbac/biz/permission.go index b610fa2a..31b056f6 100644 --- a/plugin/api/rbac/biz/permission.go +++ b/plugin/api/rbac/biz/permission.go @@ -30,6 +30,7 @@ func ListElasticsearchPermisson() (permisson ElasticsearchPermisson, err error) permisson = ElasticsearchPermisson{ ClusterPrivileges: CategoryApi["list"], + IndexPrivileges: CategoryApi["indices"], } return } diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index 02fec501..769f5d78 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -1,6 +1,9 @@ package rbac import ( + log "github.com/cihub/seelog" + "github.com/pkg/errors" + "infini.sh/console/plugin/api/rbac/biz" httprouter "infini.sh/framework/core/api/router" "net/http" ) @@ -17,6 +20,26 @@ type Response struct { } func (h Permisson) ListPermission(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + typ := ps.MustGetParameter("type") + var err error + var permissons interface{} + switch typ { + case Console: + permissons, err = biz.ListConsolePermisson() + case Elastisearch: + permissons, err = biz.ListElasticsearchPermisson() + default: + err = errors.New("unsupport type parmeter " + typ) + } + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + + _ = h.WriteJSON(w, Response{ + Hit: permissons, + }, http.StatusOK) return } From 61d2c8dea708e3396226bc90ccdd8da9a3fcf860 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 14 Apr 2022 14:24:56 +0800 Subject: [PATCH 04/75] feat: (rbac) register role api --- plugin/api/rbac/init.go | 12 ++++++--- plugin/api/rbac/permission.go | 17 +++++++++--- plugin/api/rbac/role.go | 51 +++++++++++++++++++++++++++++++++++ plugin/api/rbac/user.go | 9 +++++++ 4 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 plugin/api/rbac/role.go create mode 100644 plugin/api/rbac/user.go diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index d52d14ac..4411f4e4 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -9,14 +9,18 @@ import ( "path" ) -type Permisson struct { +type Rbac struct { api.Handler } func registerRouter() { - p := Permisson{} - - api.HandleAPIMethod(api.GET, "/permission/:type", p.ListPermission) + r := Rbac{} + api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) + api.HandleAPIMethod(api.POST, "/role", r.CreateRole) + api.HandleAPIMethod(api.GET, "/role/:id", r.GetRole) + api.HandleAPIMethod(api.DELETE, "/role/:id", r.DeleteRole) + api.HandleAPIMethod(api.PUT, "/role/:id", r.UpdateRole) + api.HandleAPIMethod(api.GET, "/roles", r.ListRole) } func loadJsonConfig() { diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index 769f5d78..f502043e 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -19,9 +19,20 @@ type Response struct { Hit interface{} `json:"hit"` } -func (h Permisson) ListPermission(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { +func validateRoleType(roleType RoleType) (err error) { + if roleType != Console && roleType != Elastisearch { + err = errors.New("unsupport type parmeter " + roleType) + } + return +} +func (h Rbac) ListPermission(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { typ := ps.MustGetParameter("type") - var err error + err := validateRoleType(typ) + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } var permissons interface{} switch typ { case Console: @@ -29,8 +40,6 @@ func (h Permisson) ListPermission(w http.ResponseWriter, req *http.Request, ps h case Elastisearch: permissons, err = biz.ListElasticsearchPermisson() - default: - err = errors.New("unsupport type parmeter " + typ) } if err != nil { _ = log.Error(err.Error()) diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go new file mode 100644 index 00000000..dc647dce --- /dev/null +++ b/plugin/api/rbac/role.go @@ -0,0 +1,51 @@ +package rbac + +import ( + log "github.com/cihub/seelog" + httprouter "infini.sh/framework/core/api/router" + "net/http" +) + +type CreateRoleReq struct { + Name string `json:"name"` + Description string `json:"description" ` + RoleType string `json:"type" ` + Permission interface{} `json:"permission"` +} +type ElasticsearchPermission struct { + Cluster []string `json:"cluster" ` + Index []string `json:"index" ` + ClusterPrivilege []string `json:"cluster_privilege" ` + IndexPrivilege []string `json:"index_privilege" ` +} + +func (h Rbac) CreateRole(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + roleType := ps.MustGetParameter("type") + err := validateRoleType(roleType) + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + +} +func (h Rbac) ListRole(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + + roleType := ps.MustGetParameter("type") + err := validateRoleType(roleType) + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } +} +func (h Rbac) GetRole(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + _ = ps.MustGetParameter("id") + +} +func (h Rbac) DeleteRole(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + _ = ps.MustGetParameter("id") +} +func (h Rbac) UpdateRole(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + _ = ps.MustGetParameter("id") +} diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go new file mode 100644 index 00000000..8ce97e36 --- /dev/null +++ b/plugin/api/rbac/user.go @@ -0,0 +1,9 @@ +package rbac + +type CreateUserReq struct { + Username string `json:"username" ` + Password string `json:"password" ` + Name string `json:"name" ` + Phone string `json:"phone" ` + Email string `json:"email" ` +} From 4afcd7c82f0ee6d12890cf14e13f32337569aee2 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 14 Apr 2022 16:06:16 +0800 Subject: [PATCH 05/75] fix: (rbac) init load EsApis --- config/permission.json | 27 ++++++-------------------- plugin/api/rbac/biz/permission.go | 32 ++++++++++++++++++++++++------- plugin/api/rbac/init.go | 12 ++++++++++-- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/config/permission.json b/config/permission.json index b651c014..f44ec1c2 100644 --- a/config/permission.json +++ b/config/permission.json @@ -1,29 +1,10 @@ { - "list": [ - "msearch", - "info", - "bulk", - "count", - "delete", - "termvectors", - "ping", - "mtermvectors", - "exists", - "explain", - "index", - "search", - "scroll", - "update", - "get", - "create", - "reindex", - "scripts", - "mget" - ], + "bulk": [ "bulk" ], "cat": [ + "*", "cat.indices", "cat.help", "cat.repositories", @@ -46,6 +27,7 @@ "cat.master" ], "cluster": [ + "*", "cluster.health", "cluster.get_settings", "cluster.pending_tasks", @@ -57,15 +39,18 @@ "cluster.state" ], "count": [ + "*", "count" ], "doc": [ + "*", "doc.update", "doc.put", "doc.create", "doc.delete" ], "exists": [ + "*", "exists" ], "explain": [ diff --git a/plugin/api/rbac/biz/permission.go b/plugin/api/rbac/biz/permission.go index 31b056f6..6c0da28d 100644 --- a/plugin/api/rbac/biz/permission.go +++ b/plugin/api/rbac/biz/permission.go @@ -1,21 +1,39 @@ package biz -var CategoryApi = make(map[string][]string) +var ClusterApis = make([]string, 0) +var EsApis = make(map[string][]string) type ConsolePermisson struct { Id string `json:"id"` Name string `json:"name"` } +// func ListConsolePermisson() (list []ConsolePermisson, err error) { list = []ConsolePermisson{ { - Id: "1", - Name: "数据管理", + Id: "cluster_overview", + Name: "平台概览", }, { - Id: "2", - Name: "网关管理", + Id: "cluster_search", + Name: "平台搜索", + }, + { + Id: "cluster_elasticsearch", + Name: "集群监控", + }, + { + Id: "cluster_elasticsearch_refresh", + Name: "集群监控刷新", + }, + { + Id: "cluster_activities", + Name: "集群动态", + }, + { + Id: "cluster_activities_search", + Name: "集群动态搜索", }, } return @@ -29,8 +47,8 @@ type ElasticsearchPermisson struct { func ListElasticsearchPermisson() (permisson ElasticsearchPermisson, err error) { permisson = ElasticsearchPermisson{ - ClusterPrivileges: CategoryApi["list"], - IndexPrivileges: CategoryApi["indices"], + ClusterPrivileges: ClusterApis, + IndexPrivileges: EsApis["indices"], } return } diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index 4411f4e4..e1b434d8 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -23,6 +23,8 @@ func registerRouter() { api.HandleAPIMethod(api.GET, "/roles", r.ListRole) } + +//TODO 权限一级配置全局变量, func loadJsonConfig() { pwd, _ := os.Getwd() @@ -32,11 +34,17 @@ func loadJsonConfig() { } - err = json.Unmarshal(bytes, &biz.CategoryApi) + err = json.Unmarshal(bytes, &biz.EsApis) if err != nil { panic("json config unmarshal err " + err.Error()) - } + list := make([]string, 0) + list = append(list, "*") + for k := range biz.EsApis { + list = append(list, k) + } + biz.ClusterApis = list + } func init() { registerRouter() From ee7c1cb81475b4e0cda4f3bad7663335fc545bd3 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 14 Apr 2022 16:08:17 +0800 Subject: [PATCH 06/75] feat: (rbac) role and user model --- model/rbac/role.go | 22 ++++++++++++++++++++++ model/rbac/user.go | 12 ++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 model/rbac/role.go create mode 100644 model/rbac/user.go diff --git a/model/rbac/role.go b/model/rbac/role.go new file mode 100644 index 00000000..09f407a4 --- /dev/null +++ b/model/rbac/role.go @@ -0,0 +1,22 @@ +package rbac + +import "infini.sh/framework/core/orm" + +type Role struct { + orm.ORMObjectBase + Name string `json:"name" elastic_mapping:"name:{type:keyword}"` + Description string `json:"description" elastic_mapping:"description:{type:text}"` + RoleType string `json:"type" elastic_mapping:"type:{type:keyword}"` + Permission interface{} `json:"permission" elastic_mapping:"permission:{type:object}"` + BuiltIn bool `json:"builtin" elastic_mapping:"builtin:{type:boolean}"` //是否内置 +} +type ConsolePermission struct { + ID string `json:"id" elastic_mapping:"id:{type:keyword}"` + Name string `json:"name" elastic_mapping:"name:{type:keyword}"` +} +type ElasticsearchPermission struct { + Cluster []string `json:"cluster" elastic_mapping:"cluster:{type:object}"` + Index []string `json:"index" elastic_mapping:"index:{type:object}"` + ClusterPrivilege []string `json:"cluster_privilege" elastic_mapping:"cluster_privilege:{type:object}"` + IndexPrivilege []string `json:"index_privilege" elastic_mapping:"index_privilege:{type:object}"` +} diff --git a/model/rbac/user.go b/model/rbac/user.go new file mode 100644 index 00000000..e6de96fe --- /dev/null +++ b/model/rbac/user.go @@ -0,0 +1,12 @@ +package rbac + +import "infini.sh/framework/core/orm" + +type User struct { + orm.ORMObjectBase + Username string `json:"username" elastic_mapping:"username:{type:keyword}"` + Password string `json:"password" elastic_mapping:"password:{type:text}"` + Name string `json:"name" elastic_mapping:"name:{type:keyword}"` + Phone string `json:"phone" elastic_mapping:"phone:{type:keyword}"` + Email string `json:"email" elastic_mapping:"email:{type:keyword}"` +} From 6e78f1bfe6f23d4879b930a555f31f3e7911e968 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Fri, 15 Apr 2022 11:57:08 +0800 Subject: [PATCH 07/75] feat: (rbac) create role / delete role / get role --- main.go | 17 ++++--- plugin/api/rbac/biz/role.go | 77 ++++++++++++++++++++++++++++++ plugin/api/rbac/dto/role.go | 18 +++++++ plugin/api/rbac/init.go | 41 +++++++++++++++- plugin/api/rbac/permission.go | 4 -- plugin/api/rbac/role.go | 89 ++++++++++++++++++++++++++--------- 6 files changed, 209 insertions(+), 37 deletions(-) create mode 100644 plugin/api/rbac/biz/role.go create mode 100644 plugin/api/rbac/dto/role.go diff --git a/main.go b/main.go index 92cca1dd..cc9052eb 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "infini.sh/console/model" "infini.sh/console/model/alerting" "infini.sh/console/model/gateway" + "infini.sh/console/model/rbac" _ "infini.sh/console/plugin" "infini.sh/framework" "infini.sh/framework/core/elastic" @@ -49,7 +50,7 @@ func main() { terminalFooter := "" app := framework.NewApp("console", "INFINI Cloud Console, The easiest way to operate your own elasticsearch platform.", - config.Version,config.BuildNumber, config.LastCommitLog, config.BuildDate, config.EOLDate, terminalHeader, terminalFooter) + config.Version, config.BuildNumber, config.LastCommitLog, config.BuildDate, config.EOLDate, terminalHeader, terminalFooter) app.Init(nil) defer app.Shutdown() @@ -58,11 +59,10 @@ func main() { if app.Setup(func() { err := bootstrapRequirementCheck() - if err !=nil{ + if err != nil { panic(err) } - //load core modules first module.RegisterSystemModule(&elastic2.ElasticModule{}) module.RegisterSystemModule(&filter.FilterModule{}) @@ -117,20 +117,19 @@ func main() { module.Start() - orm.RegisterSchemaWithIndexName(model.Dict{}, "dict") orm.RegisterSchemaWithIndexName(model.Reindex{}, "reindex") orm.RegisterSchemaWithIndexName(elastic.View{}, "view") orm.RegisterSchemaWithIndexName(alerting.Alert{}, "alerting-alerts") orm.RegisterSchemaWithIndexName(elastic.CommonCommand{}, "commands") orm.RegisterSchemaWithIndexName(elastic.TraceTemplate{}, "trace-template") - orm.RegisterSchemaWithIndexName(gateway.Instance{} , "gateway-instance") - orm.RegisterSchemaWithIndexName(alerting.Rule{} , "alert-rule") - orm.RegisterSchemaWithIndexName(alerting.Alert{} , "alert-history") - + orm.RegisterSchemaWithIndexName(gateway.Instance{}, "gateway-instance") + orm.RegisterSchemaWithIndexName(alerting.Rule{}, "alert-rule") + orm.RegisterSchemaWithIndexName(alerting.Alert{}, "alert-history") + orm.RegisterSchemaWithIndexName(rbac.Role{}, "rbac-role") + orm.RegisterSchemaWithIndexName(rbac.User{}, "rbac-user") api.RegisterSchema() - }, nil) { app.Run() } diff --git a/plugin/api/rbac/biz/role.go b/plugin/api/rbac/biz/role.go new file mode 100644 index 00000000..2a3afdb7 --- /dev/null +++ b/plugin/api/rbac/biz/role.go @@ -0,0 +1,77 @@ +package biz + +import ( + "fmt" + "infini.sh/console/model/rbac" + "infini.sh/console/plugin/api/rbac/dto" + "infini.sh/framework/core/util" + "time" + + "infini.sh/framework/core/orm" +) + +func CreateRole(req dto.CreateRoleReq) (id string, err error) { + + q := &orm.Query{Size: 1000} + q.Conds = orm.And(orm.Eq("name", req.Name)) + + err, result := orm.Search(rbac.Role{}, q) + if err != nil { + return + } + + fmt.Println(string(result.Raw)) + role := &rbac.Role{ + Name: req.Name, + Description: req.Description, + RoleType: req.RoleType, + Permission: req.Permission, + } + role.ID = util.GetUUID() + role.Created = time.Now() + role.Updated = time.Now() + err = orm.Save(role) + return +} +func DeleteRole(id string) (err error) { + role := &rbac.Role{} + role.ID = id + _, err = orm.Get(&role) + if err != nil { + return + } + return orm.Delete(role) +} +func isExistRole(o interface{}) (err error) { + _, err = orm.Get(o) + if err != nil { + return + } + + return +} +func UpdateRole(id string, req dto.UpdateRoleReq) (err error) { + role := rbac.Role{} + role.ID = id + _, err = orm.Get(&role) + if err != nil { + return + } + role.Description = req.Description + role.Permission = req.Permission + err = orm.Save(role) + return +} +func GetRole(id string) (role rbac.Role, err error) { + + role.ID = id + _, err = orm.Get(&role) + if err != nil { + return + } + + return +} +func SearchRole() (roles []rbac.Role, err error) { + return +} diff --git a/plugin/api/rbac/dto/role.go b/plugin/api/rbac/dto/role.go new file mode 100644 index 00000000..3cc4b816 --- /dev/null +++ b/plugin/api/rbac/dto/role.go @@ -0,0 +1,18 @@ +package dto + +type CreateRoleReq struct { + Name string `json:"name"` + Description string `json:"description" ` + RoleType string `json:"type" ` + Permission interface{} `json:"permission"` +} +type UpdateRoleReq struct { + Description string `json:"description" ` + Permission interface{} `json:"permission"` +} +type ElasticsearchPermission struct { + Cluster []string `json:"cluster" ` + Index []string `json:"index" ` + ClusterPrivilege []string `json:"cluster_privilege" ` + IndexPrivilege []string `json:"index_privilege" ` +} diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index e1b434d8..fde96f46 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -16,11 +16,16 @@ type Rbac struct { func registerRouter() { r := Rbac{} api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) - api.HandleAPIMethod(api.POST, "/role", r.CreateRole) + api.HandleAPIMethod(api.POST, "/role/:type", r.CreateRole) api.HandleAPIMethod(api.GET, "/role/:id", r.GetRole) api.HandleAPIMethod(api.DELETE, "/role/:id", r.DeleteRole) api.HandleAPIMethod(api.PUT, "/role/:id", r.UpdateRole) - api.HandleAPIMethod(api.GET, "/roles", r.ListRole) + api.HandleAPIMethod(api.GET, "/roles/:type", r.ListRole) + + api.HandleAPIMethod(api.GET, "/user/:id", r.ListRole) + api.HandleAPIMethod(api.GET, "/users", r.ListRole) + api.HandleAPIMethod(api.DELETE, "/user/:id", r.ListRole) + api.HandleAPIMethod(api.GET, "/users", r.ListRole) } @@ -50,3 +55,35 @@ func init() { registerRouter() loadJsonConfig() } + +type Response struct { + Hit interface{} `json:"hit,omitempty"` + Id string `json:"_id,omitempty"` + Result string `json:"result,omitempty"` + Found bool `json:"found,omitempty"` +} + +func CreateResponse(id string) Response { + return Response{ + Id: id, + Result: "created", + } +} +func UpdateResponse(id string) Response { + return Response{ + Id: id, + Result: "updated", + } +} +func DeleteResponse(id string) Response { + return Response{ + Id: id, + Result: "deleted", + } +} +func NotFoundResponse(id string) Response { + return Response{ + Id: id, + Found: false, + } +} diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index f502043e..c4222b4c 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -15,10 +15,6 @@ const ( Elastisearch RoleType = "elasticsearch" ) -type Response struct { - Hit interface{} `json:"hit"` -} - func validateRoleType(roleType RoleType) (err error) { if roleType != Console && roleType != Elastisearch { err = errors.New("unsupport type parmeter " + roleType) diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index dc647dce..c75bd8bf 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -2,34 +2,45 @@ package rbac import ( log "github.com/cihub/seelog" + "infini.sh/console/plugin/api/rbac/biz" + "infini.sh/console/plugin/api/rbac/dto" httprouter "infini.sh/framework/core/api/router" "net/http" ) -type CreateRoleReq struct { - Name string `json:"name"` - Description string `json:"description" ` - RoleType string `json:"type" ` - Permission interface{} `json:"permission"` -} -type ElasticsearchPermission struct { - Cluster []string `json:"cluster" ` - Index []string `json:"index" ` - ClusterPrivilege []string `json:"cluster_privilege" ` - IndexPrivilege []string `json:"index_privilege" ` -} - -func (h Rbac) CreateRole(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { +func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { roleType := ps.MustGetParameter("type") - err := validateRoleType(roleType) + var err error + err = validateRoleType(roleType) if err != nil { _ = log.Error(err.Error()) _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) return } + var id string + + switch roleType { + case Console: + var req dto.CreateRoleReq + err = h.DecodeJSON(r, &req) + if err != nil { + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + + id, err = biz.CreateRole(req) + } + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + _ = h.WriteJSON(w, CreateResponse(id), http.StatusOK) + return } -func (h Rbac) ListRole(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + +func (h Rbac) ListRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { roleType := ps.MustGetParameter("type") err := validateRoleType(roleType) @@ -38,14 +49,48 @@ func (h Rbac) ListRole(w http.ResponseWriter, req *http.Request, ps httprouter.P _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) return } + return } -func (h Rbac) GetRole(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - _ = ps.MustGetParameter("id") +func (h Rbac) GetRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("id") + role, err := biz.GetRole(id) + + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + h.WriteJSON(w, Response{Hit: role}, http.StatusOK) + return } -func (h Rbac) DeleteRole(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - _ = ps.MustGetParameter("id") + +func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("id") + err := biz.DeleteRole(id) + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + _ = h.WriteJSON(w, DeleteResponse(id), http.StatusOK) } -func (h Rbac) UpdateRole(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - _ = ps.MustGetParameter("id") + +func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("id") + var req dto.UpdateRoleReq + err := h.DecodeJSON(r, &req) + if err != nil { + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + err = biz.UpdateRole(id, req) + + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + _ = h.WriteJSON(w, UpdateResponse(id), http.StatusOK) + return } From cd81b909b5cc9878521bb4ca17becd6070172a02 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Fri, 15 Apr 2022 15:55:47 +0800 Subject: [PATCH 08/75] feat: (rbac) create user / update user / get user / update user role --- model/rbac/user.go | 15 ++++-- plugin/api/rbac/biz/role.go | 18 +++---- plugin/api/rbac/biz/user.go | 103 ++++++++++++++++++++++++++++++++++++ plugin/api/rbac/dto/role.go | 25 ++++++++- plugin/api/rbac/init.go | 13 +++-- plugin/api/rbac/role.go | 25 +++++---- plugin/api/rbac/user.go | 95 +++++++++++++++++++++++++++++++++ 7 files changed, 257 insertions(+), 37 deletions(-) create mode 100644 plugin/api/rbac/biz/user.go diff --git a/model/rbac/user.go b/model/rbac/user.go index e6de96fe..d9883043 100644 --- a/model/rbac/user.go +++ b/model/rbac/user.go @@ -4,9 +4,14 @@ import "infini.sh/framework/core/orm" type User struct { orm.ORMObjectBase - Username string `json:"username" elastic_mapping:"username:{type:keyword}"` - Password string `json:"password" elastic_mapping:"password:{type:text}"` - Name string `json:"name" elastic_mapping:"name:{type:keyword}"` - Phone string `json:"phone" elastic_mapping:"phone:{type:keyword}"` - Email string `json:"email" elastic_mapping:"email:{type:keyword}"` + Username string `json:"username" elastic_mapping:"username:{type:keyword}"` + Password string `json:"password" elastic_mapping:"password:{type:text}"` + Name string `json:"name" elastic_mapping:"name:{type:keyword}"` + Phone string `json:"phone" elastic_mapping:"phone:{type:keyword}"` + Email string `json:"email" elastic_mapping:"email:{type:keyword}"` + Roles []UserRole `json:"roles" elastic_mapping:"roles:{type:text}"` +} +type UserRole struct { + Id string `json:"id"` + Name string `json:"name"` } diff --git a/plugin/api/rbac/biz/role.go b/plugin/api/rbac/biz/role.go index 2a3afdb7..56cee3fa 100644 --- a/plugin/api/rbac/biz/role.go +++ b/plugin/api/rbac/biz/role.go @@ -10,12 +10,12 @@ import ( "infini.sh/framework/core/orm" ) -func CreateRole(req dto.CreateRoleReq) (id string, err error) { +func CreateRole(req dto.CreateRole) (id string, err error) { - q := &orm.Query{Size: 1000} + q := orm.Query{Size: 1000} q.Conds = orm.And(orm.Eq("name", req.Name)) - err, result := orm.Search(rbac.Role{}, q) + err, result := orm.Search(rbac.Role{}, &q) if err != nil { return } @@ -34,7 +34,7 @@ func CreateRole(req dto.CreateRoleReq) (id string, err error) { return } func DeleteRole(id string) (err error) { - role := &rbac.Role{} + role := rbac.Role{} role.ID = id _, err = orm.Get(&role) if err != nil { @@ -42,15 +42,8 @@ func DeleteRole(id string) (err error) { } return orm.Delete(role) } -func isExistRole(o interface{}) (err error) { - _, err = orm.Get(o) - if err != nil { - return - } - return -} -func UpdateRole(id string, req dto.UpdateRoleReq) (err error) { +func UpdateRole(id string, req dto.UpdateRole) (err error) { role := rbac.Role{} role.ID = id _, err = orm.Get(&role) @@ -59,6 +52,7 @@ func UpdateRole(id string, req dto.UpdateRoleReq) (err error) { } role.Description = req.Description role.Permission = req.Permission + role.Updated = time.Now() err = orm.Save(role) return } diff --git a/plugin/api/rbac/biz/user.go b/plugin/api/rbac/biz/user.go new file mode 100644 index 00000000..b18b63bd --- /dev/null +++ b/plugin/api/rbac/biz/user.go @@ -0,0 +1,103 @@ +package biz + +import ( + "fmt" + "infini.sh/console/model/rbac" + "infini.sh/console/plugin/api/rbac/dto" + "infini.sh/framework/core/orm" + "infini.sh/framework/core/util" + "time" +) + +func DeleteUser(id string) (err error) { + + user := rbac.User{} + user.ID = id + _, err = orm.Get(&user) + if err != nil { + return + } + return orm.Delete(user) + +} +func CreateUser(req dto.CreateUser) (id string, err error) { + q := orm.Query{Size: 1000} + q.Conds = orm.And(orm.Eq("name", req.Name)) + + err, result := orm.Search(rbac.Role{}, &q) + if err != nil { + return + } + fmt.Println(string(result.Raw)) + roles := make([]rbac.UserRole, 0) + for _, v := range req.Roles { + roles = append(roles, rbac.UserRole{ + Id: v.Id, + Name: v.Name, + }) + } + user := rbac.User{ + Name: req.Name, + Username: req.Username, + Password: util.MD5digest(req.Password), + Email: req.Email, + Phone: req.Phone, + Roles: roles, + } + user.ID = util.GetUUID() + user.Created = time.Now() + user.Updated = time.Now() + err = orm.Save(&user) + if err != nil { + + return + } + return user.ID, nil +} +func UpdateUser(id string, req dto.UpdateUser) (err error) { + user := rbac.User{} + user.ID = id + _, err = orm.Get(&user) + if err != nil { + return + } + user.Name = req.Name + user.Email = req.Email + user.Phone = req.Phone + user.Updated = time.Now() + err = orm.Save(user) + return +} +func UpdateUserRole(id string, req dto.UpdateUserRole) (err error) { + user := rbac.User{} + user.ID = id + _, err = orm.Get(&user) + if err != nil { + return + } + roles := make([]rbac.UserRole, 0) + for _, v := range req.Roles { + roles = append(roles, rbac.UserRole{ + Id: v.Id, + Name: v.Name, + }) + } + user.Roles = roles + user.Updated = time.Now() + err = orm.Save(user) + return + +} +func GetUser(id string) (user rbac.User, err error) { + + user.ID = id + _, err = orm.Get(&user) + if err != nil { + return + } + return + +} +func SearchUser() { + +} diff --git a/plugin/api/rbac/dto/role.go b/plugin/api/rbac/dto/role.go index 3cc4b816..56ecc64b 100644 --- a/plugin/api/rbac/dto/role.go +++ b/plugin/api/rbac/dto/role.go @@ -1,12 +1,12 @@ package dto -type CreateRoleReq struct { +type CreateRole struct { Name string `json:"name"` Description string `json:"description" ` RoleType string `json:"type" ` Permission interface{} `json:"permission"` } -type UpdateRoleReq struct { +type UpdateRole struct { Description string `json:"description" ` Permission interface{} `json:"permission"` } @@ -16,3 +16,24 @@ type ElasticsearchPermission struct { ClusterPrivilege []string `json:"cluster_privilege" ` IndexPrivilege []string `json:"index_privilege" ` } +type CreateUser struct { + Username string `json:"username"` + Password string `json:"password"` + Name string `json:"name"` + Email string `json:"email"` + Phone string `json:"phone"` + Roles []Role `json:"roles"` +} +type Role struct { + Id string `json:"id"` + Name string `json:"name"` +} +type UpdateUser struct { + Name string `json:"name"` + Email string `json:"email"` + Phone string `json:"phone"` + // Roles []Role `json:"roles"` +} +type UpdateUserRole struct { + Roles []Role `json:"roles"` +} diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index fde96f46..1caa0507 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -20,12 +20,15 @@ func registerRouter() { api.HandleAPIMethod(api.GET, "/role/:id", r.GetRole) api.HandleAPIMethod(api.DELETE, "/role/:id", r.DeleteRole) api.HandleAPIMethod(api.PUT, "/role/:id", r.UpdateRole) - api.HandleAPIMethod(api.GET, "/roles/:type", r.ListRole) + api.HandleAPIMethod(api.GET, "/role/_search", r.SearchRole) - api.HandleAPIMethod(api.GET, "/user/:id", r.ListRole) - api.HandleAPIMethod(api.GET, "/users", r.ListRole) - api.HandleAPIMethod(api.DELETE, "/user/:id", r.ListRole) - api.HandleAPIMethod(api.GET, "/users", r.ListRole) + api.HandleAPIMethod(api.POST, "/user", r.CreateUser) + api.HandleAPIMethod(api.GET, "/user/:id", r.GetUser) + api.HandleAPIMethod(api.GET, "/user/search", r.SearchUser) + api.HandleAPIMethod(api.DELETE, "/user/:id", r.DeleteUser) + api.HandleAPIMethod(api.PUT, "/user/:id", r.UpdateUser) + api.HandleAPIMethod(api.PUT, "/user/:id/role", r.UpdateUserRole) + api.HandleAPIMethod(api.GET, "/user/_search", r.SearchUser) } diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index c75bd8bf..7e82f70c 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -17,19 +17,17 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) return } - var id string - switch roleType { - case Console: - var req dto.CreateRoleReq - err = h.DecodeJSON(r, &req) - if err != nil { - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) - return - } - - id, err = biz.CreateRole(req) + var req dto.CreateRole + err = h.DecodeJSON(r, &req) + if err != nil { + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return } + req.RoleType = roleType + + var id string + id, err = biz.CreateRole(req) if err != nil { _ = log.Error(err.Error()) _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) @@ -40,7 +38,7 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P } -func (h Rbac) ListRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { roleType := ps.MustGetParameter("type") err := validateRoleType(roleType) @@ -74,11 +72,12 @@ func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.P return } _ = h.WriteJSON(w, DeleteResponse(id), http.StatusOK) + return } func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") - var req dto.UpdateRoleReq + var req dto.UpdateRole err := h.DecodeJSON(r, &req) if err != nil { _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index 8ce97e36..c81fb2a3 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -1,5 +1,13 @@ package rbac +import ( + "infini.sh/console/plugin/api/rbac/biz" + "infini.sh/console/plugin/api/rbac/dto" + httprouter "infini.sh/framework/core/api/router" + "net/http" + log "src/github.com/cihub/seelog" +) + type CreateUserReq struct { Username string `json:"username" ` Password string `json:"password" ` @@ -7,3 +15,90 @@ type CreateUserReq struct { Phone string `json:"phone" ` Email string `json:"email" ` } + +func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + + var req dto.CreateUser + err := h.DecodeJSON(r, &req) + if err != nil { + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + id, err := biz.CreateUser(req) + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + _ = h.WriteJSON(w, CreateResponse(id), http.StatusOK) + return + +} + +func (h Rbac) GetUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("id") + user, err := biz.GetUser(id) + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + h.WriteJSON(w, Response{Hit: user}, http.StatusOK) + return +} + +func (h Rbac) UpdateUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("id") + var req dto.UpdateUser + err := h.DecodeJSON(r, &req) + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + err = biz.UpdateUser(id, req) + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + _ = h.WriteJSON(w, UpdateResponse(id), http.StatusOK) + return +} + +func (h Rbac) UpdateUserRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("id") + var req dto.UpdateUserRole + err := h.DecodeJSON(r, &req) + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + err = biz.UpdateUserRole(id, req) + + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + _ = h.WriteJSON(w, UpdateResponse(id), http.StatusOK) + return +} + +func (h Rbac) DeleteUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("id") + err := biz.DeleteUser(id) + + if err != nil { + _ = log.Error(err.Error()) + _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + _ = h.WriteJSON(w, DeleteResponse(id), http.StatusOK) + return +} + +func (h Rbac) SearchUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + +} From f0b7c1a8dd7beec0741af625bd0e62c8c213b29b Mon Sep 17 00:00:00 2001 From: xushuhui Date: Fri, 15 Apr 2022 18:03:58 +0800 Subject: [PATCH 09/75] feat: (rbac) search role api / search user api --- plugin/api/rbac/biz/permission.go | 1 - plugin/api/rbac/biz/role.go | 22 ++++++++++++++++++++-- plugin/api/rbac/biz/user.go | 25 ++++++++++++++++++++++--- plugin/api/rbac/init.go | 3 ++- plugin/api/rbac/role.go | 16 ++++++++++++---- plugin/api/rbac/user.go | 15 +++++++++++++++ 6 files changed, 71 insertions(+), 11 deletions(-) diff --git a/plugin/api/rbac/biz/permission.go b/plugin/api/rbac/biz/permission.go index 6c0da28d..ed7a1f58 100644 --- a/plugin/api/rbac/biz/permission.go +++ b/plugin/api/rbac/biz/permission.go @@ -8,7 +8,6 @@ type ConsolePermisson struct { Name string `json:"name"` } -// func ListConsolePermisson() (list []ConsolePermisson, err error) { list = []ConsolePermisson{ { diff --git a/plugin/api/rbac/biz/role.go b/plugin/api/rbac/biz/role.go index 56cee3fa..7d330490 100644 --- a/plugin/api/rbac/biz/role.go +++ b/plugin/api/rbac/biz/role.go @@ -5,6 +5,7 @@ import ( "infini.sh/console/model/rbac" "infini.sh/console/plugin/api/rbac/dto" "infini.sh/framework/core/util" + "strings" "time" "infini.sh/framework/core/orm" @@ -19,8 +20,11 @@ func CreateRole(req dto.CreateRole) (id string, err error) { if err != nil { return } + if result.Total > 0 { + err = fmt.Errorf("role name %s already exists", req.Name) + return + } - fmt.Println(string(result.Raw)) role := &rbac.Role{ Name: req.Name, Description: req.Description, @@ -31,6 +35,7 @@ func CreateRole(req dto.CreateRole) (id string, err error) { role.Created = time.Now() role.Updated = time.Now() err = orm.Save(role) + id = role.ID return } func DeleteRole(id string) (err error) { @@ -66,6 +71,19 @@ func GetRole(id string) (role rbac.Role, err error) { return } -func SearchRole() (roles []rbac.Role, err error) { +func SearchRole(keyword string, from, size int) (roles orm.Result, err error) { + query := orm.Query{} + + queryDSL := `{"query":{"bool":{"must":[%s]}}, "from": %d,"size": %d}` + mustBuilder := &strings.Builder{} + + if keyword != "" { + mustBuilder.WriteString(fmt.Sprintf(`{"query_string":{"default_field":"*","query": "%s"}}`, keyword)) + } + queryDSL = fmt.Sprintf(queryDSL, mustBuilder.String(), from, size) + query.RawQuery = []byte(queryDSL) + + err, roles = orm.Search(rbac.Role{}, &query) + return } diff --git a/plugin/api/rbac/biz/user.go b/plugin/api/rbac/biz/user.go index b18b63bd..f5dea03c 100644 --- a/plugin/api/rbac/biz/user.go +++ b/plugin/api/rbac/biz/user.go @@ -6,6 +6,7 @@ import ( "infini.sh/console/plugin/api/rbac/dto" "infini.sh/framework/core/orm" "infini.sh/framework/core/util" + "strings" "time" ) @@ -24,11 +25,15 @@ func CreateUser(req dto.CreateUser) (id string, err error) { q := orm.Query{Size: 1000} q.Conds = orm.And(orm.Eq("name", req.Name)) - err, result := orm.Search(rbac.Role{}, &q) + err, result := orm.Search(rbac.User{}, &q) if err != nil { return } - fmt.Println(string(result.Raw)) + if result.Total > 0 { + err = fmt.Errorf("user name %s already exists", req.Name) + return + } + roles := make([]rbac.UserRole, 0) for _, v := range req.Roles { roles = append(roles, rbac.UserRole{ @@ -98,6 +103,20 @@ func GetUser(id string) (user rbac.User, err error) { return } -func SearchUser() { +func SearchUser(keyword string, from, size int) (users orm.Result, err error) { + query := orm.Query{} + + queryDSL := `{"query":{"bool":{"must":[%s]}}, "from": %d,"size": %d}` + mustBuilder := &strings.Builder{} + + if keyword != "" { + mustBuilder.WriteString(fmt.Sprintf(`{"query_string":{"default_field":"*","query": "%s"}}`, keyword)) + } + queryDSL = fmt.Sprintf(queryDSL, mustBuilder.String(), from, size) + query.RawQuery = []byte(queryDSL) + + err, users = orm.Search(rbac.User{}, &query) + + return } diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index 1caa0507..f75d5a35 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -60,6 +60,7 @@ func init() { } type Response struct { + Total int64 `json:"total,omitempty"` Hit interface{} `json:"hit,omitempty"` Id string `json:"_id,omitempty"` Result string `json:"result,omitempty"` @@ -86,7 +87,7 @@ func DeleteResponse(id string) Response { } func NotFoundResponse(id string) Response { return Response{ - Id: id, + Found: false, } } diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 7e82f70c..17eddf16 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -40,14 +40,22 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - roleType := ps.MustGetParameter("type") - err := validateRoleType(roleType) + var ( + keyword = h.GetParameterOrDefault(r, "keyword", "") + from = h.GetIntOrDefault(r, "from", 0) + size = h.GetIntOrDefault(r, "size", 20) + ) + + res, err := biz.SearchRole(keyword, from, size) if err != nil { - _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + log.Error(err) + h.WriteError(w, err.Error(), http.StatusInternalServerError) return } + + h.WriteJSON(w, Response{Hit: res.Result, Total: res.Total}, http.StatusOK) return + } func (h Rbac) GetRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index c81fb2a3..20292c19 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -100,5 +100,20 @@ func (h Rbac) DeleteUser(w http.ResponseWriter, r *http.Request, ps httprouter.P } func (h Rbac) SearchUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + var ( + keyword = h.GetParameterOrDefault(r, "keyword", "") + from = h.GetIntOrDefault(r, "from", 0) + size = h.GetIntOrDefault(r, "size", 20) + ) + + res, err := biz.SearchUser(keyword, from, size) + if err != nil { + log.Error(err) + h.WriteError(w, err.Error(), http.StatusInternalServerError) + return + } + + h.WriteJSON(w, Response{Hit: res.Result, Total: res.Total}, http.StatusOK) + return } From dc8bd1cd1b75c143be3cbf965e860c1dda3649ff Mon Sep 17 00:00:00 2001 From: xushuhui Date: Sat, 16 Apr 2022 17:10:54 +0800 Subject: [PATCH 10/75] refactor: (rbac) move biz and dto to internal dir fix: orm get not found error --- .../api/rbac => internal}/biz/permission.go | 0 {plugin/api/rbac => internal}/biz/role.go | 7 ++- {plugin/api/rbac => internal}/biz/user.go | 12 ++++- {plugin/api/rbac => internal}/dto/role.go | 21 ++++---- internal/dto/user.go | 6 +++ internal/middleware/user.go | 8 ++++ plugin/api/rbac/init.go | 14 ++++-- plugin/api/rbac/permission.go | 7 +-- plugin/api/rbac/role.go | 22 +++++---- plugin/api/rbac/user.go | 48 ++++++++++++------- 10 files changed, 95 insertions(+), 50 deletions(-) rename {plugin/api/rbac => internal}/biz/permission.go (100%) rename {plugin/api/rbac => internal}/biz/role.go (95%) rename {plugin/api/rbac => internal}/biz/user.go (90%) rename {plugin/api/rbac => internal}/dto/role.go (67%) create mode 100644 internal/dto/user.go create mode 100644 internal/middleware/user.go diff --git a/plugin/api/rbac/biz/permission.go b/internal/biz/permission.go similarity index 100% rename from plugin/api/rbac/biz/permission.go rename to internal/biz/permission.go diff --git a/plugin/api/rbac/biz/role.go b/internal/biz/role.go similarity index 95% rename from plugin/api/rbac/biz/role.go rename to internal/biz/role.go index 7d330490..f4a9c673 100644 --- a/plugin/api/rbac/biz/role.go +++ b/internal/biz/role.go @@ -2,8 +2,9 @@ package biz import ( "fmt" + "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" - "infini.sh/console/plugin/api/rbac/dto" + "infini.sh/framework/core/util" "strings" "time" @@ -43,6 +44,7 @@ func DeleteRole(id string) (err error) { role.ID = id _, err = orm.Get(&role) if err != nil { + err = ErrNotFound return } return orm.Delete(role) @@ -53,6 +55,7 @@ func UpdateRole(id string, req dto.UpdateRole) (err error) { role.ID = id _, err = orm.Get(&role) if err != nil { + err = ErrNotFound return } role.Description = req.Description @@ -66,9 +69,9 @@ func GetRole(id string) (role rbac.Role, err error) { role.ID = id _, err = orm.Get(&role) if err != nil { + err = ErrNotFound return } - return } func SearchRole(keyword string, from, size int) (roles orm.Result, err error) { diff --git a/plugin/api/rbac/biz/user.go b/internal/biz/user.go similarity index 90% rename from plugin/api/rbac/biz/user.go rename to internal/biz/user.go index f5dea03c..4699290e 100644 --- a/plugin/api/rbac/biz/user.go +++ b/internal/biz/user.go @@ -2,20 +2,24 @@ package biz import ( "fmt" + "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" - "infini.sh/console/plugin/api/rbac/dto" + "infini.sh/framework/core/orm" "infini.sh/framework/core/util" "strings" "time" ) +var ErrNotFound = fmt.Errorf("not found") + func DeleteUser(id string) (err error) { user := rbac.User{} user.ID = id _, err = orm.Get(&user) if err != nil { + err = ErrNotFound return } return orm.Delete(user) @@ -23,7 +27,7 @@ func DeleteUser(id string) (err error) { } func CreateUser(req dto.CreateUser) (id string, err error) { q := orm.Query{Size: 1000} - q.Conds = orm.And(orm.Eq("name", req.Name)) + q.Conds = orm.And(orm.Eq("username", req.Username)) err, result := orm.Search(rbac.User{}, &q) if err != nil { @@ -48,6 +52,7 @@ func CreateUser(req dto.CreateUser) (id string, err error) { Email: req.Email, Phone: req.Phone, Roles: roles, + Tags: req.Tags, } user.ID = util.GetUUID() user.Created = time.Now() @@ -64,11 +69,13 @@ func UpdateUser(id string, req dto.UpdateUser) (err error) { user.ID = id _, err = orm.Get(&user) if err != nil { + err = ErrNotFound return } user.Name = req.Name user.Email = req.Email user.Phone = req.Phone + user.Tags = req.Tags user.Updated = time.Now() err = orm.Save(user) return @@ -78,6 +85,7 @@ func UpdateUserRole(id string, req dto.UpdateUserRole) (err error) { user.ID = id _, err = orm.Get(&user) if err != nil { + err = ErrNotFound return } roles := make([]rbac.UserRole, 0) diff --git a/plugin/api/rbac/dto/role.go b/internal/dto/role.go similarity index 67% rename from plugin/api/rbac/dto/role.go rename to internal/dto/role.go index 56ecc64b..a919e4e4 100644 --- a/plugin/api/rbac/dto/role.go +++ b/internal/dto/role.go @@ -17,22 +17,23 @@ type ElasticsearchPermission struct { IndexPrivilege []string `json:"index_privilege" ` } type CreateUser struct { - Username string `json:"username"` - Password string `json:"password"` - Name string `json:"name"` - Email string `json:"email"` - Phone string `json:"phone"` - Roles []Role `json:"roles"` + Username string `json:"username"` + Password string `json:"password"` + Name string `json:"name"` + Email string `json:"email"` + Phone string `json:"phone"` + Roles []Role `json:"roles"` + Tags []string `json:"tags"` } type Role struct { Id string `json:"id"` Name string `json:"name"` } type UpdateUser struct { - Name string `json:"name"` - Email string `json:"email"` - Phone string `json:"phone"` - // Roles []Role `json:"roles"` + Name string `json:"name"` + Email string `json:"email"` + Phone string `json:"phone"` + Tags []string `json:"tags"` } type UpdateUserRole struct { Roles []Role `json:"roles"` diff --git a/internal/dto/user.go b/internal/dto/user.go new file mode 100644 index 00000000..55a7290f --- /dev/null +++ b/internal/dto/user.go @@ -0,0 +1,6 @@ +package dto + +type Login struct { + Username string `json:"username"` + Password string `json:"password"` +} diff --git a/internal/middleware/user.go b/internal/middleware/user.go new file mode 100644 index 00000000..c8808e79 --- /dev/null +++ b/internal/middleware/user.go @@ -0,0 +1,8 @@ +package middleware + +func LoginRequired() { + +} +func PermissionRequired() { + +} diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index f75d5a35..babcf327 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -2,7 +2,8 @@ package rbac import ( "encoding/json" - "infini.sh/console/plugin/api/rbac/biz" + "infini.sh/console/internal/biz" + "infini.sh/framework/core/api" "infini.sh/framework/core/util" "os" @@ -64,7 +65,10 @@ type Response struct { Hit interface{} `json:"hit,omitempty"` Id string `json:"_id,omitempty"` Result string `json:"result,omitempty"` - Found bool `json:"found,omitempty"` +} +type NotFoundResp struct { + Found bool `json:"found"` + Id string `json:"_id,omitempty"` } func CreateResponse(id string) Response { @@ -85,9 +89,9 @@ func DeleteResponse(id string) Response { Result: "deleted", } } -func NotFoundResponse(id string) Response { - return Response{ - +func NotFoundResponse(id string) NotFoundResp { + return NotFoundResp{ + Id: id, Found: false, } } diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index c4222b4c..c7c4365e 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -3,7 +3,8 @@ package rbac import ( log "github.com/cihub/seelog" "github.com/pkg/errors" - "infini.sh/console/plugin/api/rbac/biz" + "infini.sh/console/internal/biz" + httprouter "infini.sh/framework/core/api/router" "net/http" ) @@ -26,7 +27,7 @@ func (h Rbac) ListPermission(w http.ResponseWriter, req *http.Request, ps httpro err := validateRoleType(typ) if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } var permissons interface{} @@ -39,7 +40,7 @@ func (h Rbac) ListPermission(w http.ResponseWriter, req *http.Request, ps httpro } if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 17eddf16..9a5a1b73 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -2,8 +2,9 @@ package rbac import ( log "github.com/cihub/seelog" - "infini.sh/console/plugin/api/rbac/biz" - "infini.sh/console/plugin/api/rbac/dto" + "infini.sh/console/internal/biz" + "infini.sh/console/internal/dto" + httprouter "infini.sh/framework/core/api/router" "net/http" ) @@ -14,14 +15,14 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P err = validateRoleType(roleType) if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } var req dto.CreateRole err = h.DecodeJSON(r, &req) if err != nil { - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } req.RoleType = roleType @@ -30,7 +31,7 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P id, err = biz.CreateRole(req) if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } _ = h.WriteJSON(w, CreateResponse(id), http.StatusOK) @@ -49,7 +50,7 @@ func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.P res, err := biz.SearchRole(keyword, from, size) if err != nil { log.Error(err) - h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } @@ -64,7 +65,7 @@ func (h Rbac) GetRole(w http.ResponseWriter, r *http.Request, ps httprouter.Para if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } h.WriteJSON(w, Response{Hit: role}, http.StatusOK) @@ -74,9 +75,10 @@ func (h Rbac) GetRole(w http.ResponseWriter, r *http.Request, ps httprouter.Para func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") err := biz.DeleteRole(id) + if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } _ = h.WriteJSON(w, DeleteResponse(id), http.StatusOK) @@ -88,14 +90,14 @@ func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P var req dto.UpdateRole err := h.DecodeJSON(r, &req) if err != nil { - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } err = biz.UpdateRole(id, req) if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } _ = h.WriteJSON(w, UpdateResponse(id), http.StatusOK) diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index 20292c19..6761fa7d 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -1,19 +1,22 @@ package rbac import ( - "infini.sh/console/plugin/api/rbac/biz" - "infini.sh/console/plugin/api/rbac/dto" + "errors" + "infini.sh/console/internal/biz" + "infini.sh/console/internal/dto" httprouter "infini.sh/framework/core/api/router" + "infini.sh/framework/modules/elastic" "net/http" log "src/github.com/cihub/seelog" ) type CreateUserReq struct { - Username string `json:"username" ` - Password string `json:"password" ` - Name string `json:"name" ` - Phone string `json:"phone" ` - Email string `json:"email" ` + Username string `json:"username" ` + Password string `json:"password" ` + Name string `json:"name" ` + Phone string `json:"phone" ` + Email string `json:"email" ` + Tags []string `json:"tags"` } func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { @@ -21,13 +24,13 @@ func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P var req dto.CreateUser err := h.DecodeJSON(r, &req) if err != nil { - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } id, err := biz.CreateUser(req) if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } _ = h.WriteJSON(w, CreateResponse(id), http.StatusOK) @@ -38,9 +41,14 @@ func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P func (h Rbac) GetUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") user, err := biz.GetUser(id) + if errors.Is(err, elastic.ErrNotFound) { + h.WriteJSON(w, NotFoundResponse(id), http.StatusNotFound) + return + } + if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } h.WriteJSON(w, Response{Hit: user}, http.StatusOK) @@ -53,13 +61,14 @@ func (h Rbac) UpdateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P err := h.DecodeJSON(r, &req) if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } err = biz.UpdateUser(id, req) + if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } _ = h.WriteJSON(w, UpdateResponse(id), http.StatusOK) @@ -72,14 +81,14 @@ func (h Rbac) UpdateUserRole(w http.ResponseWriter, r *http.Request, ps httprout err := h.DecodeJSON(r, &req) if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } err = biz.UpdateUserRole(id, req) if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } _ = h.WriteJSON(w, UpdateResponse(id), http.StatusOK) @@ -89,10 +98,13 @@ func (h Rbac) UpdateUserRole(w http.ResponseWriter, r *http.Request, ps httprout func (h Rbac) DeleteUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") err := biz.DeleteUser(id) - + if errors.Is(err, elastic.ErrNotFound) { + h.WriteJSON(w, NotFoundResponse(id), http.StatusNotFound) + return + } if err != nil { _ = log.Error(err.Error()) - _ = h.WriteError(w, err.Error(), http.StatusInternalServerError) + h.Error(w, err) return } _ = h.WriteJSON(w, DeleteResponse(id), http.StatusOK) @@ -108,8 +120,8 @@ func (h Rbac) SearchUser(w http.ResponseWriter, r *http.Request, ps httprouter.P res, err := biz.SearchUser(keyword, from, size) if err != nil { - log.Error(err) - h.WriteError(w, err.Error(), http.StatusInternalServerError) + log.Error(err.Error()) + h.Error(w, err) return } From 8c013a613b4a502863486a3567d20fb6e41e689a Mon Sep 17 00:00:00 2001 From: xushuhui Date: Mon, 18 Apr 2022 16:02:14 +0800 Subject: [PATCH 11/75] feat: (rbac) permission validate / user tags --- internal/biz/account.go | 117 ++++++++++++++++++++++++++++++++++ internal/biz/context.go | 29 +++++++++ internal/middleware/user.go | 36 ++++++++++- model/rbac/role.go | 30 ++++++++- model/rbac/user.go | 1 + plugin/api/account/account.go | 109 +++++++++++++++---------------- plugin/api/rbac/init.go | 5 +- 7 files changed, 264 insertions(+), 63 deletions(-) create mode 100644 internal/biz/account.go create mode 100644 internal/biz/context.go diff --git a/internal/biz/account.go b/internal/biz/account.go new file mode 100644 index 00000000..44941811 --- /dev/null +++ b/internal/biz/account.go @@ -0,0 +1,117 @@ +package biz + +import ( + "errors" + "fmt" + "infini.sh/framework/core/global" + "infini.sh/framework/core/util" + "net/http" + "src/github.com/golang-jwt/jwt" + "strings" + "time" +) + +type UserClaims struct { + *jwt.RegisteredClaims + *User +} +type User struct { + Username string `json:"username"` + UserId string `json:"user_id"` + ApiPermission map[string]struct{} `json:"api_permission"` +} + +const Secret = "console" + +func Login(username string, password string) (m map[string]interface{}, err error) { + + u, _ := global.Env().GetConfig("bootstrap.username", "admin") + p, _ := global.Env().GetConfig("bootstrap.password", "admin") + + if u != username || p != password { + err = errors.New("invalid username or password") + return + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims{ + User: &User{ + Username: u, + UserId: "admin", + ApiPermission: map[string]struct{}{ + "account.profile": struct{}{}, + }, + }, + RegisteredClaims: &jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), + }, + }) + + tokenString, err := token.SignedString([]byte(Secret)) + if err != nil { + + return + } + m = util.MapStr{ + "access_token": tokenString, + "username": u, + "userid": "admin", + } + + return + +} + +func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { + + if authorizationHeader == "" { + err = errors.New("authorization header is empty") + return + } + fields := strings.Fields(authorizationHeader) + if fields[0] != "Bearer" || len(fields) != 2 { + err = errors.New("authorization header is invalid") + return + } + tokenString := fields[1] + token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + + return []byte(Secret), nil + }) + if err != nil { + return + } + if clams, ok := token.Claims.(*UserClaims); ok && token.Valid { + return clams, nil + } + if clams.UserId == "" { + err = errors.New("user id is empty") + return + } + return + +} +func ValidatePermission(r *http.Request, permissions string) (err error) { + reqUser, err := FromUserContext(r.Context()) + if err != nil { + + return + } + if reqUser.UserId == "" { + err = errors.New("user id is empty") + return + } + if reqUser.ApiPermission == nil { + err = errors.New("api permission is empty") + return + } + + if _, ok := reqUser.ApiPermission[permissions]; !ok { + err = errors.New("permission denied") + return + } + + return + +} diff --git a/internal/biz/context.go b/internal/biz/context.go new file mode 100644 index 00000000..d4953794 --- /dev/null +++ b/internal/biz/context.go @@ -0,0 +1,29 @@ +package biz + +import ( + "context" + "errors" +) + +const ctxUserKey = "user" + +func NewUserContext(ctx context.Context, clam *UserClaims) context.Context { + return context.WithValue(ctx, ctxUserKey, clam) +} +func FromUserContext(ctx context.Context) (*User, error) { + ctxUser := ctx.Value(ctxUserKey) + if ctxUser == nil { + return nil, errors.New("user not found") + } + reqUser, ok := ctxUser.(*UserClaims) + if !ok { + return nil, errors.New("invalid context user") + } + return reqUser.User, nil +} +func NewPermissionContext(ctx context.Context) { + +} +func FromPermissionContext(ctx context.Context) { + +} diff --git a/internal/middleware/user.go b/internal/middleware/user.go index c8808e79..8c3f9b11 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -1,8 +1,38 @@ package middleware -func LoginRequired() { +import ( + "infini.sh/console/internal/biz" + httprouter "infini.sh/framework/core/api/router" + "infini.sh/framework/core/util" + "net/http" +) -} -func PermissionRequired() { +func LoginRequired(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, err) + return + } + r = r.WithContext(biz.NewUserContext(r.Context(), claims)) + h(w, r, ps) + } +} + +func PermissionRequired(h httprouter.Handle, permissions string) httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + err := biz.ValidatePermission(r, permissions) + if err != nil { + w = handleError(w, err) + return + } + h(w, r, ps) + } +} +func handleError(w http.ResponseWriter, err error) http.ResponseWriter { + w.Header().Set("Content-type", util.ContentTypeJson) + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(`{"error":"` + err.Error() + `"}`)) + return w } diff --git a/model/rbac/role.go b/model/rbac/role.go index 09f407a4..a174a590 100644 --- a/model/rbac/role.go +++ b/model/rbac/role.go @@ -1,6 +1,9 @@ package rbac -import "infini.sh/framework/core/orm" +import ( + "infini.sh/framework/core/orm" + "time" +) type Role struct { orm.ORMObjectBase @@ -20,3 +23,28 @@ type ElasticsearchPermission struct { ClusterPrivilege []string `json:"cluster_privilege" elastic_mapping:"cluster_privilege:{type:object}"` IndexPrivilege []string `json:"index_privilege" elastic_mapping:"index_privilege:{type:object}"` } + +type ConsoleOperate struct { + UserId string `json:"user_id" elastic_mapping:"user_id:{type:keyword}"` +} +type Operation struct { + Id string `json:"id"` + Timestamp time.Time `json:"timestamp"` + Metadata struct { + Labels struct { + Userid string `json:"userid"` + Username string `json:"username"` + } `json:"labels"` + Category string `json:"category"` + Group string `json:"group"` + Name string `json:"name"` + Type string `json:"type"` + } `json:"metadata"` + Changelog []struct { + From string `json:"from"` + Path []string `json:"path"` + To string `json:"to"` + Type string `json:"type"` + } `json:"changelog"` + Payload interface{} `json:"payload"` +} diff --git a/model/rbac/user.go b/model/rbac/user.go index d9883043..d9ebcf32 100644 --- a/model/rbac/user.go +++ b/model/rbac/user.go @@ -10,6 +10,7 @@ type User struct { Phone string `json:"phone" elastic_mapping:"phone:{type:keyword}"` Email string `json:"email" elastic_mapping:"email:{type:keyword}"` Roles []UserRole `json:"roles" elastic_mapping:"roles:{type:text}"` + Tags []string `json:"tags" elastic_mapping:"tags:{type:text}"` } type UserRole struct { Id string `json:"id"` diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index 7ed4da78..62cf8793 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -1,9 +1,11 @@ package account import ( + "infini.sh/console/internal/biz" + "infini.sh/console/internal/dto" + m "infini.sh/console/internal/middleware" "infini.sh/framework/core/api" - "infini.sh/framework/core/api/router" - "infini.sh/framework/core/global" + "infini.sh/framework/core/api/router" "infini.sh/framework/core/util" "net/http" ) @@ -13,94 +15,87 @@ type Account struct { } func init() { - account:=Account{} - api.HandleAPIMethod(api.POST, "/account/login", account.AccountLogin) + account := Account{} + api.HandleAPIMethod(api.POST, "/account/login", account.Login) + api.HandleAPIMethod(api.GET, "/account/current_user", account.CurrentUser) + + api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout) + api.HandleAPIMethod(api.GET, "/account/profile", + m.LoginRequired(account.Profile)) } -var userInSession string="user_in_session" +const userInSession = "user_in_session" -func (handler Account)AccountLogin(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { +func (h Account) Login(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - //{"userName":"admin","password":"111111","type":"account"} - - json,err:=handler.GetJSON(req) - if err!=nil{ - handler.Error(w,err) - return - } - userName,err:=json.String("userName") - if err!=nil{ - handler.Error(w,err) - return - } - password,err:=json.String("password") - if err!=nil{ - handler.Error(w,err) + var req dto.Login + err := h.DecodeJSON(r, &req) + if err != nil { + h.Error(w, err) return } - u,_:=global.Env().GetConfig("bootstrap.username","admin") - p,_:=global.Env().GetConfig("bootstrap.password","admin") - if u==userName&&p==password{ - data := util.MapStr{ - "status": "ok", - "type": "account", - "currentAuthority": "admin", - "userid": "10001", - } - api.SetSession(w,req, userInSession,userName) - handler.WriteJSON(w, data, http.StatusOK) - }else{ - data := util.MapStr{ - "status": "error", - "type": "account", - "currentAuthority": "guest", - } - handler.WriteJSON(w, data, http.StatusOK) + data, err := biz.Login(req.Username, req.Password) + if err != nil { + h.Error(w, err) + return } + h.WriteJSON(w, data, http.StatusOK) } -func (handler Account)CurrentUser(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { +func (h Account) CurrentUser(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - exists,user:=api.GetSession(w,req, userInSession) - if exists{ - data:=util.MapStr{ - "name": user, - "avatar": "", - "userid": "10001", - "email": "hello@infini.ltd", + exists, user := api.GetSession(w, req, userInSession) + if exists { + data := util.MapStr{ + "name": user, + "avatar": "", + "userid": "10001", + "email": "hello@infini.ltd", "signature": "极限科技 - 专业的开源搜索与实时数据分析整体解决方案提供商。", - "title": "首席设计师", - "group": "INFINI Labs", + "title": "首席设计师", + "group": "INFINI Labs", "tags": []util.MapStr{ { - "key": "0", + "key": "0", "label": "很有想法的", }}, "notifyCount": 12, - "country": "China", + "country": "China", "geographic": util.MapStr{ "province": util.MapStr{ "label": "湖南省", - "key": "330000", + "key": "330000", }, "city": util.MapStr{ "label": "长沙市", - "key": "330100", + "key": "330100", }, }, "address": "岳麓区湘江金融中心", - "phone": "4001399200", + "phone": "4001399200", } - handler.WriteJSON(w, data,200) - }else{ + h.WriteJSON(w, data, 200) + } else { data := util.MapStr{ "status": "error", "type": "account", "currentAuthority": "guest", } - handler.WriteJSON(w, data, 403) + h.WriteJSON(w, data, 403) } } +func (h Account) Logout(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + +} +func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + reqUser, err := biz.FromUserContext(r.Context()) + if err != nil { + h.Error(w, err) + return + } + h.WriteJSON(w, reqUser, 200) + return +} diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index babcf327..283c9b1d 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -3,6 +3,7 @@ package rbac import ( "encoding/json" "infini.sh/console/internal/biz" + m "infini.sh/console/internal/middleware" "infini.sh/framework/core/api" "infini.sh/framework/core/util" @@ -18,10 +19,10 @@ func registerRouter() { r := Rbac{} api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) api.HandleAPIMethod(api.POST, "/role/:type", r.CreateRole) - api.HandleAPIMethod(api.GET, "/role/:id", r.GetRole) + api.HandleAPIMethod(api.GET, "/role/:id", m.LoginRequired(r.GetRole)) api.HandleAPIMethod(api.DELETE, "/role/:id", r.DeleteRole) api.HandleAPIMethod(api.PUT, "/role/:id", r.UpdateRole) - api.HandleAPIMethod(api.GET, "/role/_search", r.SearchRole) + api.HandleAPIMethod(api.GET, "/role/_search", m.LoginRequired(m.PermissionRequired(r.SearchRole, "search.role"))) api.HandleAPIMethod(api.POST, "/user", r.CreateUser) api.HandleAPIMethod(api.GET, "/user/:id", r.GetUser) From 65dd1f2209cc969552bdd9a0bc43600c87699409 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Mon, 18 Apr 2022 18:20:15 +0800 Subject: [PATCH 12/75] feat: (rbac) localuser --- internal/biz/context.go | 6 ---- internal/biz/event.go | 17 +++++++++ internal/biz/permission.go | 65 +++++++++++++++++++++++++++++++++-- internal/biz/role.go | 57 +++++++++++++++++++++++++++--- plugin/api/account/account.go | 9 +++-- plugin/api/rbac/init.go | 24 ++++++------- plugin/api/rbac/permission.go | 40 ++++----------------- plugin/api/rbac/role.go | 44 ++++++++++++++++-------- plugin/api/rbac/user.go | 12 +++---- 9 files changed, 190 insertions(+), 84 deletions(-) create mode 100644 internal/biz/event.go diff --git a/internal/biz/context.go b/internal/biz/context.go index d4953794..2d4a8e49 100644 --- a/internal/biz/context.go +++ b/internal/biz/context.go @@ -21,9 +21,3 @@ func FromUserContext(ctx context.Context) (*User, error) { } return reqUser.User, nil } -func NewPermissionContext(ctx context.Context) { - -} -func FromPermissionContext(ctx context.Context) { - -} diff --git a/internal/biz/event.go b/internal/biz/event.go new file mode 100644 index 00000000..8619e491 --- /dev/null +++ b/internal/biz/event.go @@ -0,0 +1,17 @@ +package biz + +import ( + "infini.sh/framework/core/event" + "infini.sh/framework/core/util" + "time" +) + +func GenerateEvent(metadata event.ActivityMetadata, fields util.MapStr) *event.Activity { + return &event.Activity{ + ID: util.GetUUID(), + Timestamp: time.Now(), + Metadata: metadata, + Fields: fields, + } + +} diff --git a/internal/biz/permission.go b/internal/biz/permission.go index ed7a1f58..1bb4384b 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -1,15 +1,45 @@ package biz +import "fmt" + var ClusterApis = make([]string, 0) var EsApis = make(map[string][]string) +type RoleType = string + +const ( + Console RoleType = "console" + Elastisearch RoleType = "elasticsearch" +) + +type IRole interface { + ListPermission() interface{} +} +type ConsoleRole struct { +} +type ElasticsearchRole struct { +} + +func NewRole(typ string) (r IRole, err error) { + switch typ { + case Console: + r = &ConsoleRole{} + + case Elastisearch: + r = &ElasticsearchRole{} + default: + err = fmt.Errorf("role type %s not support", typ) + } + return +} + type ConsolePermisson struct { Id string `json:"id"` Name string `json:"name"` } -func ListConsolePermisson() (list []ConsolePermisson, err error) { - list = []ConsolePermisson{ +func (r ConsoleRole) ListPermission() interface{} { + list := []ConsolePermisson{ { Id: "cluster_overview", Name: "平台概览", @@ -35,7 +65,36 @@ func ListConsolePermisson() (list []ConsolePermisson, err error) { Name: "集群动态搜索", }, } - return + return list +} +func (r ElasticsearchRole) ListPermission() interface{} { + list := []ConsolePermisson{ + { + Id: "cluster_overview", + Name: "平台概览", + }, + { + Id: "cluster_search", + Name: "平台搜索", + }, + { + Id: "cluster_elasticsearch", + Name: "集群监控", + }, + { + Id: "cluster_elasticsearch_refresh", + Name: "集群监控刷新", + }, + { + Id: "cluster_activities", + Name: "集群动态", + }, + { + Id: "cluster_activities_search", + Name: "集群动态搜索", + }, + } + return list } type ElasticsearchPermisson struct { diff --git a/internal/biz/role.go b/internal/biz/role.go index f4a9c673..0a810f13 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -4,6 +4,8 @@ import ( "fmt" "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" + "infini.sh/framework/core/event" + log "src/github.com/cihub/seelog" "infini.sh/framework/core/util" "strings" @@ -12,7 +14,7 @@ import ( "infini.sh/framework/core/orm" ) -func CreateRole(req dto.CreateRole) (id string, err error) { +func CreateRole(localUser *User, req dto.CreateRole) (id string, err error) { q := orm.Query{Size: 1000} q.Conds = orm.And(orm.Eq("name", req.Name)) @@ -36,10 +38,36 @@ func CreateRole(req dto.CreateRole) (id string, err error) { role.Created = time.Now() role.Updated = time.Now() err = orm.Save(role) + if err != nil { + return + } id = role.ID + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "role", + Type: "create", + Labels: util.MapStr{ + "id": id, + "name": req.Name, + "description": req.Description, + "permission": req.Permission, + "type": req.RoleType, + "created": role.Created.Format("2006-01-02 15:04:05"), + "updated": role.Updated.Format("2006-01-02 15:04:05"), + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, nil)) + + if err != nil { + log.Error(err) + } return } -func DeleteRole(id string) (err error) { +func DeleteRole(localUser *User, id string) (err error) { role := rbac.Role{} role.ID = id _, err = orm.Get(&role) @@ -47,10 +75,31 @@ func DeleteRole(id string) (err error) { err = ErrNotFound return } - return orm.Delete(role) + err = orm.Delete(role) + if err != nil { + return + } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "role", + Type: "delete", + Labels: util.MapStr{ + "id": id, + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, nil)) + + if err != nil { + log.Error(err) + } + return } -func UpdateRole(id string, req dto.UpdateRole) (err error) { +func UpdateRole(localUser *User, id string, req dto.UpdateRole) (err error) { role := rbac.Role{} role.ID = id _, err = orm.Get(&role) diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index 62cf8793..6e661714 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -18,11 +18,10 @@ func init() { account := Account{} api.HandleAPIMethod(api.POST, "/account/login", account.Login) - api.HandleAPIMethod(api.GET, "/account/current_user", account.CurrentUser) + //api.HandleAPIMethod(api.GET, "/account/current_user", account.CurrentUser) - api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout) - api.HandleAPIMethod(api.GET, "/account/profile", - m.LoginRequired(account.Profile)) + api.HandleAPIMethod(api.DELETE, "/account/logout", m.LoginRequired(account.Logout)) + api.HandleAPIMethod(api.GET, "/account/profile", m.LoginRequired(account.Profile)) } const userInSession = "user_in_session" @@ -41,7 +40,7 @@ func (h Account) Login(w http.ResponseWriter, r *http.Request, ps httprouter.Par h.Error(w, err) return } - h.WriteJSON(w, data, http.StatusOK) + h.WriteOKJSON(w, data) } func (h Account) CurrentUser(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index 283c9b1d..e3cc0ef5 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -17,20 +17,20 @@ type Rbac struct { func registerRouter() { r := Rbac{} - api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) - api.HandleAPIMethod(api.POST, "/role/:type", r.CreateRole) - api.HandleAPIMethod(api.GET, "/role/:id", m.LoginRequired(r.GetRole)) - api.HandleAPIMethod(api.DELETE, "/role/:id", r.DeleteRole) - api.HandleAPIMethod(api.PUT, "/role/:id", r.UpdateRole) + api.HandleAPIMethod(api.GET, "/permission/:type", m.LoginRequired(m.PermissionRequired(r.ListPermission, "list.permission"))) + api.HandleAPIMethod(api.POST, "/role/:type", m.LoginRequired(m.PermissionRequired(r.CreateRole, "create.role"))) + api.HandleAPIMethod(api.GET, "/role/:id", m.LoginRequired(m.PermissionRequired(r.GetRole, "get.role"))) + api.HandleAPIMethod(api.DELETE, "/role/:id", m.LoginRequired(m.PermissionRequired(r.DeleteRole, "delete.role"))) + api.HandleAPIMethod(api.PUT, "/role/:id", m.LoginRequired(m.PermissionRequired(r.UpdateRole, "update.role"))) api.HandleAPIMethod(api.GET, "/role/_search", m.LoginRequired(m.PermissionRequired(r.SearchRole, "search.role"))) - api.HandleAPIMethod(api.POST, "/user", r.CreateUser) - api.HandleAPIMethod(api.GET, "/user/:id", r.GetUser) - api.HandleAPIMethod(api.GET, "/user/search", r.SearchUser) - api.HandleAPIMethod(api.DELETE, "/user/:id", r.DeleteUser) - api.HandleAPIMethod(api.PUT, "/user/:id", r.UpdateUser) - api.HandleAPIMethod(api.PUT, "/user/:id/role", r.UpdateUserRole) - api.HandleAPIMethod(api.GET, "/user/_search", r.SearchUser) + api.HandleAPIMethod(api.POST, "/user", m.LoginRequired(m.PermissionRequired(r.CreateUser, "create.user"))) + api.HandleAPIMethod(api.GET, "/user/:id", m.LoginRequired(m.PermissionRequired(r.GetUser, "get.user"))) + api.HandleAPIMethod(api.GET, "/user/search", m.LoginRequired(m.PermissionRequired(r.SearchUser, "search.user"))) + api.HandleAPIMethod(api.DELETE, "/user/:id", m.LoginRequired(m.PermissionRequired(r.DeleteUser, "delete.user"))) + api.HandleAPIMethod(api.PUT, "/user/:id", m.LoginRequired(m.PermissionRequired(r.UpdateUser, "update.user"))) + api.HandleAPIMethod(api.PUT, "/user/:id/role", m.LoginRequired(m.PermissionRequired(r.UpdateUserRole, "update.user.role"))) + api.HandleAPIMethod(api.GET, "/user/_search", m.LoginRequired(m.PermissionRequired(r.SearchUser, "search.user"))) } diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index c7c4365e..1f480a53 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -2,50 +2,24 @@ package rbac import ( log "github.com/cihub/seelog" - "github.com/pkg/errors" "infini.sh/console/internal/biz" httprouter "infini.sh/framework/core/api/router" "net/http" ) -type RoleType = string - -const ( - Console RoleType = "console" - Elastisearch RoleType = "elasticsearch" -) - -func validateRoleType(roleType RoleType) (err error) { - if roleType != Console && roleType != Elastisearch { - err = errors.New("unsupport type parmeter " + roleType) - } - return -} -func (h Rbac) ListPermission(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { +func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { typ := ps.MustGetParameter("type") - err := validateRoleType(typ) + role, err := biz.NewRole(typ) + if err != nil { _ = log.Error(err.Error()) h.Error(w, err) return } - var permissons interface{} - switch typ { - case Console: - permissons, err = biz.ListConsolePermisson() - - case Elastisearch: - permissons, err = biz.ListElasticsearchPermisson() - } - if err != nil { - _ = log.Error(err.Error()) - h.Error(w, err) - return - } - - _ = h.WriteJSON(w, Response{ - Hit: permissons, - }, http.StatusOK) + permissions := role.ListPermission() + h.WriteOKJSON(w, Response{ + Hit: permissions, + }) return } diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 9a5a1b73..32a687f5 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -4,7 +4,6 @@ import ( log "github.com/cihub/seelog" "infini.sh/console/internal/biz" "infini.sh/console/internal/dto" - httprouter "infini.sh/framework/core/api/router" "net/http" ) @@ -12,12 +11,6 @@ import ( func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { roleType := ps.MustGetParameter("type") var err error - err = validateRoleType(roleType) - if err != nil { - _ = log.Error(err.Error()) - h.Error(w, err) - return - } var req dto.CreateRole err = h.DecodeJSON(r, &req) @@ -28,13 +21,20 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P req.RoleType = roleType var id string - id, err = biz.CreateRole(req) + localUser, err := biz.FromUserContext(r.Context()) + if err != nil { + log.Error(err.Error()) + h.Error(w, err) + return + } + id, err = biz.CreateRole(localUser, req) if err != nil { _ = log.Error(err.Error()) h.Error(w, err) return } - _ = h.WriteJSON(w, CreateResponse(id), http.StatusOK) + + _ = h.WriteOKJSON(w, CreateResponse(id)) return } @@ -54,7 +54,7 @@ func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.P return } - h.WriteJSON(w, Response{Hit: res.Result, Total: res.Total}, http.StatusOK) + h.WriteOKJSON(w, Response{Hit: res.Result, Total: res.Total}) return } @@ -68,38 +68,52 @@ func (h Rbac) GetRole(w http.ResponseWriter, r *http.Request, ps httprouter.Para h.Error(w, err) return } - h.WriteJSON(w, Response{Hit: role}, http.StatusOK) + h.WriteOKJSON(w, Response{Hit: role}) return } func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") - err := biz.DeleteRole(id) + + localUser, err := biz.FromUserContext(r.Context()) + if err != nil { + log.Error(err.Error()) + h.Error(w, err) + return + } + err = biz.DeleteRole(localUser, id) if err != nil { _ = log.Error(err.Error()) h.Error(w, err) return } - _ = h.WriteJSON(w, DeleteResponse(id), http.StatusOK) + _ = h.WriteOKJSON(w, DeleteResponse(id)) return } func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") + var req dto.UpdateRole err := h.DecodeJSON(r, &req) if err != nil { h.Error(w, err) return } - err = biz.UpdateRole(id, req) + localUser, err := biz.FromUserContext(r.Context()) + if err != nil { + log.Error(err.Error()) + h.Error(w, err) + return + } + err = biz.UpdateRole(localUser, id, req) if err != nil { _ = log.Error(err.Error()) h.Error(w, err) return } - _ = h.WriteJSON(w, UpdateResponse(id), http.StatusOK) + _ = h.WriteOKJSON(w, UpdateResponse(id)) return } diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index 6761fa7d..88f51d17 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -33,7 +33,7 @@ func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - _ = h.WriteJSON(w, CreateResponse(id), http.StatusOK) + _ = h.WriteOKJSON(w, CreateResponse(id)) return } @@ -51,7 +51,7 @@ func (h Rbac) GetUser(w http.ResponseWriter, r *http.Request, ps httprouter.Para h.Error(w, err) return } - h.WriteJSON(w, Response{Hit: user}, http.StatusOK) + h.WriteOKJSON(w, Response{Hit: user}) return } @@ -71,7 +71,7 @@ func (h Rbac) UpdateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - _ = h.WriteJSON(w, UpdateResponse(id), http.StatusOK) + _ = h.WriteOKJSON(w, UpdateResponse(id)) return } @@ -91,7 +91,7 @@ func (h Rbac) UpdateUserRole(w http.ResponseWriter, r *http.Request, ps httprout h.Error(w, err) return } - _ = h.WriteJSON(w, UpdateResponse(id), http.StatusOK) + _ = h.WriteOKJSON(w, UpdateResponse(id)) return } @@ -107,7 +107,7 @@ func (h Rbac) DeleteUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - _ = h.WriteJSON(w, DeleteResponse(id), http.StatusOK) + _ = h.WriteOKJSON(w, DeleteResponse(id)) return } @@ -125,7 +125,7 @@ func (h Rbac) SearchUser(w http.ResponseWriter, r *http.Request, ps httprouter.P return } - h.WriteJSON(w, Response{Hit: res.Result, Total: res.Total}, http.StatusOK) + h.WriteOKJSON(w, Response{Hit: res.Result, Total: res.Total}) return } From 74ddc44ce7c5bbe087317eb7c87efba3a1c7c0a3 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Tue, 19 Apr 2022 12:03:56 +0800 Subject: [PATCH 13/75] feat: (rbac) init load rolePermission / validate user permission / operation log --- internal/biz/account.go | 41 +++++++++----- internal/biz/enum/const.go | 13 +++++ internal/biz/permission.go | 44 ++------------ internal/biz/role.go | 32 +++++++++-- internal/biz/user.go | 104 +++++++++++++++++++++++++++++++--- internal/middleware/user.go | 9 ++- plugin/api/account/account.go | 2 +- plugin/api/rbac/init.go | 33 ++++++----- plugin/api/rbac/user.go | 32 +++++++++-- 9 files changed, 226 insertions(+), 84 deletions(-) create mode 100644 internal/biz/enum/const.go diff --git a/internal/biz/account.go b/internal/biz/account.go index 44941811..a891b15e 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -5,7 +5,6 @@ import ( "fmt" "infini.sh/framework/core/global" "infini.sh/framework/core/util" - "net/http" "src/github.com/golang-jwt/jwt" "strings" "time" @@ -16,9 +15,9 @@ type UserClaims struct { *User } type User struct { - Username string `json:"username"` - UserId string `json:"user_id"` - ApiPermission map[string]struct{} `json:"api_permission"` + Username string `json:"username"` + UserId string `json:"user_id"` + Role []string `json:"role"` } const Secret = "console" @@ -36,9 +35,7 @@ func Login(username string, password string) (m map[string]interface{}, err erro User: &User{ Username: u, UserId: "admin", - ApiPermission: map[string]struct{}{ - "account.profile": struct{}{}, - }, + Role: []string{"admin_user"}, }, RegisteredClaims: &jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), @@ -92,8 +89,9 @@ func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { return } -func ValidatePermission(r *http.Request, permissions string) (err error) { - reqUser, err := FromUserContext(r.Context()) +func ValidatePermission(claims *UserClaims, permissions []string) (err error) { + + reqUser := claims.User if err != nil { return @@ -102,16 +100,31 @@ func ValidatePermission(r *http.Request, permissions string) (err error) { err = errors.New("user id is empty") return } - if reqUser.ApiPermission == nil { + if reqUser.Role == nil { err = errors.New("api permission is empty") return } - if _, ok := reqUser.ApiPermission[permissions]; !ok { - err = errors.New("permission denied") - return + // 权限校验 + userPermissionMap := make(map[string]struct{}) + for _, role := range reqUser.Role { + if _, ok := RolePermission[role]; ok { + for _, v := range RolePermission[role] { + userPermissionMap[v] = struct{}{} + } + } } - + var count int + for _, v := range permissions { + if _, ok := userPermissionMap[v]; ok { + count++ + continue + } + } + if count == len(permissions) { + return nil + } + err = errors.New("permission denied") return } diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go new file mode 100644 index 00000000..f64f892d --- /dev/null +++ b/internal/biz/enum/const.go @@ -0,0 +1,13 @@ +package enum + +const CreateUser = "create_user" +const UpdateUser = "update_user" +const DeleteUser = "delete_user" +const GetUser = "get_user" +const ListUser = "list_user" +const CreateRole = "create_role" +const UpdateRole = "update_role" +const DeleteRole = "delete_role" +const GetRole = "get_role" +const ListRole = "list_role" +const ListPermission = "list_permission" diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 1bb4384b..8ba25b40 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -4,6 +4,7 @@ import "fmt" var ClusterApis = make([]string, 0) var EsApis = make(map[string][]string) +var RolePermission = make(map[string][]string) type RoleType = string @@ -15,10 +16,8 @@ const ( type IRole interface { ListPermission() interface{} } -type ConsoleRole struct { -} -type ElasticsearchRole struct { -} +type ConsoleRole struct{} +type ElasticsearchRole struct{} func NewRole(typ string) (r IRole, err error) { switch typ { @@ -68,31 +67,9 @@ func (r ConsoleRole) ListPermission() interface{} { return list } func (r ElasticsearchRole) ListPermission() interface{} { - list := []ConsolePermisson{ - { - Id: "cluster_overview", - Name: "平台概览", - }, - { - Id: "cluster_search", - Name: "平台搜索", - }, - { - Id: "cluster_elasticsearch", - Name: "集群监控", - }, - { - Id: "cluster_elasticsearch_refresh", - Name: "集群监控刷新", - }, - { - Id: "cluster_activities", - Name: "集群动态", - }, - { - Id: "cluster_activities_search", - Name: "集群动态搜索", - }, + list := ElasticsearchPermisson{ + ClusterPrivileges: ClusterApis, + IndexPrivileges: EsApis["indices"], } return list } @@ -101,12 +78,3 @@ type ElasticsearchPermisson struct { IndexPrivileges []string `json:"index_privileges"` ClusterPrivileges []string `json:"cluster_privileges"` } - -func ListElasticsearchPermisson() (permisson ElasticsearchPermisson, err error) { - - permisson = ElasticsearchPermisson{ - ClusterPrivileges: ClusterApis, - IndexPrivileges: EsApis["indices"], - } - return -} diff --git a/internal/biz/role.go b/internal/biz/role.go index 0a810f13..75ce6f66 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -91,11 +91,16 @@ func DeleteRole(localUser *User, id string) (err error) { "userid": localUser.UserId, "username": localUser.Username, }, - }, nil)) + }, util.MapStr{ + "id": id, + "name": role.Name, + "description": role.Description, + "permission": role.Permission, + "type": role.RoleType, + "created": role.Created.Format("2006-01-02 15:04:05"), + "updated": role.Updated.Format("2006-01-02 15:04:05"), + })) - if err != nil { - log.Error(err) - } return } @@ -111,6 +116,25 @@ func UpdateRole(localUser *User, id string, req dto.UpdateRole) (err error) { role.Permission = req.Permission role.Updated = time.Now() err = orm.Save(role) + if err != nil { + return + } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "role", + Type: "update", + Labels: util.MapStr{ + "id": id, + "description": role.Description, + "permission": role.Permission, + "updated": role.Updated, + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, nil)) return } func GetRole(id string) (role rbac.Role, err error) { diff --git a/internal/biz/user.go b/internal/biz/user.go index 4699290e..271761a0 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -4,6 +4,7 @@ import ( "fmt" "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" + "infini.sh/framework/core/event" "infini.sh/framework/core/orm" "infini.sh/framework/core/util" @@ -13,7 +14,7 @@ import ( var ErrNotFound = fmt.Errorf("not found") -func DeleteUser(id string) (err error) { +func DeleteUser(localUser *User, id string) (err error) { user := rbac.User{} user.ID = id @@ -22,10 +23,37 @@ func DeleteUser(id string) (err error) { err = ErrNotFound return } - return orm.Delete(user) - + err = orm.Delete(user) + if err != nil { + return + } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "user", + Type: "delete", + Labels: util.MapStr{ + "id": id, + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, util.MapStr{ + "id": id, + "username": user.Username, + "email": user.Email, + "phone": user.Phone, + "password": user.Password, + "name": user.Name, + "tags": user.Tags, + "roles": user.Roles, + "created": user.Created, + "updated": user.Updated, + })) + return } -func CreateUser(req dto.CreateUser) (id string, err error) { +func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) { q := orm.Query{Size: 1000} q.Conds = orm.And(orm.Eq("username", req.Username)) @@ -62,9 +90,32 @@ func CreateUser(req dto.CreateUser) (id string, err error) { return } - return user.ID, nil + id = user.ID + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "user", + Type: "create", + Labels: util.MapStr{ + "id": id, + "username": user.Username, + "email": user.Email, + "phone": user.Phone, + "password": user.Password, + "name": user.Name, + "tags": user.Tags, + "roles": user.Roles, + "created": user.Created, + "updated": user.Updated, + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, nil)) + return } -func UpdateUser(id string, req dto.UpdateUser) (err error) { +func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { user := rbac.User{} user.ID = id _, err = orm.Get(&user) @@ -78,9 +129,30 @@ func UpdateUser(id string, req dto.UpdateUser) (err error) { user.Tags = req.Tags user.Updated = time.Now() err = orm.Save(user) + if err != nil { + return + } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "user", + Type: "update", + Labels: util.MapStr{ + "id": id, + "email": user.Email, + "phone": user.Phone, + "name": user.Name, + "tags": user.Tags, + "updated": user.Updated, + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, nil)) return } -func UpdateUserRole(id string, req dto.UpdateUserRole) (err error) { +func UpdateUserRole(localUser *User, id string, req dto.UpdateUserRole) (err error) { user := rbac.User{} user.ID = id _, err = orm.Get(&user) @@ -98,6 +170,24 @@ func UpdateUserRole(id string, req dto.UpdateUserRole) (err error) { user.Roles = roles user.Updated = time.Now() err = orm.Save(user) + if err != nil { + return + } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "user", + Type: "update", + Labels: util.MapStr{ + "id": id, + "roles": user.Roles, + "updated": user.Updated, + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, nil)) return } diff --git a/internal/middleware/user.go b/internal/middleware/user.go index 8c3f9b11..e3466cd6 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -20,9 +20,14 @@ func LoginRequired(h httprouter.Handle) httprouter.Handle { } } -func PermissionRequired(h httprouter.Handle, permissions string) httprouter.Handle { +func PermissionRequired(h httprouter.Handle, permissions ...string) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - err := biz.ValidatePermission(r, permissions) + claims, err := biz.ValidateLogin(r.Header.Get("Authorization")) + if err != nil { + w = handleError(w, err) + return + } + err = biz.ValidatePermission(claims, permissions) if err != nil { w = handleError(w, err) return diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index 6e661714..e0d6db45 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -20,7 +20,7 @@ func init() { //api.HandleAPIMethod(api.GET, "/account/current_user", account.CurrentUser) - api.HandleAPIMethod(api.DELETE, "/account/logout", m.LoginRequired(account.Logout)) + api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout) api.HandleAPIMethod(api.GET, "/account/profile", m.LoginRequired(account.Profile)) } diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index e3cc0ef5..b988105c 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -3,6 +3,7 @@ package rbac import ( "encoding/json" "infini.sh/console/internal/biz" + "infini.sh/console/internal/biz/enum" m "infini.sh/console/internal/middleware" "infini.sh/framework/core/api" @@ -17,24 +18,23 @@ type Rbac struct { func registerRouter() { r := Rbac{} - api.HandleAPIMethod(api.GET, "/permission/:type", m.LoginRequired(m.PermissionRequired(r.ListPermission, "list.permission"))) - api.HandleAPIMethod(api.POST, "/role/:type", m.LoginRequired(m.PermissionRequired(r.CreateRole, "create.role"))) - api.HandleAPIMethod(api.GET, "/role/:id", m.LoginRequired(m.PermissionRequired(r.GetRole, "get.role"))) - api.HandleAPIMethod(api.DELETE, "/role/:id", m.LoginRequired(m.PermissionRequired(r.DeleteRole, "delete.role"))) - api.HandleAPIMethod(api.PUT, "/role/:id", m.LoginRequired(m.PermissionRequired(r.UpdateRole, "update.role"))) - api.HandleAPIMethod(api.GET, "/role/_search", m.LoginRequired(m.PermissionRequired(r.SearchRole, "search.role"))) + api.HandleAPIMethod(api.GET, "/permission/:type", m.PermissionRequired(r.ListPermission, enum.ListPermission)) + api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.CreateRole)) + api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.GetRole)) + api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.DeleteRole)) + api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.UpdateRole)) + api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.ListRole)) - api.HandleAPIMethod(api.POST, "/user", m.LoginRequired(m.PermissionRequired(r.CreateUser, "create.user"))) - api.HandleAPIMethod(api.GET, "/user/:id", m.LoginRequired(m.PermissionRequired(r.GetUser, "get.user"))) - api.HandleAPIMethod(api.GET, "/user/search", m.LoginRequired(m.PermissionRequired(r.SearchUser, "search.user"))) - api.HandleAPIMethod(api.DELETE, "/user/:id", m.LoginRequired(m.PermissionRequired(r.DeleteUser, "delete.user"))) - api.HandleAPIMethod(api.PUT, "/user/:id", m.LoginRequired(m.PermissionRequired(r.UpdateUser, "update.user"))) - api.HandleAPIMethod(api.PUT, "/user/:id/role", m.LoginRequired(m.PermissionRequired(r.UpdateUserRole, "update.user.role"))) - api.HandleAPIMethod(api.GET, "/user/_search", m.LoginRequired(m.PermissionRequired(r.SearchUser, "search.user"))) + api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.CreateUser)) + api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.GetUser)) + api.HandleAPIMethod(api.GET, "/user/search", m.PermissionRequired(r.SearchUser, enum.ListUser)) + api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.DeleteUser)) + api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UpdateUser)) + api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UpdateUser)) + api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.ListUser)) } -//TODO 权限一级配置全局变量, func loadJsonConfig() { pwd, _ := os.Getwd() @@ -56,9 +56,14 @@ func loadJsonConfig() { biz.ClusterApis = list } +func loadRolePermission() { + biz.RolePermission = make(map[string][]string) + biz.RolePermission["admin_user"] = []string{enum.GetUser} +} func init() { registerRouter() loadJsonConfig() + loadRolePermission() } type Response struct { diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index 88f51d17..d86a16ff 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -27,7 +27,13 @@ func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - id, err := biz.CreateUser(req) + localUser, err := biz.FromUserContext(r.Context()) + if err != nil { + log.Error(err.Error()) + h.Error(w, err) + return + } + id, err := biz.CreateUser(localUser, req) if err != nil { _ = log.Error(err.Error()) h.Error(w, err) @@ -64,7 +70,13 @@ func (h Rbac) UpdateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - err = biz.UpdateUser(id, req) + localUser, err := biz.FromUserContext(r.Context()) + if err != nil { + log.Error(err.Error()) + h.Error(w, err) + return + } + err = biz.UpdateUser(localUser, id, req) if err != nil { _ = log.Error(err.Error()) @@ -84,7 +96,13 @@ func (h Rbac) UpdateUserRole(w http.ResponseWriter, r *http.Request, ps httprout h.Error(w, err) return } - err = biz.UpdateUserRole(id, req) + localUser, err := biz.FromUserContext(r.Context()) + if err != nil { + log.Error(err.Error()) + h.Error(w, err) + return + } + err = biz.UpdateUserRole(localUser, id, req) if err != nil { _ = log.Error(err.Error()) @@ -97,7 +115,13 @@ func (h Rbac) UpdateUserRole(w http.ResponseWriter, r *http.Request, ps httprout func (h Rbac) DeleteUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") - err := biz.DeleteUser(id) + localUser, err := biz.FromUserContext(r.Context()) + if err != nil { + log.Error(err.Error()) + h.Error(w, err) + return + } + err = biz.DeleteUser(localUser, id) if errors.Is(err, elastic.ErrNotFound) { h.WriteJSON(w, NotFoundResponse(id), http.StatusNotFound) return From 7e9f39cb88d24acbc7ba58384c6cc484d57d8ff1 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Tue, 19 Apr 2022 18:20:52 +0800 Subject: [PATCH 14/75] feat: (rbac) build in role / logout / login operation log --- internal/biz/account.go | 81 ++++++++++++++++++++++++++++++----- internal/biz/enum/const.go | 55 +++++++++++++++++++++++- internal/biz/event.go | 3 +- internal/biz/role.go | 7 +-- internal/biz/user.go | 10 +++-- internal/middleware/user.go | 1 + model/rbac/role.go | 5 ++- plugin/api/account/account.go | 3 ++ plugin/api/rbac/init.go | 8 ++-- plugin/api/rbac/role.go | 10 ++++- 10 files changed, 155 insertions(+), 28 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index a891b15e..5dd6f184 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -3,7 +3,10 @@ package biz import ( "errors" "fmt" + "infini.sh/console/model/rbac" + "infini.sh/framework/core/event" "infini.sh/framework/core/global" + "infini.sh/framework/core/orm" "infini.sh/framework/core/util" "src/github.com/golang-jwt/jwt" "strings" @@ -17,12 +20,31 @@ type UserClaims struct { type User struct { Username string `json:"username"` UserId string `json:"user_id"` - Role []string `json:"role"` + Roles []string `json:"roles"` } const Secret = "console" -func Login(username string, password string) (m map[string]interface{}, err error) { +func authenticateUser(username string, password string) (user rbac.User, err error) { + q := orm.Query{Size: 1000} + q.Conds = orm.And(orm.Eq("username", username)) + + err, result := orm.Search(rbac.User{}, &q) + if err != nil { + return + } + if result.Total == 0 { + err = errors.New("user not found") + return + } + user = result.Result[0].(rbac.User) + if util.MD5digest(password) != user.Password { + err = errors.New("password error") + return + } + return +} +func authenticateAdmin(username string, password string) (user rbac.User, err error) { u, _ := global.Env().GetConfig("bootstrap.username", "admin") p, _ := global.Env().GetConfig("bootstrap.password", "admin") @@ -31,11 +53,16 @@ func Login(username string, password string) (m map[string]interface{}, err erro err = errors.New("invalid username or password") return } + user.ID = username + user.Username = username + return user, nil +} +func authorize(user rbac.User) (m map[string]interface{}, err error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims{ User: &User{ - Username: u, - UserId: "admin", - Role: []string{"admin_user"}, + Username: user.Username, + UserId: user.ID, + Roles: []string{"admin"}, }, RegisteredClaims: &jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), @@ -44,17 +71,49 @@ func Login(username string, password string) (m map[string]interface{}, err erro tokenString, err := token.SignedString([]byte(Secret)) if err != nil { - return } m = util.MapStr{ "access_token": tokenString, - "username": u, - "userid": "admin", + "username": user.Username, + "userid": user.ID, + } + return +} +func Login(username string, password string) (m map[string]interface{}, err error) { + var user rbac.User + if username == "admin" { + user, err = authenticateAdmin(username, password) + if err != nil { + return nil, err + } + + } else { + user, err = authenticateUser(username, password) + if err != nil { + return nil, err + } } + m, err = authorize(user) + if err != nil { + return + } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "login", + Type: "create", + Labels: util.MapStr{ + "username": username, + "password": password, + }, + User: util.MapStr{ + "userid": user.ID, + "username": user.Username, + }, + }, nil, nil)) return - } func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { @@ -100,14 +159,14 @@ func ValidatePermission(claims *UserClaims, permissions []string) (err error) { err = errors.New("user id is empty") return } - if reqUser.Role == nil { + if reqUser.Roles == nil { err = errors.New("api permission is empty") return } // 权限校验 userPermissionMap := make(map[string]struct{}) - for _, role := range reqUser.Role { + for _, role := range reqUser.Roles { if _, ok := RolePermission[role]; ok { for _, v := range RolePermission[role] { userPermissionMap[v] = struct{}{} diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index f64f892d..6c468feb 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -1,13 +1,64 @@ package enum +import ( + "infini.sh/console/model/rbac" + "infini.sh/framework/core/orm" +) + const CreateUser = "create_user" const UpdateUser = "update_user" const DeleteUser = "delete_user" const GetUser = "get_user" -const ListUser = "list_user" +const SearchUser = "search_user" + const CreateRole = "create_role" const UpdateRole = "update_role" const DeleteRole = "delete_role" const GetRole = "get_role" -const ListRole = "list_role" +const SearchRole = "search_role" const ListPermission = "list_permission" + +const CreateRule = "create_rule" +const UpdateRule = "update_rule" +const DeleteRule = "delete_rule" +const GetRule = "get_rule" +const SearchRule = "search_rule" + +const CreateInstance = "create_instance" +const UpdateInstance = "update_instance" +const DeleteInstance = "delete_instance" +const GetInstance = "get_instance" +const SearchInstance = "search_instance" +const GetInstanceStatus = "get_instance_status" +const ConnectInstance = "connect_instance" +const InstanceProxy = "instance_proxy" + +var Admin = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} +var AdminUser = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser} + +var BuildRoles = []rbac.Role{ + { + ORMObjectBase: orm.ORMObjectBase{ + ID: "admin", + }, + Name: "admin", + Description: "管理员", + RoleType: "console", + Permission: rbac.ConsolePermission{ + ApiPermission: Admin, + }, + BuiltIn: true, + }, + { + ORMObjectBase: orm.ORMObjectBase{ + ID: "admin_user", + }, + Name: "admin_user", + Description: "用户模块管理员", + RoleType: "console", + Permission: rbac.ConsolePermission{ + ApiPermission: AdminUser, + }, + BuiltIn: true, + }, +} diff --git a/internal/biz/event.go b/internal/biz/event.go index 8619e491..224b82a5 100644 --- a/internal/biz/event.go +++ b/internal/biz/event.go @@ -6,12 +6,13 @@ import ( "time" ) -func GenerateEvent(metadata event.ActivityMetadata, fields util.MapStr) *event.Activity { +func GenerateEvent(metadata event.ActivityMetadata, fields util.MapStr, changeLog interface{}) *event.Activity { return &event.Activity{ ID: util.GetUUID(), Timestamp: time.Now(), Metadata: metadata, Fields: fields, + Changelog: changeLog, } } diff --git a/internal/biz/role.go b/internal/biz/role.go index 75ce6f66..f2464500 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -60,7 +60,7 @@ func CreateRole(localUser *User, req dto.CreateRole) (id string, err error) { "userid": localUser.UserId, "username": localUser.Username, }, - }, nil)) + }, nil, nil)) if err != nil { log.Error(err) @@ -99,7 +99,7 @@ func DeleteRole(localUser *User, id string) (err error) { "type": role.RoleType, "created": role.Created.Format("2006-01-02 15:04:05"), "updated": role.Updated.Format("2006-01-02 15:04:05"), - })) + }, nil)) return } @@ -112,6 +112,7 @@ func UpdateRole(localUser *User, id string, req dto.UpdateRole) (err error) { err = ErrNotFound return } + changeLog, _ := util.DiffTwoObject(role, req) role.Description = req.Description role.Permission = req.Permission role.Updated = time.Now() @@ -134,7 +135,7 @@ func UpdateRole(localUser *User, id string, req dto.UpdateRole) (err error) { "userid": localUser.UserId, "username": localUser.Username, }, - }, nil)) + }, nil, changeLog)) return } func GetRole(id string) (role rbac.Role, err error) { diff --git a/internal/biz/user.go b/internal/biz/user.go index 271761a0..283daa92 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -50,7 +50,7 @@ func DeleteUser(localUser *User, id string) (err error) { "roles": user.Roles, "created": user.Created, "updated": user.Updated, - })) + }, nil)) return } func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) { @@ -112,7 +112,7 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) { "userid": localUser.UserId, "username": localUser.Username, }, - }, nil)) + }, nil, nil)) return } func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { @@ -123,6 +123,7 @@ func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { err = ErrNotFound return } + changeLog, _ := util.DiffTwoObject(user, req) user.Name = req.Name user.Email = req.Email user.Phone = req.Phone @@ -149,7 +150,7 @@ func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { "userid": localUser.UserId, "username": localUser.Username, }, - }, nil)) + }, nil, changeLog)) return } func UpdateUserRole(localUser *User, id string, req dto.UpdateUserRole) (err error) { @@ -160,6 +161,7 @@ func UpdateUserRole(localUser *User, id string, req dto.UpdateUserRole) (err err err = ErrNotFound return } + changeLog, _ := util.DiffTwoObject(user, req) roles := make([]rbac.UserRole, 0) for _, v := range req.Roles { roles = append(roles, rbac.UserRole{ @@ -187,7 +189,7 @@ func UpdateUserRole(localUser *User, id string, req dto.UpdateUserRole) (err err "userid": localUser.UserId, "username": localUser.Username, }, - }, nil)) + }, nil, changeLog)) return } diff --git a/internal/middleware/user.go b/internal/middleware/user.go index e3466cd6..d822adbc 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -32,6 +32,7 @@ func PermissionRequired(h httprouter.Handle, permissions ...string) httprouter.H w = handleError(w, err) return } + r = r.WithContext(biz.NewUserContext(r.Context(), claims)) h(w, r, ps) } } diff --git a/model/rbac/role.go b/model/rbac/role.go index a174a590..07331e6c 100644 --- a/model/rbac/role.go +++ b/model/rbac/role.go @@ -14,8 +14,9 @@ type Role struct { BuiltIn bool `json:"builtin" elastic_mapping:"builtin:{type:boolean}"` //是否内置 } type ConsolePermission struct { - ID string `json:"id" elastic_mapping:"id:{type:keyword}"` - Name string `json:"name" elastic_mapping:"name:{type:keyword}"` + ApiPermission []string `json:"api_permission"` + //ID string `json:"id" elastic_mapping:"id:{type:keyword}"` + //Name string `json:"name" elastic_mapping:"name:{type:keyword}"` } type ElasticsearchPermission struct { Cluster []string `json:"cluster" elastic_mapping:"cluster:{type:object}"` diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index e0d6db45..a281a344 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -88,6 +88,9 @@ func (h Account) CurrentUser(w http.ResponseWriter, req *http.Request, ps httpro } func (h Account) Logout(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + h.WriteOKJSON(w, util.MapStr{ + "status": "ok", + }) } func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { reqUser, err := biz.FromUserContext(r.Context()) diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index b988105c..bbb2d2e1 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -23,15 +23,14 @@ func registerRouter() { api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.GetRole)) api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.DeleteRole)) api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.UpdateRole)) - api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.ListRole)) + api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.SearchRole)) api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.CreateUser)) api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.GetUser)) - api.HandleAPIMethod(api.GET, "/user/search", m.PermissionRequired(r.SearchUser, enum.ListUser)) api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.DeleteUser)) api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UpdateUser)) api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UpdateUser)) - api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.ListUser)) + api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.SearchUser)) } @@ -58,7 +57,8 @@ func loadJsonConfig() { } func loadRolePermission() { biz.RolePermission = make(map[string][]string) - biz.RolePermission["admin_user"] = []string{enum.GetUser} + biz.RolePermission["admin_user"] = enum.AdminUser + biz.RolePermission["admin"] = enum.Admin } func init() { registerRouter() diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 32a687f5..cda8dd91 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -3,6 +3,7 @@ package rbac import ( log "github.com/cihub/seelog" "infini.sh/console/internal/biz" + "infini.sh/console/internal/biz/enum" "infini.sh/console/internal/dto" httprouter "infini.sh/framework/core/api/router" "net/http" @@ -53,8 +54,15 @@ func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } + roles := make([]interface{}, 0) + for _, role := range enum.BuildRoles { + roles = append(roles, role) + } + for _, v := range res.Result { + roles = append(roles, v) + } - h.WriteOKJSON(w, Response{Hit: res.Result, Total: res.Total}) + h.WriteOKJSON(w, Response{Hit: roles, Total: res.Total + int64(len(enum.BuildRoles))}) return } From f6d4d9fda58cc7bb2fd1110da4f55c7df7d5aac8 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 20 Apr 2022 10:22:53 +0800 Subject: [PATCH 15/75] feat: (rbac) middleware handle error / password bcrypt hash / user update password --- internal/biz/account.go | 49 ++++++++++++++++++++------- internal/biz/enum/const.go | 2 +- internal/biz/permission.go | 63 +++++++++++++++++++---------------- internal/biz/role.go | 6 ++-- internal/biz/user.go | 8 ++++- internal/dto/user.go | 4 +++ internal/middleware/user.go | 21 ++++++++---- plugin/api/account/account.go | 23 +++++++++++++ 8 files changed, 124 insertions(+), 52 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index 5dd6f184..253516f3 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -3,12 +3,14 @@ package biz import ( "errors" "fmt" + "github.com/golang-jwt/jwt" + "golang.org/x/crypto/bcrypt" + "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" "infini.sh/framework/core/event" "infini.sh/framework/core/global" "infini.sh/framework/core/orm" "infini.sh/framework/core/util" - "src/github.com/golang-jwt/jwt" "strings" "time" ) @@ -26,11 +28,10 @@ type User struct { const Secret = "console" func authenticateUser(username string, password string) (user rbac.User, err error) { - q := orm.Query{Size: 1000} - q.Conds = orm.And(orm.Eq("username", username)) - err, result := orm.Search(rbac.User{}, &q) + err, result := orm.GetBy("username", username, rbac.User{}) if err != nil { + err = ErrNotFound return } if result.Total == 0 { @@ -38,10 +39,12 @@ func authenticateUser(username string, password string) (user rbac.User, err err return } user = result.Result[0].(rbac.User) - if util.MD5digest(password) != user.Password { - err = errors.New("password error") + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) + if err == bcrypt.ErrMismatchedHashAndPassword { + err = errors.New("password incorrect") return } + return } func authenticateAdmin(username string, password string) (user rbac.User, err error) { @@ -62,7 +65,7 @@ func authorize(user rbac.User) (m map[string]interface{}, err error) { User: &User{ Username: user.Username, UserId: user.ID, - Roles: []string{"admin"}, + Roles: []string{"admin_user"}, }, RegisteredClaims: &jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), @@ -76,7 +79,9 @@ func authorize(user rbac.User) (m map[string]interface{}, err error) { m = util.MapStr{ "access_token": tokenString, "username": user.Username, - "userid": user.ID, + "id": user.ID, + "expire_in": 86400, + "roles": []string{"admin_user"}, } return } @@ -115,7 +120,30 @@ func Login(username string, password string) (m map[string]interface{}, err erro }, nil, nil)) return } - +func UpdatePassword(localUser *User, req dto.UpdatePassword) (err error) { + user := rbac.User{} + user.ID = localUser.UserId + _, err = orm.Get(&user) + if err != nil { + err = ErrNotFound + return + } + err = bcrypt.CompareHashAndPassword([]byte(req.OldPassword), []byte(user.Password)) + if err == bcrypt.ErrMismatchedHashAndPassword { + err = errors.New("old password is not correct") + return + } + hash, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost) + if err != nil { + return + } + user.Password = string(hash) + err = orm.Save(&user) + if err != nil { + return + } + return +} func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { if authorizationHeader == "" { @@ -151,10 +179,7 @@ func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { func ValidatePermission(claims *UserClaims, permissions []string) (err error) { reqUser := claims.User - if err != nil { - return - } if reqUser.UserId == "" { err = errors.New("user id is empty") return diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 6c468feb..8c68288b 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -35,7 +35,7 @@ const InstanceProxy = "instance_proxy" var Admin = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} var AdminUser = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser} - +var AdminRole = []string{CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} var BuildRoles = []rbac.Role{ { ORMObjectBase: orm.ORMObjectBase{ diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 8ba25b40..48453648 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -1,6 +1,9 @@ package biz -import "fmt" +import ( + "fmt" + "infini.sh/console/internal/biz/enum" +) var ClusterApis = make([]string, 0) var EsApis = make(map[string][]string) @@ -38,33 +41,37 @@ type ConsolePermisson struct { } func (r ConsoleRole) ListPermission() interface{} { - list := []ConsolePermisson{ - { - Id: "cluster_overview", - Name: "平台概览", - }, - { - Id: "cluster_search", - Name: "平台搜索", - }, - { - Id: "cluster_elasticsearch", - Name: "集群监控", - }, - { - Id: "cluster_elasticsearch_refresh", - Name: "集群监控刷新", - }, - { - Id: "cluster_activities", - Name: "集群动态", - }, - { - Id: "cluster_activities_search", - Name: "集群动态搜索", - }, - } - return list + //list := []ConsolePermisson{ + // { + // Id: "cluster_overview", + // Name: "平台概览", + // }, + // { + // Id: "cluster_search", + // Name: "平台搜索", + // }, + // { + // Id: "cluster_elasticsearch", + // Name: "集群监控", + // }, + // { + // Id: "cluster_elasticsearch_refresh", + // Name: "集群监控刷新", + // }, + // { + // Id: "cluster_activities", + // Name: "集群动态", + // }, + // { + // Id: "cluster_activities_search", + // Name: "集群动态搜索", + // }, + // + //} + m := make(map[string]map[string][]string) + m["api"]["用户管理"] = enum.AdminUser + m["api"]["角色管理"] = enum.AdminRole + return m } func (r ElasticsearchRole) ListPermission() interface{} { list := ElasticsearchPermisson{ diff --git a/internal/biz/role.go b/internal/biz/role.go index f2464500..e723df34 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -5,13 +5,11 @@ import ( "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" "infini.sh/framework/core/event" - log "src/github.com/cihub/seelog" - + "infini.sh/framework/core/orm" "infini.sh/framework/core/util" + log "src/github.com/cihub/seelog" "strings" "time" - - "infini.sh/framework/core/orm" ) func CreateRole(localUser *User, req dto.CreateRole) (id string, err error) { diff --git a/internal/biz/user.go b/internal/biz/user.go index 283daa92..5c4c67c0 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -2,6 +2,7 @@ package biz import ( "fmt" + "golang.org/x/crypto/bcrypt" "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" "infini.sh/framework/core/event" @@ -73,10 +74,15 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) { Name: v.Name, }) } + hash, err := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost) + if err != nil { + + return + } user := rbac.User{ Name: req.Name, Username: req.Username, - Password: util.MD5digest(req.Password), + Password: string(hash), Email: req.Email, Phone: req.Phone, Roles: roles, diff --git a/internal/dto/user.go b/internal/dto/user.go index 55a7290f..67a98696 100644 --- a/internal/dto/user.go +++ b/internal/dto/user.go @@ -4,3 +4,7 @@ type Login struct { Username string `json:"username"` Password string `json:"password"` } +type UpdatePassword struct { + OldPassword string `json:"oldPassword"` + NewPassword string `json:"newPassword"` +} diff --git a/internal/middleware/user.go b/internal/middleware/user.go index d822adbc..9b41edf8 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -12,7 +12,7 @@ func LoginRequired(h httprouter.Handle) httprouter.Handle { claims, err := biz.ValidateLogin(r.Header.Get("Authorization")) if err != nil { - w = handleError(w, err) + w = handleError(w, http.StatusUnauthorized, err) return } r = r.WithContext(biz.NewUserContext(r.Context(), claims)) @@ -24,21 +24,30 @@ func PermissionRequired(h httprouter.Handle, permissions ...string) httprouter.H 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, err) + + w = handleError(w, http.StatusUnauthorized, err) + return } err = biz.ValidatePermission(claims, permissions) if err != nil { - w = handleError(w, err) + w = handleError(w, http.StatusForbidden, err) return } r = r.WithContext(biz.NewUserContext(r.Context(), claims)) h(w, r, ps) } } -func handleError(w http.ResponseWriter, err error) http.ResponseWriter { +func handleError(w http.ResponseWriter, statusCode int, err error) http.ResponseWriter { w.Header().Set("Content-type", util.ContentTypeJson) - w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte(`{"error":"` + err.Error() + `"}`)) + w.WriteHeader(statusCode) + json := util.ToJson(util.MapStr{ + "error": util.MapStr{ + "status": statusCode, + "reason": err.Error(), + }, + }, true) + w.Write([]byte(json)) + return w } diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index a281a344..f7de9fe5 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -22,6 +22,7 @@ func init() { api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout) api.HandleAPIMethod(api.GET, "/account/profile", m.LoginRequired(account.Profile)) + api.HandleAPIMethod(api.PUT, "/account/password", m.LoginRequired(account.UpdatePassword)) } const userInSession = "user_in_session" @@ -101,3 +102,25 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P h.WriteJSON(w, reqUser, 200) return } +func (h Account) UpdatePassword(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + reqUser, err := biz.FromUserContext(r.Context()) + if err != nil { + h.Error(w, err) + return + } + var req dto.UpdatePassword + err = h.DecodeJSON(r, &req) + if err != nil { + h.Error(w, err) + return + } + err = biz.UpdatePassword(reqUser, req) + if err != nil { + h.Error(w, err) + return + } + h.WriteOKJSON(w, util.MapStr{ + "status": "ok", + }) + +} From 16821ed736cb277c9e05a24275b70b1e0f8ded9c Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 20 Apr 2022 15:25:54 +0800 Subject: [PATCH 16/75] feat: (rbac) core response --- internal/biz/account.go | 29 +++++++++++++++++----- internal/biz/user.go | 4 ++-- internal/core/response.go | 45 +++++++++++++++++++++++++++++++++++ internal/dto/user.go | 4 ++-- plugin/api/account/account.go | 15 +++++++++++- plugin/api/rbac/init.go | 36 ---------------------------- plugin/api/rbac/permission.go | 3 ++- plugin/api/rbac/role.go | 11 +++++---- plugin/api/rbac/user.go | 17 ++++++------- 9 files changed, 103 insertions(+), 61 deletions(-) create mode 100644 internal/core/response.go diff --git a/internal/biz/account.go b/internal/biz/account.go index 253516f3..1ee4df90 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "github.com/golang-jwt/jwt" + "github.com/mitchellh/mapstructure" "golang.org/x/crypto/bcrypt" "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" @@ -11,6 +12,7 @@ import ( "infini.sh/framework/core/global" "infini.sh/framework/core/orm" "infini.sh/framework/core/util" + "strings" "time" ) @@ -24,10 +26,21 @@ type User struct { UserId string `json:"user_id"` Roles []string `json:"roles"` } +type Account struct { + ID string `json:"id,omitempty" ` + Created string `json:"created,omitempty" ` + Updated string `json:"updated,omitempty" ` + Username string `json:"username" elastic_mapping:"username:{type:keyword}"` + Password string `json:"password" elastic_mapping:"password:{type:text}"` + Name string `json:"name" elastic_mapping:"name:{type:keyword}"` + Phone string `json:"phone" elastic_mapping:"phone:{type:keyword}"` + Email string `json:"email" elastic_mapping:"email:{type:keyword}"` + Tags []string `json:"tags" elastic_mapping:"tags:{type:text}"` +} const Secret = "console" -func authenticateUser(username string, password string) (user rbac.User, err error) { +func authenticateUser(username string, password string) (user Account, err error) { err, result := orm.GetBy("username", username, rbac.User{}) if err != nil { @@ -38,7 +51,11 @@ func authenticateUser(username string, password string) (user rbac.User, err err err = errors.New("user not found") return } - user = result.Result[0].(rbac.User) + + err = mapstructure.Decode(result.Result[0], &user) + if err != nil { + return + } err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) if err == bcrypt.ErrMismatchedHashAndPassword { err = errors.New("password incorrect") @@ -47,7 +64,7 @@ func authenticateUser(username string, password string) (user rbac.User, err err return } -func authenticateAdmin(username string, password string) (user rbac.User, err error) { +func authenticateAdmin(username string, password string) (user Account, err error) { u, _ := global.Env().GetConfig("bootstrap.username", "admin") p, _ := global.Env().GetConfig("bootstrap.password", "admin") @@ -60,7 +77,7 @@ func authenticateAdmin(username string, password string) (user rbac.User, err er user.Username = username return user, nil } -func authorize(user rbac.User) (m map[string]interface{}, err error) { +func authorize(user Account) (m map[string]interface{}, err error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims{ User: &User{ Username: user.Username, @@ -86,7 +103,7 @@ func authorize(user rbac.User) (m map[string]interface{}, err error) { return } func Login(username string, password string) (m map[string]interface{}, err error) { - var user rbac.User + var user Account if username == "admin" { user, err = authenticateAdmin(username, password) if err != nil { @@ -128,7 +145,7 @@ func UpdatePassword(localUser *User, req dto.UpdatePassword) (err error) { err = ErrNotFound return } - err = bcrypt.CompareHashAndPassword([]byte(req.OldPassword), []byte(user.Password)) + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword)) if err == bcrypt.ErrMismatchedHashAndPassword { err = errors.New("old password is not correct") return diff --git a/internal/biz/user.go b/internal/biz/user.go index 5c4c67c0..66903c5f 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -135,7 +135,7 @@ func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { user.Phone = req.Phone user.Tags = req.Tags user.Updated = time.Now() - err = orm.Save(user) + err = orm.Save(&user) if err != nil { return } @@ -177,7 +177,7 @@ func UpdateUserRole(localUser *User, id string, req dto.UpdateUserRole) (err err } user.Roles = roles user.Updated = time.Now() - err = orm.Save(user) + err = orm.Save(&user) if err != nil { return } diff --git a/internal/core/response.go b/internal/core/response.go new file mode 100644 index 00000000..0804e91c --- /dev/null +++ b/internal/core/response.go @@ -0,0 +1,45 @@ +package core + +type Response struct { + Total int64 `json:"total,omitempty"` + Hit interface{} `json:"hit,omitempty"` + Id string `json:"_id,omitempty"` + Result string `json:"result,omitempty"` +} +type FoundResp struct { + Found bool `json:"found"` + Id string `json:"_id,omitempty"` + Source interface{} `json:"_source,omitempty"` +} + +func CreateResponse(id string) Response { + return Response{ + Id: id, + Result: "created", + } +} +func UpdateResponse(id string) Response { + return Response{ + Id: id, + Result: "updated", + } +} +func DeleteResponse(id string) Response { + return Response{ + Id: id, + Result: "deleted", + } +} +func NotFoundResponse(id string) FoundResp { + return FoundResp{ + Id: id, + Found: false, + } +} +func FoundResponse(id string, data interface{}) FoundResp { + return FoundResp{ + Id: id, + Found: true, + Source: data, + } +} diff --git a/internal/dto/user.go b/internal/dto/user.go index 67a98696..a9b4dde7 100644 --- a/internal/dto/user.go +++ b/internal/dto/user.go @@ -5,6 +5,6 @@ type Login struct { Password string `json:"password"` } type UpdatePassword struct { - OldPassword string `json:"oldPassword"` - NewPassword string `json:"newPassword"` + OldPassword string `json:"old_password"` + NewPassword string `json:"new_password"` } diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index f7de9fe5..c5203a99 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -2,6 +2,7 @@ package account import ( "infini.sh/console/internal/biz" + "infini.sh/console/internal/core" "infini.sh/console/internal/dto" m "infini.sh/console/internal/middleware" "infini.sh/framework/core/api" @@ -99,7 +100,19 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - h.WriteJSON(w, reqUser, 200) + user, err := biz.GetUser(reqUser.UserId) + if err != nil { + h.Error(w, err) + return + } + u := util.MapStr{ + "id": user.ID, + "username": user.Username, + "email": user.Email, + "phone": user.Phone, + "name": user.Name, + } + h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) return } func (h Account) UpdatePassword(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index bbb2d2e1..d9abb13b 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -65,39 +65,3 @@ func init() { loadJsonConfig() loadRolePermission() } - -type Response struct { - Total int64 `json:"total,omitempty"` - Hit interface{} `json:"hit,omitempty"` - Id string `json:"_id,omitempty"` - Result string `json:"result,omitempty"` -} -type NotFoundResp struct { - Found bool `json:"found"` - Id string `json:"_id,omitempty"` -} - -func CreateResponse(id string) Response { - return Response{ - Id: id, - Result: "created", - } -} -func UpdateResponse(id string) Response { - return Response{ - Id: id, - Result: "updated", - } -} -func DeleteResponse(id string) Response { - return Response{ - Id: id, - Result: "deleted", - } -} -func NotFoundResponse(id string) NotFoundResp { - return NotFoundResp{ - Id: id, - Found: false, - } -} diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index 1f480a53..a6ff6e7b 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -3,6 +3,7 @@ package rbac import ( log "github.com/cihub/seelog" "infini.sh/console/internal/biz" + "infini.sh/console/internal/core" httprouter "infini.sh/framework/core/api/router" "net/http" @@ -18,7 +19,7 @@ func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprout return } permissions := role.ListPermission() - h.WriteOKJSON(w, Response{ + h.WriteOKJSON(w, core.Response{ Hit: permissions, }) return diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index cda8dd91..8e996f6c 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -4,6 +4,7 @@ import ( log "github.com/cihub/seelog" "infini.sh/console/internal/biz" "infini.sh/console/internal/biz/enum" + "infini.sh/console/internal/core" "infini.sh/console/internal/dto" httprouter "infini.sh/framework/core/api/router" "net/http" @@ -35,7 +36,7 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P return } - _ = h.WriteOKJSON(w, CreateResponse(id)) + _ = h.WriteOKJSON(w, core.CreateResponse(id)) return } @@ -62,7 +63,7 @@ func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.P roles = append(roles, v) } - h.WriteOKJSON(w, Response{Hit: roles, Total: res.Total + int64(len(enum.BuildRoles))}) + h.WriteOKJSON(w, core.Response{Hit: roles, Total: res.Total + int64(len(enum.BuildRoles))}) return } @@ -76,7 +77,7 @@ func (h Rbac) GetRole(w http.ResponseWriter, r *http.Request, ps httprouter.Para h.Error(w, err) return } - h.WriteOKJSON(w, Response{Hit: role}) + h.WriteOKJSON(w, core.Response{Hit: role}) return } @@ -96,7 +97,7 @@ func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - _ = h.WriteOKJSON(w, DeleteResponse(id)) + _ = h.WriteOKJSON(w, core.DeleteResponse(id)) return } @@ -122,6 +123,6 @@ func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - _ = h.WriteOKJSON(w, UpdateResponse(id)) + _ = h.WriteOKJSON(w, core.UpdateResponse(id)) return } diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index d86a16ff..5b8c1de2 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -3,6 +3,7 @@ package rbac import ( "errors" "infini.sh/console/internal/biz" + "infini.sh/console/internal/core" "infini.sh/console/internal/dto" httprouter "infini.sh/framework/core/api/router" "infini.sh/framework/modules/elastic" @@ -39,7 +40,7 @@ func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - _ = h.WriteOKJSON(w, CreateResponse(id)) + _ = h.WriteOKJSON(w, core.CreateResponse(id)) return } @@ -48,7 +49,7 @@ func (h Rbac) GetUser(w http.ResponseWriter, r *http.Request, ps httprouter.Para id := ps.MustGetParameter("id") user, err := biz.GetUser(id) if errors.Is(err, elastic.ErrNotFound) { - h.WriteJSON(w, NotFoundResponse(id), http.StatusNotFound) + h.WriteJSON(w, core.NotFoundResponse(id), http.StatusNotFound) return } @@ -57,7 +58,7 @@ func (h Rbac) GetUser(w http.ResponseWriter, r *http.Request, ps httprouter.Para h.Error(w, err) return } - h.WriteOKJSON(w, Response{Hit: user}) + h.WriteOKJSON(w, core.FoundResponse(id, user)) return } @@ -83,7 +84,7 @@ func (h Rbac) UpdateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - _ = h.WriteOKJSON(w, UpdateResponse(id)) + _ = h.WriteOKJSON(w, core.UpdateResponse(id)) return } @@ -109,7 +110,7 @@ func (h Rbac) UpdateUserRole(w http.ResponseWriter, r *http.Request, ps httprout h.Error(w, err) return } - _ = h.WriteOKJSON(w, UpdateResponse(id)) + _ = h.WriteOKJSON(w, core.UpdateResponse(id)) return } @@ -123,7 +124,7 @@ func (h Rbac) DeleteUser(w http.ResponseWriter, r *http.Request, ps httprouter.P } err = biz.DeleteUser(localUser, id) if errors.Is(err, elastic.ErrNotFound) { - h.WriteJSON(w, NotFoundResponse(id), http.StatusNotFound) + h.WriteJSON(w, core.NotFoundResponse(id), http.StatusNotFound) return } if err != nil { @@ -131,7 +132,7 @@ func (h Rbac) DeleteUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - _ = h.WriteOKJSON(w, DeleteResponse(id)) + _ = h.WriteOKJSON(w, core.DeleteResponse(id)) return } @@ -149,7 +150,7 @@ func (h Rbac) SearchUser(w http.ResponseWriter, r *http.Request, ps httprouter.P return } - h.WriteOKJSON(w, Response{Hit: res.Result, Total: res.Total}) + h.WriteOKJSON(w, core.Response{Hit: res.Result, Total: res.Total}) return } From cbef25d4cebe5f99d4aa9ff25fff3d7f7fcebe06 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 20 Apr 2022 15:50:49 +0800 Subject: [PATCH 17/75] feat: (rbac) set all user admin role for test --- internal/biz/account.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index 1ee4df90..34440f58 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -82,7 +82,7 @@ func authorize(user Account) (m map[string]interface{}, err error) { User: &User{ Username: user.Username, UserId: user.ID, - Roles: []string{"admin_user"}, + Roles: []string{"admin"}, }, RegisteredClaims: &jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), @@ -98,7 +98,7 @@ func authorize(user Account) (m map[string]interface{}, err error) { "username": user.Username, "id": user.ID, "expire_in": 86400, - "roles": []string{"admin_user"}, + "roles": []string{"admin"}, } return } From e25fc8da10d80edf2eedf7c31d88054a24a613fc Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 20 Apr 2022 16:19:22 +0800 Subject: [PATCH 18/75] feat: (rbac) login response --- plugin/api/account/account.go | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index c5203a99..6cd6f679 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -42,6 +42,7 @@ func (h Account) Login(w http.ResponseWriter, r *http.Request, ps httprouter.Par h.Error(w, err) return } + data["status"] = "ok" h.WriteOKJSON(w, data) } From b8b97652929a472046163ba984a6da0a039268c0 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 20 Apr 2022 16:31:56 +0800 Subject: [PATCH 19/75] feat: (rbac) user session --- plugin/api/account/account.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index 6cd6f679..52f41b5e 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -43,6 +43,8 @@ func (h Account) Login(w http.ResponseWriter, r *http.Request, ps httprouter.Par return } data["status"] = "ok" + + api.SetSession(w, r, userInSession, req.Username) h.WriteOKJSON(w, data) } From abad11e3bfafbdbf25be4b606f3815445fe6af70 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 20 Apr 2022 17:36:45 +0800 Subject: [PATCH 20/75] feat: (rbac) builtin role --- internal/biz/enum/const.go | 76 ++++++++++++++++++++++------------- internal/biz/role.go | 1 + plugin/api/account/account.go | 6 +-- plugin/api/rbac/role.go | 25 ++++++++---- 4 files changed, 69 insertions(+), 39 deletions(-) diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 8c68288b..7f755ad8 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -1,9 +1,6 @@ package enum -import ( - "infini.sh/console/model/rbac" - "infini.sh/framework/core/orm" -) +import "time" const CreateUser = "create_user" const UpdateUser = "update_user" @@ -36,29 +33,50 @@ const InstanceProxy = "instance_proxy" var Admin = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} var AdminUser = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser} var AdminRole = []string{CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} -var BuildRoles = []rbac.Role{ - { - ORMObjectBase: orm.ORMObjectBase{ - ID: "admin", - }, - Name: "admin", - Description: "管理员", - RoleType: "console", - Permission: rbac.ConsolePermission{ - ApiPermission: Admin, - }, - BuiltIn: true, - }, - { - ORMObjectBase: orm.ORMObjectBase{ - ID: "admin_user", - }, - Name: "admin_user", - Description: "用户模块管理员", - RoleType: "console", - Permission: rbac.ConsolePermission{ - ApiPermission: AdminUser, - }, - BuiltIn: true, - }, +var BuildRoles = make(map[string]map[string]interface{}, 0) + +func init() { + BuildRoles["admin"] = map[string]interface{}{ + "id": "admin", + "name": "admin", + "permission": AdminUser, + "builtin": true, + "description": "is admin", + "created": time.Now(), + } } + +// BuildRoles["admin"] = { +// "id":"admin", +// "name":"admin", +//} +//{ +// "name":"admin", +// "id":"admin", +// +//},{ +// +//} +// { +// "name": "admin", +// Name: "admin", +// Description: "管理员", +// RoleType: "console", +// Permission: rbac.ConsolePermission{ +// ApiPermission: Admin, +// }, +// BuiltIn: true, +// }, +// { +// ORMObjectBase: orm.ORMObjectBase{ +// ID: "admin_user", +// }, +// Name: "admin_user", +// Description: "用户模块管理员", +// RoleType: "console", +// Permission: rbac.ConsolePermission{ +// ApiPermission: AdminUser, +// }, +// BuiltIn: true, +// }, +//} diff --git a/internal/biz/role.go b/internal/biz/role.go index e723df34..9716136b 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -147,6 +147,7 @@ func GetRole(id string) (role rbac.Role, err error) { return } func SearchRole(keyword string, from, size int) (roles orm.Result, err error) { + query := orm.Query{} queryDSL := `{"query":{"bool":{"must":[%s]}}, "from": %d,"size": %d}` diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index 52f41b5e..9e14a402 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -19,14 +19,14 @@ func init() { account := Account{} api.HandleAPIMethod(api.POST, "/account/login", account.Login) - //api.HandleAPIMethod(api.GET, "/account/current_user", account.CurrentUser) + api.HandleAPIMethod(api.GET, "/account/current_user", account.CurrentUser) api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout) api.HandleAPIMethod(api.GET, "/account/profile", m.LoginRequired(account.Profile)) api.HandleAPIMethod(api.PUT, "/account/password", m.LoginRequired(account.UpdatePassword)) } -const userInSession = "user_in_session" +const userInSession = "user_session:" func (h Account) Login(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { @@ -44,7 +44,7 @@ func (h Account) Login(w http.ResponseWriter, r *http.Request, ps httprouter.Par } data["status"] = "ok" - api.SetSession(w, r, userInSession, req.Username) + //api.SetSession(w, r, userInSession+req.Username, req.Username) h.WriteOKJSON(w, data) } diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 8e996f6c..3bc0fac1 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -7,6 +7,8 @@ import ( "infini.sh/console/internal/core" "infini.sh/console/internal/dto" httprouter "infini.sh/framework/core/api/router" + "infini.sh/framework/core/elastic" + "infini.sh/framework/core/util" "net/http" ) @@ -55,15 +57,24 @@ func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - roles := make([]interface{}, 0) - for _, role := range enum.BuildRoles { - roles = append(roles, role) - } - for _, v := range res.Result { - roles = append(roles, v) + response := elastic.SearchResponse{} + util.FromJSONBytes(res.Raw, &response) + + list := response.Hits.Hits + var index string + for _, v := range list { + index = v.Index } - h.WriteOKJSON(w, core.Response{Hit: roles, Total: res.Total + int64(len(enum.BuildRoles))}) + list = append(list, elastic.IndexDocument{ + ID: "admin", + Index: index, + Type: "_doc", + Source: enum.BuildRoles["admin"], + }) + response.Hits.Hits = list + + h.WriteOKJSON(w, response) return } From 454319b8d49eea23e2f0f370051678a203dfd9d1 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 20 Apr 2022 17:54:09 +0800 Subject: [PATCH 21/75] feat: (rbac) user role mapping --- model/rbac/user.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/model/rbac/user.go b/model/rbac/user.go index d9ebcf32..266379a9 100644 --- a/model/rbac/user.go +++ b/model/rbac/user.go @@ -13,6 +13,6 @@ type User struct { Tags []string `json:"tags" elastic_mapping:"tags:{type:text}"` } type UserRole struct { - Id string `json:"id"` - Name string `json:"name"` + Id string `json:"id" elastic_mapping:"id:{type:keyword}"` + Name string `json:"name" elastic_mapping:"name:{type:keyword}" ` } From 1658b029260dc2a16f8cddc675c074dc71a34a0b Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 20 Apr 2022 18:20:29 +0800 Subject: [PATCH 22/75] fix tags mapping --- model/rbac/user.go | 4 ++-- plugin/api/rbac/user.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/model/rbac/user.go b/model/rbac/user.go index 266379a9..1cd131b3 100644 --- a/model/rbac/user.go +++ b/model/rbac/user.go @@ -9,8 +9,8 @@ type User struct { Name string `json:"name" elastic_mapping:"name:{type:keyword}"` Phone string `json:"phone" elastic_mapping:"phone:{type:keyword}"` Email string `json:"email" elastic_mapping:"email:{type:keyword}"` - Roles []UserRole `json:"roles" elastic_mapping:"roles:{type:text}"` - Tags []string `json:"tags" elastic_mapping:"tags:{type:text}"` + Roles []UserRole `json:"roles"` + Tags []string `json:"tags,omitempty" elastic_mapping:"tags:{type:text}"` } type UserRole struct { Id string `json:"id" elastic_mapping:"id:{type:keyword}"` diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index 5b8c1de2..d9bff0de 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -150,7 +150,7 @@ func (h Rbac) SearchUser(w http.ResponseWriter, r *http.Request, ps httprouter.P return } - h.WriteOKJSON(w, core.Response{Hit: res.Result, Total: res.Total}) + h.WriteOKJSON(w, res) return } From d62067f8026e13372f812938d4d1b498452eb260 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 20 Apr 2022 18:28:24 +0800 Subject: [PATCH 23/75] feat: (rbac) user search --- plugin/api/rbac/user.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index d9bff0de..662ded0a 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -150,7 +150,7 @@ func (h Rbac) SearchUser(w http.ResponseWriter, r *http.Request, ps httprouter.P return } - h.WriteOKJSON(w, res) + h.Write(w, res.Raw) return } From 42ca7cac2573460c4d94543f312209cf36b02f2f Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 20 Apr 2022 18:49:14 +0800 Subject: [PATCH 24/75] feat: (rbac) user profile --- plugin/api/account/account.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index 9e14a402..e7a03a12 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -103,17 +103,18 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - user, err := biz.GetUser(reqUser.UserId) - if err != nil { - h.Error(w, err) - return - } + //user, err := biz.GetUser(reqUser.UserId) + //if err != nil { + // h.Error(w, err) + // return + //} + //TODO get user from es u := util.MapStr{ - "id": user.ID, - "username": user.Username, - "email": user.Email, - "phone": user.Phone, - "name": user.Name, + "user_id": reqUser.UserId, + "username": reqUser.Username, + "email": "hello@infini.ltd", + + "name": "admin", } h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) return From 66b9995b076b44d9cd29395edb6c993d131c253f Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 21 Apr 2022 10:13:49 +0800 Subject: [PATCH 25/75] fix: (rbac) create user password require --- internal/biz/user.go | 2 +- plugin/api/rbac/role.go | 2 +- plugin/api/rbac/user.go | 11 ++++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/internal/biz/user.go b/internal/biz/user.go index 66903c5f..45c43a1a 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -74,7 +74,7 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) { Name: v.Name, }) } - hash, err := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost) + hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) if err != nil { return diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 3bc0fac1..c9c2d65e 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -19,7 +19,7 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P var req dto.CreateRole err = h.DecodeJSON(r, &req) if err != nil { - h.Error(w, err) + h.Error400(w, err.Error()) return } req.RoleType = roleType diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index 662ded0a..9bdb7f18 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -25,7 +25,12 @@ func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P var req dto.CreateUser err := h.DecodeJSON(r, &req) if err != nil { - h.Error(w, err) + h.Error400(w, err.Error()) + return + } + if req.Username == "" || req.Password == "" { + + h.Error400(w, "username or password require") return } localUser, err := biz.FromUserContext(r.Context()) @@ -68,7 +73,7 @@ func (h Rbac) UpdateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P err := h.DecodeJSON(r, &req) if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.Error400(w, err.Error()) return } localUser, err := biz.FromUserContext(r.Context()) @@ -94,7 +99,7 @@ func (h Rbac) UpdateUserRole(w http.ResponseWriter, r *http.Request, ps httprout err := h.DecodeJSON(r, &req) if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.Error400(w, err.Error()) return } localUser, err := biz.FromUserContext(r.Context()) From 5d8a92a33614dd1d327f57a93df11be5d1deb380 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 21 Apr 2022 10:33:28 +0800 Subject: [PATCH 26/75] feat: (rbac) role search total --- plugin/api/rbac/role.go | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index c9c2d65e..86029c6c 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -73,6 +73,7 @@ func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.P Source: enum.BuildRoles["admin"], }) response.Hits.Hits = list + response.Hits.Total = response.GetTotal() + 1 h.WriteOKJSON(w, response) return From 2593a5a065d572ee9f4fc2c68a13fafa7a1b33ff Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 21 Apr 2022 11:30:12 +0800 Subject: [PATCH 27/75] fix: (rbac) permission list --- internal/biz/enum/const.go | 1 + internal/biz/permission.go | 58 +++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 7f755ad8..5450be8f 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -30,6 +30,7 @@ const GetInstanceStatus = "get_instance_status" const ConnectInstance = "connect_instance" const InstanceProxy = "instance_proxy" +var All = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} var Admin = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} var AdminUser = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser} var AdminRole = []string{CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 48453648..dd4f5a59 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -36,24 +36,18 @@ func NewRole(typ string) (r IRole, err error) { } type ConsolePermisson struct { - Id string `json:"id"` - Name string `json:"name"` + Api []string `json:"api"` + Menu []Menu `json:"menu"` +} +type Menu struct { + Id string `json:"id"` + Name string `json:"name"` + Switch []string `json:"switch,omitempty"` + Children []Menu `json:"children,omitempty"` } func (r ConsoleRole) ListPermission() interface{} { - //list := []ConsolePermisson{ - // { - // Id: "cluster_overview", - // Name: "平台概览", - // }, - // { - // Id: "cluster_search", - // Name: "平台搜索", - // }, - // { - // Id: "cluster_elasticsearch", - // Name: "集群监控", - // }, + // { // Id: "cluster_elasticsearch_refresh", // Name: "集群监控刷新", @@ -68,10 +62,36 @@ func (r ConsoleRole) ListPermission() interface{} { // }, // //} - m := make(map[string]map[string][]string) - m["api"]["用户管理"] = enum.AdminUser - m["api"]["角色管理"] = enum.AdminRole - return m + menu := []Menu{ + { + Id: "cluster", + Name: "平台管理", + Children: []Menu{ + { + Id: "cluster_overview", + Name: "平台概览", + Switch: []string{"none", "write", "read"}, + }, + { + + Id: "cluster_elasticsearch", + Name: "集群监控", + Switch: []string{"none", "write", "read"}, + }, { + + Id: "cluster_activities", + Name: "集群动态", + Switch: []string{"none", "write", "read"}, + }, + }, + }, + } + p := ConsolePermisson{ + Api: enum.All, + Menu: menu, + } + + return p } func (r ElasticsearchRole) ListPermission() interface{} { list := ElasticsearchPermisson{ From bfc314d01db50337aa5148279602697977666a9b Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 21 Apr 2022 14:12:57 +0800 Subject: [PATCH 28/75] fix: (rbac) role permission --- internal/biz/enum/const.go | 8 +++++--- internal/dto/role.go | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 5450be8f..2bd2aa94 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -30,17 +30,19 @@ const GetInstanceStatus = "get_instance_status" const ConnectInstance = "connect_instance" const InstanceProxy = "instance_proxy" -var All = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} +var All = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, + SearchRole, ListPermission, CreateRule, UpdateRule, DeleteRule, GetRule, SearchRule, CreateInstance, UpdateInstance, DeleteInstance, + GetInstance, SearchInstance, GetInstanceStatus, ConnectInstance, InstanceProxy} + var Admin = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} var AdminUser = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser} -var AdminRole = []string{CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} var BuildRoles = make(map[string]map[string]interface{}, 0) func init() { BuildRoles["admin"] = map[string]interface{}{ "id": "admin", "name": "admin", - "permission": AdminUser, + "permission": Admin, "builtin": true, "description": "is admin", "created": time.Now(), diff --git a/internal/dto/role.go b/internal/dto/role.go index a919e4e4..fb56ebb1 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -1,10 +1,19 @@ package dto type CreateRole struct { - Name string `json:"name"` - Description string `json:"description" ` - RoleType string `json:"type" ` - Permission interface{} `json:"permission"` + Name string `json:"name"` + Description string `json:"description" ` + RoleType string `json:"type" ` + Permission RolePermission `json:"permission"` +} +type RolePermission struct { + Api []string `json:"api"` + Menu []Menu `json:"menu"` +} +type Menu struct { + Id string `json:"id"` + Name string `json:"name"` + Switch string `json:"switch"` } type UpdateRole struct { Description string `json:"description" ` From 8d730834ddc2ff5b82409b20b04e0b4f66b5065d Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 21 Apr 2022 15:38:57 +0800 Subject: [PATCH 29/75] fix: (rbac) create console role and es role --- internal/biz/role.go | 56 +++++++++++++++++++++++++++++++++++++++-- internal/dto/role.go | 14 ++++++++--- model/rbac/role.go | 37 ++++++--------------------- plugin/api/rbac/init.go | 25 ++++++++++++++++-- plugin/api/rbac/role.go | 37 ++++++++++++++++----------- 5 files changed, 118 insertions(+), 51 deletions(-) diff --git a/internal/biz/role.go b/internal/biz/role.go index 9716136b..a788bf87 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -12,7 +12,59 @@ import ( "time" ) -func CreateRole(localUser *User, req dto.CreateRole) (id string, err error) { +func CreateEsRole(localUser *User, req dto.CreateEsRole) (id string, err error) { + q := orm.Query{Size: 1000} + q.Conds = orm.And(orm.Eq("name", req.Name)) + + err, result := orm.Search(rbac.Role{}, &q) + if err != nil { + return + } + if result.Total > 0 { + err = fmt.Errorf("role name %s already exists", req.Name) + return + } + + role := &rbac.Role{ + Name: req.Name, + Description: req.Description, + RoleType: req.RoleType, + Permission: req.Permission, + } + role.ID = util.GetUUID() + role.Created = time.Now() + role.Updated = time.Now() + err = orm.Save(role) + if err != nil { + return + } + id = role.ID + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "role", + Type: "create", + Labels: util.MapStr{ + "id": id, + "name": req.Name, + "description": req.Description, + "permission": req.Permission, + "type": req.RoleType, + "created": role.Created.Format("2006-01-02 15:04:05"), + "updated": role.Updated.Format("2006-01-02 15:04:05"), + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, nil, nil)) + + if err != nil { + log.Error(err) + } + return +} +func CreateRole(localUser *User, req dto.CreateConsoleRole) (id string, err error) { q := orm.Query{Size: 1000} q.Conds = orm.And(orm.Eq("name", req.Name)) @@ -102,7 +154,7 @@ func DeleteRole(localUser *User, id string) (err error) { return } -func UpdateRole(localUser *User, id string, req dto.UpdateRole) (err error) { +func UpdateRole(localUser *User, id string, req dto.UpdateConsoleRole) (err error) { role := rbac.Role{} role.ID = id _, err = orm.Get(&role) diff --git a/internal/dto/role.go b/internal/dto/role.go index fb56ebb1..ca5e65e3 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -1,6 +1,6 @@ package dto -type CreateRole struct { +type CreateConsoleRole struct { Name string `json:"name"` Description string `json:"description" ` RoleType string `json:"type" ` @@ -15,9 +15,15 @@ type Menu struct { Name string `json:"name"` Switch string `json:"switch"` } -type UpdateRole struct { - Description string `json:"description" ` - Permission interface{} `json:"permission"` +type UpdateConsoleRole struct { + Description string `json:"description" ` + Permission RolePermission `json:"permission"` +} +type CreateEsRole struct { + Name string `json:"name"` + Description string `json:"description" ` + RoleType string `json:"type" ` + Permission ElasticsearchPermission `json:"permission"` } type ElasticsearchPermission struct { Cluster []string `json:"cluster" ` diff --git a/model/rbac/role.go b/model/rbac/role.go index 07331e6c..b36ec54f 100644 --- a/model/rbac/role.go +++ b/model/rbac/role.go @@ -2,7 +2,6 @@ package rbac import ( "infini.sh/framework/core/orm" - "time" ) type Role struct { @@ -14,9 +13,14 @@ type Role struct { BuiltIn bool `json:"builtin" elastic_mapping:"builtin:{type:boolean}"` //是否内置 } type ConsolePermission struct { - ApiPermission []string `json:"api_permission"` - //ID string `json:"id" elastic_mapping:"id:{type:keyword}"` - //Name string `json:"name" elastic_mapping:"name:{type:keyword}"` + Api []string `json:"api"` + Menu []Menu `json:"menu"` +} + +type Menu struct { + Id string `json:"id"` + Name string `json:"name"` + Switch string `json:"switch"` } type ElasticsearchPermission struct { Cluster []string `json:"cluster" elastic_mapping:"cluster:{type:object}"` @@ -24,28 +28,3 @@ type ElasticsearchPermission struct { ClusterPrivilege []string `json:"cluster_privilege" elastic_mapping:"cluster_privilege:{type:object}"` IndexPrivilege []string `json:"index_privilege" elastic_mapping:"index_privilege:{type:object}"` } - -type ConsoleOperate struct { - UserId string `json:"user_id" elastic_mapping:"user_id:{type:keyword}"` -} -type Operation struct { - Id string `json:"id"` - Timestamp time.Time `json:"timestamp"` - Metadata struct { - Labels struct { - Userid string `json:"userid"` - Username string `json:"username"` - } `json:"labels"` - Category string `json:"category"` - Group string `json:"group"` - Name string `json:"name"` - Type string `json:"type"` - } `json:"metadata"` - Changelog []struct { - From string `json:"from"` - Path []string `json:"path"` - To string `json:"to"` - Type string `json:"type"` - } `json:"changelog"` - Payload interface{} `json:"payload"` -} diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index d9abb13b..348d0760 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -5,7 +5,6 @@ import ( "infini.sh/console/internal/biz" "infini.sh/console/internal/biz/enum" m "infini.sh/console/internal/middleware" - "infini.sh/framework/core/api" "infini.sh/framework/core/util" "os" @@ -57,11 +56,33 @@ func loadJsonConfig() { } func loadRolePermission() { biz.RolePermission = make(map[string][]string) - biz.RolePermission["admin_user"] = enum.AdminUser + biz.RolePermission["admin"] = enum.Admin } func init() { registerRouter() loadJsonConfig() loadRolePermission() + +} +func existInternalUser() { + //user, err := biz.GetUser("admin") + //if errors.Is(err, elastic.ErrNotFound) { + // user.ID = "admin" + // user.Username = "admin" + // hash, _ := bcrypt.GenerateFromPassword([]byte("admin"), bcrypt.DefaultCost) + // + // user.Password = string(hash) + // user.Email = "" + // user.Phone = "" + // user.Name = "" + // + // + // user.Created = time.Now() + // user.Updated = time.Now() + // + //} +} +func existInternalRole() { + } diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 86029c6c..50421b69 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -14,30 +14,39 @@ import ( func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { roleType := ps.MustGetParameter("type") - var err error - - var req dto.CreateRole - err = h.DecodeJSON(r, &req) - if err != nil { - h.Error400(w, err.Error()) - return - } - req.RoleType = roleType - - var id string localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) h.Error(w, err) return } - id, err = biz.CreateRole(localUser, req) + var id string + switch roleType { + case biz.Console: + var req dto.CreateConsoleRole + err = h.DecodeJSON(r, &req) + if err != nil { + h.Error400(w, err.Error()) + return + } + req.RoleType = roleType + id, err = biz.CreateRole(localUser, req) + case biz.Elastisearch: + var req dto.CreateEsRole + err = h.DecodeJSON(r, &req) + if err != nil { + h.Error400(w, err.Error()) + return + } + req.RoleType = roleType + id, err = biz.CreateEsRole(localUser, req) + } + if err != nil { _ = log.Error(err.Error()) h.Error(w, err) return } - _ = h.WriteOKJSON(w, core.CreateResponse(id)) return @@ -116,7 +125,7 @@ func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.P func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") - var req dto.UpdateRole + var req dto.UpdateConsoleRole err := h.DecodeJSON(r, &req) if err != nil { h.Error(w, err) From 2e939cee70409849342947aa54ee1adaf353ef04 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 21 Apr 2022 15:44:22 +0800 Subject: [PATCH 30/75] fix: (rbac) menu permission --- internal/biz/permission.go | 26 +++++++++++++------------- model/rbac/role.go | 6 +++--- plugin/api/rbac/permission.go | 6 +----- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/internal/biz/permission.go b/internal/biz/permission.go index dd4f5a59..c954a2f6 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -40,10 +40,10 @@ type ConsolePermisson struct { Menu []Menu `json:"menu"` } type Menu struct { - Id string `json:"id"` - Name string `json:"name"` - Switch []string `json:"switch,omitempty"` - Children []Menu `json:"children,omitempty"` + Id string `json:"id"` + Name string `json:"name"` + Permission []string `json:"permission,omitempty"` + Children []Menu `json:"children,omitempty"` } func (r ConsoleRole) ListPermission() interface{} { @@ -68,20 +68,20 @@ func (r ConsoleRole) ListPermission() interface{} { Name: "平台管理", Children: []Menu{ { - Id: "cluster_overview", - Name: "平台概览", - Switch: []string{"none", "write", "read"}, + Id: "cluster_overview", + Name: "平台概览", + Permission: []string{"none", "write", "read"}, }, { - Id: "cluster_elasticsearch", - Name: "集群监控", - Switch: []string{"none", "write", "read"}, + Id: "cluster_elasticsearch", + Name: "集群监控", + Permission: []string{"none", "write", "read"}, }, { - Id: "cluster_activities", - Name: "集群动态", - Switch: []string{"none", "write", "read"}, + Id: "cluster_activities", + Name: "集群动态", + Permission: []string{"none", "write", "read"}, }, }, }, diff --git a/model/rbac/role.go b/model/rbac/role.go index b36ec54f..dea4bdf0 100644 --- a/model/rbac/role.go +++ b/model/rbac/role.go @@ -18,9 +18,9 @@ type ConsolePermission struct { } type Menu struct { - Id string `json:"id"` - Name string `json:"name"` - Switch string `json:"switch"` + Id string `json:"id"` + Name string `json:"name"` + Permission string `json:"permission"` } type ElasticsearchPermission struct { Cluster []string `json:"cluster" elastic_mapping:"cluster:{type:object}"` diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index a6ff6e7b..138c2bc7 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -3,8 +3,6 @@ package rbac import ( log "github.com/cihub/seelog" "infini.sh/console/internal/biz" - "infini.sh/console/internal/core" - httprouter "infini.sh/framework/core/api/router" "net/http" ) @@ -19,8 +17,6 @@ func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprout return } permissions := role.ListPermission() - h.WriteOKJSON(w, core.Response{ - Hit: permissions, - }) + h.WriteOKJSON(w, permissions) return } From 9a6c9489f96697d64e8dafb018db881733aba39e Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 21 Apr 2022 15:52:26 +0800 Subject: [PATCH 31/75] fix: (rbac) permission Privilege --- internal/biz/permission.go | 26 +++++++++++++------------- internal/dto/role.go | 6 +++--- model/rbac/role.go | 6 +++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/internal/biz/permission.go b/internal/biz/permission.go index c954a2f6..d3b1c24f 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -40,10 +40,10 @@ type ConsolePermisson struct { Menu []Menu `json:"menu"` } type Menu struct { - Id string `json:"id"` - Name string `json:"name"` - Permission []string `json:"permission,omitempty"` - Children []Menu `json:"children,omitempty"` + Id string `json:"id"` + Name string `json:"name"` + Privilege []string `json:"privilege,omitempty"` + Children []Menu `json:"children,omitempty"` } func (r ConsoleRole) ListPermission() interface{} { @@ -68,20 +68,20 @@ func (r ConsoleRole) ListPermission() interface{} { Name: "平台管理", Children: []Menu{ { - Id: "cluster_overview", - Name: "平台概览", - Permission: []string{"none", "write", "read"}, + Id: "cluster_overview", + Name: "平台概览", + Privilege: []string{"none", "write", "read"}, }, { - Id: "cluster_elasticsearch", - Name: "集群监控", - Permission: []string{"none", "write", "read"}, + Id: "cluster_elasticsearch", + Name: "集群监控", + Privilege: []string{"none", "write", "read"}, }, { - Id: "cluster_activities", - Name: "集群动态", - Permission: []string{"none", "write", "read"}, + Id: "cluster_activities", + Name: "集群动态", + Privilege: []string{"none", "write", "read"}, }, }, }, diff --git a/internal/dto/role.go b/internal/dto/role.go index ca5e65e3..9384db71 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -11,9 +11,9 @@ type RolePermission struct { Menu []Menu `json:"menu"` } type Menu struct { - Id string `json:"id"` - Name string `json:"name"` - Switch string `json:"switch"` + Id string `json:"id"` + Name string `json:"name"` + Privilege string `json:"privilege"` } type UpdateConsoleRole struct { Description string `json:"description" ` diff --git a/model/rbac/role.go b/model/rbac/role.go index dea4bdf0..1e5f2612 100644 --- a/model/rbac/role.go +++ b/model/rbac/role.go @@ -18,9 +18,9 @@ type ConsolePermission struct { } type Menu struct { - Id string `json:"id"` - Name string `json:"name"` - Permission string `json:"permission"` + Id string `json:"id"` + Name string `json:"name"` + Privilege string `json:"privilege"` } type ElasticsearchPermission struct { Cluster []string `json:"cluster" elastic_mapping:"cluster:{type:object}"` From 882eea91a5f5b6d9a32d1774c5b1cdb8d181d0f9 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 21 Apr 2022 17:11:26 +0800 Subject: [PATCH 32/75] fix: (rbac) es apis --- internal/biz/permission.go | 52 ++++++++++++++++++++--------------- internal/biz/role.go | 7 +++++ plugin/api/rbac/init.go | 13 ++++----- plugin/api/rbac/permission.go | 6 ++++ plugin/api/rbac/role.go | 5 ++++ 5 files changed, 53 insertions(+), 30 deletions(-) diff --git a/internal/biz/permission.go b/internal/biz/permission.go index d3b1c24f..762df697 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -5,7 +5,8 @@ import ( "infini.sh/console/internal/biz/enum" ) -var ClusterApis = make([]string, 0) +var ClusterApis = make(map[string][]string) +var IndexApis = make([]string, 0) var EsApis = make(map[string][]string) var RolePermission = make(map[string][]string) @@ -18,8 +19,24 @@ const ( type IRole interface { ListPermission() interface{} + + Create(localUser *User) (id string, err error) +} +type ConsoleRole struct { + Name string `json:"name"` + Description string `json:"description" ` + RoleType string `json:"type" ` + Permission Permission `json:"permission"` +} +type Permission struct { + Api []string `json:"api"` + Menu []MenuPermission `json:"menu"` +} +type MenuPermission struct { + Id string `json:"id"` + Name string `json:"name"` + Privilege string `json:"privilege"` } -type ConsoleRole struct{} type ElasticsearchRole struct{} func NewRole(typ string) (r IRole, err error) { @@ -46,22 +63,13 @@ type Menu struct { Children []Menu `json:"children,omitempty"` } -func (r ConsoleRole) ListPermission() interface{} { - - // { - // Id: "cluster_elasticsearch_refresh", - // Name: "集群监控刷新", - // }, - // { - // Id: "cluster_activities", - // Name: "集群动态", - // }, - // { - // Id: "cluster_activities_search", - // Name: "集群动态搜索", - // }, - // - //} +func (role ConsoleRole) Create(localUser *User) (id string, err error) { + return +} +func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { + return +} +func (role ConsoleRole) ListPermission() interface{} { menu := []Menu{ { Id: "cluster", @@ -93,15 +101,15 @@ func (r ConsoleRole) ListPermission() interface{} { return p } -func (r ElasticsearchRole) ListPermission() interface{} { +func (role ElasticsearchRole) ListPermission() interface{} { list := ElasticsearchPermisson{ ClusterPrivileges: ClusterApis, - IndexPrivileges: EsApis["indices"], + IndexPrivileges: IndexApis, } return list } type ElasticsearchPermisson struct { - IndexPrivileges []string `json:"index_privileges"` - ClusterPrivileges []string `json:"cluster_privileges"` + IndexPrivileges []string `json:"index_privileges"` + ClusterPrivileges map[string][]string `json:"cluster_privileges"` } diff --git a/internal/biz/role.go b/internal/biz/role.go index a788bf87..30ca06cd 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -215,3 +215,10 @@ func SearchRole(keyword string, from, size int) (roles orm.Result, err error) { return } +func IsAllowRoleType(roleType string) (err error) { + if roleType != Console && roleType != Elastisearch { + err = fmt.Errorf("invalid role type %s ", roleType) + return + } + return +} diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index 348d0760..e87880f5 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -41,17 +41,14 @@ func loadJsonConfig() { panic("load json file err " + err.Error()) } - - err = json.Unmarshal(bytes, &biz.EsApis) + apis := make(map[string][]string) + err = json.Unmarshal(bytes, &apis) if err != nil { panic("json config unmarshal err " + err.Error()) } - list := make([]string, 0) - list = append(list, "*") - for k := range biz.EsApis { - list = append(list, k) - } - biz.ClusterApis = list + biz.IndexApis = apis["indices"] + delete(apis, "indices") + biz.ClusterApis = apis } func loadRolePermission() { diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index 138c2bc7..7a356cc8 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -9,6 +9,12 @@ import ( func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { typ := ps.MustGetParameter("type") + + err := biz.IsAllowRoleType(typ) + if err != nil { + h.Error400(w, err.Error()) + return + } role, err := biz.NewRole(typ) if err != nil { diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 50421b69..f73e8f7c 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -14,6 +14,11 @@ import ( func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { roleType := ps.MustGetParameter("type") + err := biz.IsAllowRoleType(roleType) + if err != nil { + h.Error400(w, err.Error()) + return + } localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) From 231e174aff2670f6025e40a796ecf2c7a2bedcb9 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 21 Apr 2022 18:20:10 +0800 Subject: [PATCH 33/75] fix: (rbac) role interface --- internal/biz/permission.go | 51 +------------- internal/biz/role.go | 132 +++++++++++++++++++++++++------------ internal/dto/role.go | 6 -- plugin/api/rbac/role.go | 32 ++++----- 4 files changed, 104 insertions(+), 117 deletions(-) diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 762df697..ec1b3c00 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -1,57 +1,14 @@ package biz import ( - "fmt" "infini.sh/console/internal/biz/enum" ) var ClusterApis = make(map[string][]string) var IndexApis = make([]string, 0) -var EsApis = make(map[string][]string) + var RolePermission = make(map[string][]string) -type RoleType = string - -const ( - Console RoleType = "console" - Elastisearch RoleType = "elasticsearch" -) - -type IRole interface { - ListPermission() interface{} - - Create(localUser *User) (id string, err error) -} -type ConsoleRole struct { - Name string `json:"name"` - Description string `json:"description" ` - RoleType string `json:"type" ` - Permission Permission `json:"permission"` -} -type Permission struct { - Api []string `json:"api"` - Menu []MenuPermission `json:"menu"` -} -type MenuPermission struct { - Id string `json:"id"` - Name string `json:"name"` - Privilege string `json:"privilege"` -} -type ElasticsearchRole struct{} - -func NewRole(typ string) (r IRole, err error) { - switch typ { - case Console: - r = &ConsoleRole{} - - case Elastisearch: - r = &ElasticsearchRole{} - default: - err = fmt.Errorf("role type %s not support", typ) - } - return -} - type ConsolePermisson struct { Api []string `json:"api"` Menu []Menu `json:"menu"` @@ -63,12 +20,6 @@ type Menu struct { Children []Menu `json:"children,omitempty"` } -func (role ConsoleRole) Create(localUser *User) (id string, err error) { - return -} -func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { - return -} func (role ConsoleRole) ListPermission() interface{} { menu := []Menu{ { diff --git a/internal/biz/role.go b/internal/biz/role.go index 30ca06cd..c228e213 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -12,33 +12,83 @@ import ( "time" ) -func CreateEsRole(localUser *User, req dto.CreateEsRole) (id string, err error) { - q := orm.Query{Size: 1000} - q.Conds = orm.And(orm.Eq("name", req.Name)) +type RoleType = string + +const ( + Console RoleType = "console" + Elastisearch RoleType = "elasticsearch" +) + +type IRole interface { + ListPermission() interface{} + Create(localUser *User) (id string, err error) +} +type ConsoleRole struct { + Name string `json:"name"` + Description string `json:"description" ` + RoleType string `json:"type" ` + Permission Permission `json:"permission"` +} +type Permission struct { + Api []string `json:"api"` + Menu []MenuPermission `json:"menu"` +} +type MenuPermission struct { + Id string `json:"id"` + Name string `json:"name"` + Privilege string `json:"privilege"` +} +type ElasticsearchRole struct { + Name string `json:"name"` + Description string `json:"description" ` + RoleType string `json:"type" ` + Permission interface{} `json:"permission"` +} + +func NewRole(typ string) (r IRole, err error) { + switch typ { + case Console: + r = &ConsoleRole{ + RoleType: typ, + } + + case Elastisearch: + r = &ElasticsearchRole{ + RoleType: typ, + } + default: + err = fmt.Errorf("role type %s not support", typ) + } + return +} + +func (role ConsoleRole) Create(localUser *User) (id string, err error) { + q := orm.Query{Size: 1} + q.Conds = orm.And(orm.Eq("name", role.Name)) err, result := orm.Search(rbac.Role{}, &q) if err != nil { return } if result.Total > 0 { - err = fmt.Errorf("role name %s already exists", req.Name) + err = fmt.Errorf("role name %s already exists", role.Name) return } - role := &rbac.Role{ - Name: req.Name, - Description: req.Description, - RoleType: req.RoleType, - Permission: req.Permission, + newRole := rbac.Role{ + Name: role.Name, + Description: role.Description, + RoleType: role.RoleType, + Permission: role.Permission, } - role.ID = util.GetUUID() - role.Created = time.Now() - role.Updated = time.Now() - err = orm.Save(role) + newRole.ID = util.GetUUID() + newRole.Created = time.Now() + newRole.Updated = time.Now() + err = orm.Save(&newRole) if err != nil { return } - id = role.ID + id = newRole.ID err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -46,12 +96,12 @@ func CreateEsRole(localUser *User, req dto.CreateEsRole) (id string, err error) Type: "create", Labels: util.MapStr{ "id": id, - "name": req.Name, - "description": req.Description, - "permission": req.Permission, - "type": req.RoleType, - "created": role.Created.Format("2006-01-02 15:04:05"), - "updated": role.Updated.Format("2006-01-02 15:04:05"), + "name": role.Name, + "description": role.Description, + "permission": role.Permission, + "type": role.RoleType, + "created": newRole.Created.Format("2006-01-02 15:04:05"), + "updated": newRole.Updated.Format("2006-01-02 15:04:05"), }, User: util.MapStr{ "userid": localUser.UserId, @@ -63,35 +113,35 @@ func CreateEsRole(localUser *User, req dto.CreateEsRole) (id string, err error) log.Error(err) } return -} -func CreateRole(localUser *User, req dto.CreateConsoleRole) (id string, err error) { - q := orm.Query{Size: 1000} - q.Conds = orm.And(orm.Eq("name", req.Name)) +} +func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { + q := orm.Query{Size: 1} + q.Conds = orm.And(orm.Eq("name", role.Name)) err, result := orm.Search(rbac.Role{}, &q) if err != nil { return } if result.Total > 0 { - err = fmt.Errorf("role name %s already exists", req.Name) + err = fmt.Errorf("role name %s already exists", role.Name) return } - role := &rbac.Role{ - Name: req.Name, - Description: req.Description, - RoleType: req.RoleType, - Permission: req.Permission, + newRole := rbac.Role{ + Name: role.Name, + Description: role.Description, + RoleType: role.RoleType, + Permission: role.Permission, } - role.ID = util.GetUUID() - role.Created = time.Now() - role.Updated = time.Now() - err = orm.Save(role) + newRole.ID = util.GetUUID() + newRole.Created = time.Now() + newRole.Updated = time.Now() + err = orm.Save(&newRole) if err != nil { return } - id = role.ID + id = newRole.ID err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -99,12 +149,12 @@ func CreateRole(localUser *User, req dto.CreateConsoleRole) (id string, err erro Type: "create", Labels: util.MapStr{ "id": id, - "name": req.Name, - "description": req.Description, - "permission": req.Permission, - "type": req.RoleType, - "created": role.Created.Format("2006-01-02 15:04:05"), - "updated": role.Updated.Format("2006-01-02 15:04:05"), + "name": role.Name, + "description": role.Description, + "permission": role.Permission, + "type": role.RoleType, + "created": newRole.Created.Format("2006-01-02 15:04:05"), + "updated": newRole.Updated.Format("2006-01-02 15:04:05"), }, User: util.MapStr{ "userid": localUser.UserId, diff --git a/internal/dto/role.go b/internal/dto/role.go index 9384db71..de97414d 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -1,11 +1,5 @@ package dto -type CreateConsoleRole struct { - Name string `json:"name"` - Description string `json:"description" ` - RoleType string `json:"type" ` - Permission RolePermission `json:"permission"` -} type RolePermission struct { Api []string `json:"api"` Menu []Menu `json:"menu"` diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index f73e8f7c..73928ad6 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -25,28 +25,20 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - var id string - switch roleType { - case biz.Console: - var req dto.CreateConsoleRole - err = h.DecodeJSON(r, &req) - if err != nil { - h.Error400(w, err.Error()) - return - } - req.RoleType = roleType - id, err = biz.CreateRole(localUser, req) - case biz.Elastisearch: - var req dto.CreateEsRole - err = h.DecodeJSON(r, &req) - if err != nil { - h.Error400(w, err.Error()) - return - } - req.RoleType = roleType - id, err = biz.CreateEsRole(localUser, req) + irole, err := biz.NewRole(roleType) + if err != nil { + h.Error(w, err) + return } + err = h.DecodeJSON(r, &irole) + if err != nil { + h.Error400(w, err.Error()) + return + } + var id string + id, err = irole.Create(localUser) + if err != nil { _ = log.Error(err.Error()) h.Error(w, err) From 006e16252323b16586ed34a741c63d60fb8d53a6 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 21 Apr 2022 18:36:40 +0800 Subject: [PATCH 34/75] fix: (rbac) create es role --- internal/biz/role.go | 20 +++++++++++--------- model/rbac/role.go | 19 +++++++++++++------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/internal/biz/role.go b/internal/biz/role.go index c228e213..52b67fbb 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -39,10 +39,10 @@ type MenuPermission struct { Privilege string `json:"privilege"` } type ElasticsearchRole struct { - Name string `json:"name"` - Description string `json:"description" ` - RoleType string `json:"type" ` - Permission interface{} `json:"permission"` + Name string `json:"name"` + Description string `json:"description" ` + RoleType string `json:"type" ` + rbac.ElasticRole } func NewRole(typ string) (r IRole, err error) { @@ -132,8 +132,10 @@ func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { Name: role.Name, Description: role.Description, RoleType: role.RoleType, - Permission: role.Permission, } + newRole.Cluster = role.Cluster + newRole.Index = role.Index + newRole.ClusterPrivilege = role.ClusterPrivilege newRole.ID = util.GetUUID() newRole.Created = time.Now() newRole.Updated = time.Now() @@ -151,10 +153,10 @@ func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { "id": id, "name": role.Name, "description": role.Description, - "permission": role.Permission, - "type": role.RoleType, - "created": newRole.Created.Format("2006-01-02 15:04:05"), - "updated": newRole.Updated.Format("2006-01-02 15:04:05"), + + "type": role.RoleType, + "created": newRole.Created.Format("2006-01-02 15:04:05"), + "updated": newRole.Updated.Format("2006-01-02 15:04:05"), }, User: util.MapStr{ "userid": localUser.UserId, diff --git a/model/rbac/role.go b/model/rbac/role.go index 1e5f2612..ae0b2520 100644 --- a/model/rbac/role.go +++ b/model/rbac/role.go @@ -9,8 +9,9 @@ type Role struct { Name string `json:"name" elastic_mapping:"name:{type:keyword}"` Description string `json:"description" elastic_mapping:"description:{type:text}"` RoleType string `json:"type" elastic_mapping:"type:{type:keyword}"` - Permission interface{} `json:"permission" elastic_mapping:"permission:{type:object}"` + Permission interface{} `json:"permission,omitempty" elastic_mapping:"permission:{type:object}"` BuiltIn bool `json:"builtin" elastic_mapping:"builtin:{type:boolean}"` //是否内置 + ElasticRole } type ConsolePermission struct { Api []string `json:"api"` @@ -22,9 +23,15 @@ type Menu struct { Name string `json:"name"` Privilege string `json:"privilege"` } -type ElasticsearchPermission struct { - Cluster []string `json:"cluster" elastic_mapping:"cluster:{type:object}"` - Index []string `json:"index" elastic_mapping:"index:{type:object}"` - ClusterPrivilege []string `json:"cluster_privilege" elastic_mapping:"cluster_privilege:{type:object}"` - IndexPrivilege []string `json:"index_privilege" elastic_mapping:"index_privilege:{type:object}"` + +type ElasticRole struct { + Cluster []struct { + Id string `json:"id"` + Name string `json:"name"` + } `json:"cluster,omitempty"` + ClusterPrivilege []map[string][]string `json:"cluster_privilege,omitempty"` + Index []struct { + Name []string `json:"name"` + Privilege []string `json:"privilege"` + } `json:"index,omitempty"` } From d64edd2826a4976a70183527c10e24131cc22bc3 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Fri, 22 Apr 2022 11:08:34 +0800 Subject: [PATCH 35/75] fix: (rbac) role=>permission --- internal/biz/enum/const.go | 89 ++++++++++---------------------------- internal/biz/permission.go | 43 +++++++----------- plugin/api/rbac/init.go | 24 +++++----- 3 files changed, 50 insertions(+), 106 deletions(-) diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 2bd2aa94..e373a14c 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -2,43 +2,25 @@ package enum import "time" -const CreateUser = "create_user" -const UpdateUser = "update_user" -const DeleteUser = "delete_user" -const GetUser = "get_user" -const SearchUser = "search_user" +var UserRead = []string{"user::read"} +var UserAll = []string{"user::read", "user::write"} -const CreateRole = "create_role" -const UpdateRole = "update_role" -const DeleteRole = "delete_role" -const GetRole = "get_role" -const SearchRole = "search_role" -const ListPermission = "list_permission" +var RoleRead = []string{"role::read"} +var RoleAll = []string{"role::read", "role::write"} -const CreateRule = "create_rule" -const UpdateRule = "update_rule" -const DeleteRule = "delete_rule" -const GetRule = "get_rule" -const SearchRule = "search_rule" +//const RuleRead = "rule::read" +//const RuleAll = "rule::all" +// +//const InstanceRead = "instance::read" +//const InstanceAll = "instance::all" -const CreateInstance = "create_instance" -const UpdateInstance = "update_instance" -const DeleteInstance = "delete_instance" -const GetInstance = "get_instance" -const SearchInstance = "search_instance" -const GetInstanceStatus = "get_instance_status" -const ConnectInstance = "connect_instance" -const InstanceProxy = "instance_proxy" - -var All = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, - SearchRole, ListPermission, CreateRule, UpdateRule, DeleteRule, GetRule, SearchRule, CreateInstance, UpdateInstance, DeleteInstance, - GetInstance, SearchInstance, GetInstanceStatus, ConnectInstance, InstanceProxy} - -var Admin = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser, CreateRole, UpdateRole, DeleteRole, GetRole, SearchRole, ListPermission} -var AdminUser = []string{CreateUser, UpdateUser, DeleteUser, GetUser, SearchUser} +var Admin []string var BuildRoles = make(map[string]map[string]interface{}, 0) +var Permission = make(map[string][]string) func init() { + Admin = append(Admin, UserAll...) + Admin = append(Admin, RoleAll...) BuildRoles["admin"] = map[string]interface{}{ "id": "admin", "name": "admin", @@ -47,39 +29,14 @@ func init() { "description": "is admin", "created": time.Now(), } -} + //自定义角色=》内置角色 =》权限列表 + // userrole=> cluster;read => permissionList + // login=> userrole=> cluster:read =>permissionList + // search require = (search) + //Permission = map[string][]string{ + // + // UserRead : {UserRead}, + // UserAll: {UserRead, UserWrite}, + //} -// BuildRoles["admin"] = { -// "id":"admin", -// "name":"admin", -//} -//{ -// "name":"admin", -// "id":"admin", -// -//},{ -// -//} -// { -// "name": "admin", -// Name: "admin", -// Description: "管理员", -// RoleType: "console", -// Permission: rbac.ConsolePermission{ -// ApiPermission: Admin, -// }, -// BuiltIn: true, -// }, -// { -// ORMObjectBase: orm.ORMObjectBase{ -// ID: "admin_user", -// }, -// Name: "admin_user", -// Description: "用户模块管理员", -// RoleType: "console", -// Permission: rbac.ConsolePermission{ -// ApiPermission: AdminUser, -// }, -// BuiltIn: true, -// }, -//} +} diff --git a/internal/biz/permission.go b/internal/biz/permission.go index ec1b3c00..4f75967d 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -1,17 +1,12 @@ package biz -import ( - "infini.sh/console/internal/biz/enum" -) - var ClusterApis = make(map[string][]string) var IndexApis = make([]string, 0) var RolePermission = make(map[string][]string) type ConsolePermisson struct { - Api []string `json:"api"` - Menu []Menu `json:"menu"` + Menu []Menu `json:"menu"` } type Menu struct { Id string `json:"id"` @@ -21,32 +16,24 @@ type Menu struct { } func (role ConsoleRole) ListPermission() interface{} { - menu := []Menu{ + menu := []Menu{{ + Id: "cluster", + Name: "平台管理", + Privilege: []string{"none", "read", "all"}, + }, { - Id: "cluster", - Name: "平台管理", - Children: []Menu{ - { - Id: "cluster_overview", - Name: "平台概览", - Privilege: []string{"none", "write", "read"}, - }, - { - - Id: "cluster_elasticsearch", - Name: "集群监控", - Privilege: []string{"none", "write", "read"}, - }, { - - Id: "cluster_activities", - Name: "集群动态", - Privilege: []string{"none", "write", "read"}, - }, - }, + Id: "role", + Name: "角色管理", + Privilege: []string{"none", "read", "all"}, + }, + { + Id: "user", + Name: "用户管理", + Privilege: []string{"none", "read", "all"}, }, } p := ConsolePermisson{ - Api: enum.All, + Menu: menu, } diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index e87880f5..d1f9ba5f 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -17,19 +17,19 @@ type Rbac struct { func registerRouter() { r := Rbac{} - api.HandleAPIMethod(api.GET, "/permission/:type", m.PermissionRequired(r.ListPermission, enum.ListPermission)) - api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.CreateRole)) - api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.GetRole)) - api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.DeleteRole)) - api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.UpdateRole)) - api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.SearchRole)) + api.HandleAPIMethod(api.GET, "/permission/:type", m.PermissionRequired(r.ListPermission, enum.RoleRead...)) + api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAll...)) + api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleRead...)) + api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAll...)) + api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.RoleAll...)) + api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.RoleRead...)) - api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.CreateUser)) - api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.GetUser)) - api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.DeleteUser)) - api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UpdateUser)) - api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UpdateUser)) - api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.SearchUser)) + api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.UserAll...)) + api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.UserRead...)) + api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.UserAll...)) + api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAll...)) + api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAll...)) + api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserRead...)) } From 2c1b792977a51897eb7702b327767ceef7129bb1 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Fri, 22 Apr 2022 12:56:11 +0800 Subject: [PATCH 36/75] fix: (rbac) permission --- internal/biz/enum/const.go | 10 ++++++---- internal/biz/permission.go | 30 ++++++++++++++++-------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index e373a14c..2c1175a9 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -29,14 +29,16 @@ func init() { "description": "is admin", "created": time.Now(), } - //自定义角色=》内置角色 =》权限列表 - // userrole=> cluster;read => permissionList - // login=> userrole=> cluster:read =>permissionList - // search require = (search) + //自定义角色=》 =》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) } diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 4f75967d..31ac4440 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -16,27 +16,29 @@ type Menu struct { } func (role ConsoleRole) ListPermission() interface{} { - menu := []Menu{{ - Id: "cluster", - Name: "平台管理", - Privilege: []string{"none", "read", "all"}, - }, + menu := []Menu{ { - Id: "role", - Name: "角色管理", - Privilege: []string{"none", "read", "all"}, - }, - { - Id: "user", - Name: "用户管理", - Privilege: []string{"none", "read", "all"}, + Id: "system", + Name: "系统管理", + Children: []Menu{ + { + Id: "system_user", + Name: "用户管理", + Privilege: []string{"none", "read", "all"}, + }, + { + + Id: "system_role", + Name: "角色管理", + Privilege: []string{"none", "read", "all"}, + }, + }, }, } p := ConsolePermisson{ Menu: menu, } - return p } func (role ElasticsearchRole) ListPermission() interface{} { From fbacc4ab62bf042e35bdbed8ba111768497b6f71 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Fri, 22 Apr 2022 15:55:15 +0800 Subject: [PATCH 37/75] fix: (rbac) login privllege --- internal/biz/account.go | 3 ++ internal/biz/enum/const.go | 39 +++++++++++++++++++----- internal/biz/enum/menu.go | 7 +++++ internal/biz/role.go | 10 +++++++ plugin/api/index_management/index.go | 44 ++++++++++++++++++++++++++-- plugin/api/init.go | 8 ++--- plugin/api/rbac/role.go | 18 +++++++----- 7 files changed, 109 insertions(+), 20 deletions(-) create mode 100644 internal/biz/enum/menu.go diff --git a/internal/biz/account.go b/internal/biz/account.go index 34440f58..53254aa2 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -99,6 +99,9 @@ func authorize(user Account) (m map[string]interface{}, err error) { "id": user.ID, "expire_in": 86400, "roles": []string{"admin"}, + "privilege": []string{ + "system_user:all", "system_role:all", "system_cluster:all", "system_command:all", + }, } return } diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 2c1175a9..d2b08c17 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -8,11 +8,11 @@ var UserAll = []string{"user::read", "user::write"} var RoleRead = []string{"role::read"} var RoleAll = []string{"role::read", "role::write"} -//const RuleRead = "rule::read" -//const RuleAll = "rule::all" -// -//const InstanceRead = "instance::read" -//const InstanceAll = "instance::all" +var RuleRead = []string{"rule::read"} +var RuleAll = []string{"rule::read", "rule::write"} + +var InstanceRead = []string{"instance::read"} +var InstanceAll = []string{"instance::read", "instance::write"} var Admin []string var BuildRoles = make(map[string]map[string]interface{}, 0) @@ -21,14 +21,39 @@ var Permission = make(map[string][]string) func init() { Admin = append(Admin, UserAll...) Admin = append(Admin, RoleAll...) + + UserMenu := Menu{ + Id: "system_user", + Name: "用户管理", + Privilege: "all", + } + RoleMenu := Menu{ + Id: "system_role", + Name: "角色管理", + Privilege: "all", + } + AdminMenu := []Menu{ + UserMenu, RoleMenu, + } + BuildRoles["admin"] = map[string]interface{}{ "id": "admin", - "name": "admin", - "permission": Admin, + "name": "管理员", + "permission": AdminMenu, "builtin": true, "description": "is admin", "created": time.Now(), } + + BuildRoles["user_admin"] = map[string]interface{}{ + "id": "user_admin", + "name": "用户管理员", + "permission": UserMenu, + "builtin": true, + "description": "is user admin", + "created": time.Now(), + } + //自定义角色=》 =》permissionKey // userrole=> [cluster::all,clust] => permissionValue [cluster::read,cluster::write] // login=> userrole=> cluster::all =>permissionList[] diff --git a/internal/biz/enum/menu.go b/internal/biz/enum/menu.go new file mode 100644 index 00000000..f12602f7 --- /dev/null +++ b/internal/biz/enum/menu.go @@ -0,0 +1,7 @@ +package enum + +type Menu struct { + Id string `json:"id"` + Name string `json:"name"` + Privilege string `json:"privilege,omitempty"` +} diff --git a/internal/biz/role.go b/internal/biz/role.go index 52b67fbb..6566c29d 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -2,6 +2,7 @@ package biz import ( "fmt" + "infini.sh/console/internal/biz/enum" "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" "infini.sh/framework/core/event" @@ -63,6 +64,10 @@ func NewRole(typ string) (r IRole, err error) { } func (role ConsoleRole) Create(localUser *User) (id string, err error) { + if _, ok := enum.BuildRoles[role.Name]; ok { + err = fmt.Errorf("role name %s already exists", role.Name) + return + } q := orm.Query{Size: 1} q.Conds = orm.And(orm.Eq("name", role.Name)) @@ -116,6 +121,11 @@ func (role ConsoleRole) Create(localUser *User) (id string, err error) { } func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { + + if _, ok := enum.BuildRoles[role.Name]; ok { + err = fmt.Errorf("role name %s already exists", role.Name) + return + } q := orm.Query{Size: 1} q.Conds = orm.And(orm.Eq("name", role.Name)) diff --git a/plugin/api/index_management/index.go b/plugin/api/index_management/index.go index 50e48c97..519e60b9 100644 --- a/plugin/api/index_management/index.go +++ b/plugin/api/index_management/index.go @@ -6,12 +6,12 @@ import ( "strings" "time" + "infini.sh/console/config" + model2 "infini.sh/console/model" "infini.sh/framework/core/api" httprouter "infini.sh/framework/core/api/router" "infini.sh/framework/core/orm" "infini.sh/framework/core/util" - "infini.sh/console/config" - model2 "infini.sh/console/model" ) type APIHandler struct { @@ -116,3 +116,43 @@ func (handler APIHandler) UpdateDictItemAction(w http.ResponseWriter, req *http. handler.WriteJSON(w, resp, http.StatusOK) } +func (handler APIHandler) ListIndex(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + // clusterIds := handler.GetParameterOrDefault(req, "cluster_id", "") + // keyword := handler.GetParameterOrDefault(req, "keyword", "") + // Ids := strings.Split(clusterIds, ",") + // var dsl = `{ + // "_source": ["metadata.index_name"], + // "collapse": { + // "field": "metadata.index_name" + // }, + // "size": 100, + // "query": { + // "bool": { + // "must": [ + // { + // "terms": { + // "metadata.cluster_id": [%s] + // } + // },%s + // ], + // "must_not": [ + // { + // "term": { + // "metadata.labels.state": { + // "value": "delete" + // } + // } + // } + // ] + // } + // } + //}` + // var likeDsl = `{ + // "wildcard": { + // "metadata.index_name": { + // "value": "*inf*" + // } + // } + // }` + return +} diff --git a/plugin/api/init.go b/plugin/api/init.go index c7f323aa..cc10b933 100644 --- a/plugin/api/init.go +++ b/plugin/api/init.go @@ -33,18 +33,18 @@ func Init(cfg *config.AppConfig) { api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "rebuild/_search"), handler.HandleGetRebuildListAction) api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "rebuild/:id"), handler.HandleDeleteRebuildAction) - api.HandleAPIMethod(api.GET, path.Join(esPrefix, "_cat/indices"), handler.HandleGetIndicesAction) + api.HandleAPIMethod(api.GET, path.Join(esPrefix, "_cat/indices"), handler.HandleGetIndicesAction) api.HandleAPIMethod(api.GET, path.Join(esPrefix, "index/:index/_mappings"), handler.HandleGetMappingsAction) api.HandleAPIMethod(api.GET, path.Join(esPrefix, "index/:index/_settings"), handler.HandleGetSettingsAction) api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "index/:index/_settings"), handler.HandleUpdateSettingsAction) api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "index/:index"), handler.HandleDeleteIndexAction) api.HandleAPIMethod(api.POST, path.Join(esPrefix, "index/:index"), handler.HandleCreateIndexAction) - api.HandleAPIMethod(api.POST, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleAddCommonCommandAction) - api.HandleAPIMethod(api.PUT, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleSaveCommonCommandAction) + api.HandleAPIMethod(api.POST, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleAddCommonCommandAction) + api.HandleAPIMethod(api.PUT, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleSaveCommonCommandAction) api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleQueryCommonCommandAction) api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleDeleteCommonCommandAction) - + api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "cluster/indices"), handler.ListIndex) //task.RegisterScheduleTask(task.ScheduleTask{ // Description: "sync reindex task result", // Task: func() { diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 73928ad6..92657cfa 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -67,19 +67,23 @@ func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.P util.FromJSONBytes(res.Raw, &response) list := response.Hits.Hits + total := response.GetTotal() var index string for _, v := range list { index = v.Index } + for k, v := range enum.BuildRoles { + list = append(list, elastic.IndexDocument{ + ID: k, + Index: index, + Type: "_doc", + Source: v, + }) + total++ + } - list = append(list, elastic.IndexDocument{ - ID: "admin", - Index: index, - Type: "_doc", - Source: enum.BuildRoles["admin"], - }) response.Hits.Hits = list - response.Hits.Total = response.GetTotal() + 1 + response.Hits.Total = total h.WriteOKJSON(w, response) return From 0c7d037e07e5a1a35b2f478059c4a0f11daec5da Mon Sep 17 00:00:00 2001 From: xushuhui Date: Fri, 22 Apr 2022 18:36:39 +0800 Subject: [PATCH 38/75] fix: (rbac) list index names by cluster ids --- internal/biz/account.go | 2 +- internal/biz/permission.go | 35 ++------- internal/biz/role.go | 2 - plugin/api/index_management/index.go | 103 +++++++++++++++++---------- plugin/api/rbac/init.go | 2 +- 5 files changed, 74 insertions(+), 70 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index 53254aa2..5e76374a 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -100,7 +100,7 @@ func authorize(user Account) (m map[string]interface{}, err error) { "expire_in": 86400, "roles": []string{"admin"}, "privilege": []string{ - "system_user:all", "system_role:all", "system_cluster:all", "system_command:all", + "system.user:all", "system.role:all", "system.cluster:all", "system.command:all", }, } return diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 31ac4440..9ac146a7 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -6,39 +6,18 @@ var IndexApis = make([]string, 0) var RolePermission = make(map[string][]string) type ConsolePermisson struct { - Menu []Menu `json:"menu"` + Platform []Platform `json:"platform"` } -type Menu struct { - Id string `json:"id"` - Name string `json:"name"` - Privilege []string `json:"privilege,omitempty"` - Children []Menu `json:"children,omitempty"` +type Platform struct { + Id string `json:"id"` + + Privilege map[string]string `json:"privilege,omitempty"` + Children []Platform `json:"children,omitempty"` } func (role ConsoleRole) ListPermission() interface{} { - menu := []Menu{ - { - Id: "system", - Name: "系统管理", - Children: []Menu{ - { - Id: "system_user", - Name: "用户管理", - Privilege: []string{"none", "read", "all"}, - }, - { - Id: "system_role", - Name: "角色管理", - Privilege: []string{"none", "read", "all"}, - }, - }, - }, - } - p := ConsolePermisson{ - - Menu: menu, - } + p := ConsolePermisson{} return p } func (role ElasticsearchRole) ListPermission() interface{} { diff --git a/internal/biz/role.go b/internal/biz/role.go index 6566c29d..22a065b4 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -31,12 +31,10 @@ type ConsoleRole struct { Permission Permission `json:"permission"` } type Permission struct { - Api []string `json:"api"` Menu []MenuPermission `json:"menu"` } type MenuPermission struct { Id string `json:"id"` - Name string `json:"name"` Privilege string `json:"privilege"` } type ElasticsearchRole struct { diff --git a/plugin/api/index_management/index.go b/plugin/api/index_management/index.go index 519e60b9..3c0be5e6 100644 --- a/plugin/api/index_management/index.go +++ b/plugin/api/index_management/index.go @@ -1,6 +1,8 @@ package index_management import ( + "fmt" + "infini.sh/framework/core/elastic" "net/http" "strconv" "strings" @@ -116,43 +118,68 @@ func (handler APIHandler) UpdateDictItemAction(w http.ResponseWriter, req *http. handler.WriteJSON(w, resp, http.StatusOK) } -func (handler APIHandler) ListIndex(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - // clusterIds := handler.GetParameterOrDefault(req, "cluster_id", "") - // keyword := handler.GetParameterOrDefault(req, "keyword", "") - // Ids := strings.Split(clusterIds, ",") - // var dsl = `{ - // "_source": ["metadata.index_name"], - // "collapse": { - // "field": "metadata.index_name" - // }, - // "size": 100, - // "query": { - // "bool": { - // "must": [ - // { - // "terms": { - // "metadata.cluster_id": [%s] - // } - // },%s - // ], - // "must_not": [ - // { - // "term": { - // "metadata.labels.state": { - // "value": "delete" - // } - // } - // } - // ] - // } - // } - //}` - // var likeDsl = `{ - // "wildcard": { - // "metadata.index_name": { - // "value": "*inf*" - // } - // } - // }` +func (h APIHandler) ListIndex(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + clusterIds := h.GetParameterOrDefault(req, "ids", "") + keyword := h.GetParameterOrDefault(req, "keyword", "") + ids := strings.Split(clusterIds, ",") + for i := range ids { + ids[i] = `"` + ids[i] + `"` + } + if len(ids) == 0 { + h.Error400(w, "id is required") + return + } + var dsl = `{ + "_source": ["metadata.index_name"], + "collapse": { + "field": "metadata.index_name" + }, + "size": 100, + "query": { + "bool": { + "must": [ + { + "terms": { + "metadata.cluster_id": %s + } + }%s + ], + "must_not": [ + { + "term": { + "metadata.labels.state": { + "value": "delete" + } + } + } + ] + } + } + }` + + str := &strings.Builder{} + + if keyword != "" { + str.WriteString(fmt.Sprintf(`,{"wildcard":{"metadata.index_name":{"value":"*%s*"}}}`, keyword)) + } + dsl = fmt.Sprintf(dsl, ids, str) + + esClient := elastic.GetClient(h.Config.Elasticsearch) + resp, err := esClient.SearchWithRawQueryDSL(".infini_index", []byte(dsl)) + if err != nil { + + return + } + list := resp.Hits.Hits + var indexNames []string + for _, v := range list { + m := v.Source["metadata"].(map[string]interface{}) + indexNames = append(indexNames, m["index_name"].(string)) + + } + m := make(map[string]interface{}) + m["indexnames"] = indexNames + h.WriteOKJSON(w, m) + return } diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/init.go index d1f9ba5f..37845318 100644 --- a/plugin/api/rbac/init.go +++ b/plugin/api/rbac/init.go @@ -58,7 +58,7 @@ func loadRolePermission() { } func init() { registerRouter() - loadJsonConfig() + loadRolePermission() } From a6f3c2203f185dc028b4b8f75036c51f0d46476f Mon Sep 17 00:00:00 2001 From: xushuhui Date: Sun, 24 Apr 2022 09:37:07 +0800 Subject: [PATCH 39/75] fix: (rbac) --- internal/biz/account.go | 7 ++++--- internal/biz/enum/const.go | 5 ++--- internal/biz/enum/menu.go | 4 ++-- internal/biz/role.go | 26 ++++++++++++-------------- internal/dto/role.go | 4 ++-- model/rbac/role.go | 19 ++++++++++++------- plugin/api/rbac/permission.go | 28 +++++++++++++--------------- 7 files changed, 47 insertions(+), 46 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index 5e76374a..eee13089 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -22,9 +22,10 @@ type UserClaims struct { *User } type User struct { - Username string `json:"username"` - UserId string `json:"user_id"` - Roles []string `json:"roles"` + Username string `json:"username"` + UserId string `json:"user_id"` + Roles []string `json:"roles"` + Privilege []string `json:"privilege"` } type Account struct { ID string `json:"id,omitempty" ` diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index d2b08c17..6c657966 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -24,12 +24,11 @@ func init() { UserMenu := Menu{ Id: "system_user", - Name: "用户管理", Privilege: "all", } RoleMenu := Menu{ - Id: "system_role", - Name: "角色管理", + Id: "system_role", + Privilege: "all", } AdminMenu := []Menu{ diff --git a/internal/biz/enum/menu.go b/internal/biz/enum/menu.go index f12602f7..3d75ee6e 100644 --- a/internal/biz/enum/menu.go +++ b/internal/biz/enum/menu.go @@ -1,7 +1,7 @@ package enum type Menu struct { - Id string `json:"id"` - Name string `json:"name"` + Id string `json:"id"` + Privilege string `json:"privilege,omitempty"` } diff --git a/internal/biz/role.go b/internal/biz/role.go index 22a065b4..0bd19446 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -21,18 +21,16 @@ const ( ) type IRole interface { - ListPermission() interface{} Create(localUser *User) (id string, err error) + //Delete(localUser *User, id string) (err error) } type ConsoleRole struct { - Name string `json:"name"` - Description string `json:"description" ` - RoleType string `json:"type" ` - Permission Permission `json:"permission"` -} -type Permission struct { - Menu []MenuPermission `json:"menu"` + Name string `json:"name"` + Description string `json:"description" ` + RoleType string `json:"type" ` + Platform []string `json:"platform,omitempty"` } + type MenuPermission struct { Id string `json:"id"` Privilege string `json:"privilege"` @@ -82,7 +80,7 @@ func (role ConsoleRole) Create(localUser *User) (id string, err error) { Name: role.Name, Description: role.Description, RoleType: role.RoleType, - Permission: role.Permission, + Platform: role.Platform, } newRole.ID = util.GetUUID() newRole.Created = time.Now() @@ -101,7 +99,7 @@ func (role ConsoleRole) Create(localUser *User) (id string, err error) { "id": id, "name": role.Name, "description": role.Description, - "permission": role.Permission, + "platform": role.Platform, "type": role.RoleType, "created": newRole.Created.Format("2006-01-02 15:04:05"), "updated": newRole.Updated.Format("2006-01-02 15:04:05"), @@ -136,7 +134,7 @@ func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { return } - newRole := rbac.Role{ + newRole := rbac.ElasticRole{ Name: role.Name, Description: role.Description, RoleType: role.RoleType, @@ -205,7 +203,7 @@ func DeleteRole(localUser *User, id string) (err error) { "id": id, "name": role.Name, "description": role.Description, - "permission": role.Permission, + "platform": role.Platform, "type": role.RoleType, "created": role.Created.Format("2006-01-02 15:04:05"), "updated": role.Updated.Format("2006-01-02 15:04:05"), @@ -224,7 +222,7 @@ func UpdateRole(localUser *User, id string, req dto.UpdateConsoleRole) (err erro } changeLog, _ := util.DiffTwoObject(role, req) role.Description = req.Description - role.Permission = req.Permission + role.Platform = req.Platform role.Updated = time.Now() err = orm.Save(role) if err != nil { @@ -238,7 +236,7 @@ func UpdateRole(localUser *User, id string, req dto.UpdateConsoleRole) (err erro Labels: util.MapStr{ "id": id, "description": role.Description, - "permission": role.Permission, + "platform": role.Platform, "updated": role.Updated, }, User: util.MapStr{ diff --git a/internal/dto/role.go b/internal/dto/role.go index de97414d..9ab2e858 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -10,8 +10,8 @@ type Menu struct { Privilege string `json:"privilege"` } type UpdateConsoleRole struct { - Description string `json:"description" ` - Permission RolePermission `json:"permission"` + Description string `json:"description" ` + Platform []string `json:"platform"` } type CreateEsRole struct { Name string `json:"name"` diff --git a/model/rbac/role.go b/model/rbac/role.go index ae0b2520..012219fe 100644 --- a/model/rbac/role.go +++ b/model/rbac/role.go @@ -6,12 +6,12 @@ import ( type Role struct { orm.ORMObjectBase - Name string `json:"name" elastic_mapping:"name:{type:keyword}"` - Description string `json:"description" elastic_mapping:"description:{type:text}"` - RoleType string `json:"type" elastic_mapping:"type:{type:keyword}"` - Permission interface{} `json:"permission,omitempty" elastic_mapping:"permission:{type:object}"` - BuiltIn bool `json:"builtin" elastic_mapping:"builtin:{type:boolean}"` //是否内置 - ElasticRole + Name string `json:"name" elastic_mapping:"name:{type:keyword}"` + Description string `json:"description" elastic_mapping:"description:{type:text}"` + RoleType string `json:"type" elastic_mapping:"type:{type:keyword}"` + Platform []string `json:"platform,omitempty" ` + BuiltIn bool `json:"builtin" elastic_mapping:"builtin:{type:boolean}"` //是否内置 + } type ConsolePermission struct { Api []string `json:"api"` @@ -25,7 +25,12 @@ type Menu struct { } type ElasticRole struct { - Cluster []struct { + orm.ORMObjectBase + Name string `json:"name" elastic_mapping:"name:{type:keyword}"` + Description string `json:"description" elastic_mapping:"description:{type:text}"` + RoleType string `json:"type" elastic_mapping:"type:{type:keyword}"` + BuiltIn bool `json:"builtin" elastic_mapping:"builtin:{type:boolean}"` //是否内置 + Cluster []struct { Id string `json:"id"` Name string `json:"name"` } `json:"cluster,omitempty"` diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index 7a356cc8..165b9398 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -1,8 +1,6 @@ package rbac import ( - log "github.com/cihub/seelog" - "infini.sh/console/internal/biz" httprouter "infini.sh/framework/core/api/router" "net/http" ) @@ -10,19 +8,19 @@ import ( func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { typ := ps.MustGetParameter("type") - err := biz.IsAllowRoleType(typ) - if err != nil { - h.Error400(w, err.Error()) - return - } - role, err := biz.NewRole(typ) + //err := biz.IsAllowRoleType(typ) + //if err != nil { + // h.Error400(w, err.Error()) + // return + //} + //role, err := biz.NewRole(typ) + // + //if err != nil { + // _ = log.Error(err.Error()) + // h.Error(w, err) + // return + //} - if err != nil { - _ = log.Error(err.Error()) - h.Error(w, err) - return - } - permissions := role.ListPermission() - h.WriteOKJSON(w, permissions) + h.WriteOKJSON(w, typ) return } From 16dc8347d91bfea5e2c9ba5d314f211eef3eb6ec Mon Sep 17 00:00:00 2001 From: liugq Date: Sun, 24 Apr 2022 10:25:07 +0800 Subject: [PATCH 40/75] rename cluster to elasticsearch --- plugin/api/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/api/init.go b/plugin/api/init.go index cc10b933..df7775d2 100644 --- a/plugin/api/init.go +++ b/plugin/api/init.go @@ -44,7 +44,7 @@ func Init(cfg *config.AppConfig) { api.HandleAPIMethod(api.PUT, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleSaveCommonCommandAction) api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleQueryCommonCommandAction) api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleDeleteCommonCommandAction) - api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "cluster/indices"), handler.ListIndex) + api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "elasticsearch/indices"), handler.ListIndex) //task.RegisterScheduleTask(task.ScheduleTask{ // Description: "sync reindex task result", // Task: func() { From 95aeeac37771b207d5ade83d20e7acbd3973680f Mon Sep 17 00:00:00 2001 From: xushuhui Date: Sun, 24 Apr 2022 10:40:47 +0800 Subject: [PATCH 41/75] fix: (rbac) login roles --- internal/biz/account.go | 25 +++++++++++++++---------- plugin/api/rbac/{init.go => api.go} | 0 2 files changed, 15 insertions(+), 10 deletions(-) rename plugin/api/rbac/{init.go => api.go} (100%) diff --git a/internal/biz/account.go b/internal/biz/account.go index eee13089..6e657590 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -28,15 +28,16 @@ type User struct { Privilege []string `json:"privilege"` } type Account struct { - ID string `json:"id,omitempty" ` - Created string `json:"created,omitempty" ` - Updated string `json:"updated,omitempty" ` - Username string `json:"username" elastic_mapping:"username:{type:keyword}"` - Password string `json:"password" elastic_mapping:"password:{type:text}"` - Name string `json:"name" elastic_mapping:"name:{type:keyword}"` - Phone string `json:"phone" elastic_mapping:"phone:{type:keyword}"` - Email string `json:"email" elastic_mapping:"email:{type:keyword}"` - Tags []string `json:"tags" elastic_mapping:"tags:{type:text}"` + ID string `json:"id,omitempty" ` + Created string `json:"created,omitempty" ` + Updated string `json:"updated,omitempty" ` + Username string `json:"username" elastic_mapping:"username:{type:keyword}"` + Password string `json:"password" elastic_mapping:"password:{type:text}"` + Name string `json:"name" elastic_mapping:"name:{type:keyword}"` + Phone string `json:"phone" elastic_mapping:"phone:{type:keyword}"` + Email string `json:"email" elastic_mapping:"email:{type:keyword}"` + Tags []string `json:"tags" elastic_mapping:"tags:{type:text}"` + Roles []rbac.UserRole `json:"roles"` } const Secret = "console" @@ -76,6 +77,9 @@ func authenticateAdmin(username string, password string) (user Account, err erro } user.ID = username user.Username = username + user.Roles = []rbac.UserRole{{ + Id: "admin", Name: "admin", + }} return user, nil } func authorize(user Account) (m map[string]interface{}, err error) { @@ -94,12 +98,13 @@ func authorize(user Account) (m map[string]interface{}, err error) { if err != nil { return } + m = util.MapStr{ "access_token": tokenString, "username": user.Username, "id": user.ID, "expire_in": 86400, - "roles": []string{"admin"}, + "roles": user.Roles, "privilege": []string{ "system.user:all", "system.role:all", "system.cluster:all", "system.command:all", }, diff --git a/plugin/api/rbac/init.go b/plugin/api/rbac/api.go similarity index 100% rename from plugin/api/rbac/init.go rename to plugin/api/rbac/api.go From a1efff50f2af099ec9a79a48fc6d603315023e80 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Sun, 24 Apr 2022 10:49:07 +0800 Subject: [PATCH 42/75] fix: (rbac) --- internal/biz/account.go | 7 +++++-- internal/biz/role.go | 1 + plugin/api/rbac/permission.go | 28 +++++++++++++++------------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index 6e657590..a5bac517 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -98,13 +98,16 @@ func authorize(user Account) (m map[string]interface{}, err error) { if err != nil { return } - + var roles []string + for _, v := range user.Roles { + roles = append(roles, v.Name) + } m = util.MapStr{ "access_token": tokenString, "username": user.Username, "id": user.ID, "expire_in": 86400, - "roles": user.Roles, + "roles": roles, "privilege": []string{ "system.user:all", "system.role:all", "system.cluster:all", "system.command:all", }, diff --git a/internal/biz/role.go b/internal/biz/role.go index 0bd19446..0d15dce1 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -21,6 +21,7 @@ const ( ) type IRole interface { + ListPermission() interface{} Create(localUser *User) (id string, err error) //Delete(localUser *User, id string) (err error) } diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index 165b9398..7a356cc8 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -1,6 +1,8 @@ package rbac import ( + log "github.com/cihub/seelog" + "infini.sh/console/internal/biz" httprouter "infini.sh/framework/core/api/router" "net/http" ) @@ -8,19 +10,19 @@ import ( func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { typ := ps.MustGetParameter("type") - //err := biz.IsAllowRoleType(typ) - //if err != nil { - // h.Error400(w, err.Error()) - // return - //} - //role, err := biz.NewRole(typ) - // - //if err != nil { - // _ = log.Error(err.Error()) - // h.Error(w, err) - // return - //} + err := biz.IsAllowRoleType(typ) + if err != nil { + h.Error400(w, err.Error()) + return + } + role, err := biz.NewRole(typ) - h.WriteOKJSON(w, typ) + if err != nil { + _ = log.Error(err.Error()) + h.Error(w, err) + return + } + permissions := role.ListPermission() + h.WriteOKJSON(w, permissions) return } From 3bb04e4ab1a34c71bc110d85bce88b41c35978e0 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Sun, 24 Apr 2022 12:05:05 +0800 Subject: [PATCH 43/75] fix: (rbac) user profile --- internal/biz/account.go | 8 ++++---- internal/biz/context.go | 36 +++++++++++++++++++++++++++++++++++ internal/biz/enum/const.go | 1 - internal/biz/permission.go | 12 ++++++++++++ internal/biz/role.go | 2 +- internal/middleware/user.go | 12 ++++++++++++ model/rbac/role.go | 9 +++++++++ plugin/api/account/account.go | 35 ++++++++++++++++++++++------------ plugin/api/rbac/api.go | 5 +++-- 9 files changed, 100 insertions(+), 20 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index a5bac517..ecaaca87 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -22,10 +22,9 @@ type UserClaims struct { *User } type User struct { - Username string `json:"username"` - UserId string `json:"user_id"` - Roles []string `json:"roles"` - Privilege []string `json:"privilege"` + Username string `json:"username"` + UserId string `json:"user_id"` + Roles []string `json:"roles"` } type Account struct { ID string `json:"id,omitempty" ` @@ -227,6 +226,7 @@ func ValidatePermission(claims *UserClaims, permissions []string) (err error) { } } } + var count int for _, v := range permissions { if _, ok := userPermissionMap[v]; ok { diff --git a/internal/biz/context.go b/internal/biz/context.go index 2d4a8e49..d6f41808 100644 --- a/internal/biz/context.go +++ b/internal/biz/context.go @@ -21,3 +21,39 @@ func FromUserContext(ctx context.Context) (*User, error) { } return reqUser.User, nil } + +//type EsRole struct { +// Cluster []string `json:"cluster,omitempty"` +// Index []string `json:"index,omitempty"` +//} + +func NewEsContext(ctx context.Context, role EsRole) { + //get user es role + +} +func ValidateEsPermission(req, userRole EsRole) (err error) { + userClusterMap := make(map[string]struct{}) + userIndexMap := make(map[string]struct{}) + for _, v := range userRole.Cluster { + userClusterMap[v.Id] = struct{}{} + } + for _, val := range userRole.Index { + for _, v := range val.Name { + userIndexMap[v] = struct{}{} + } + + } + //for _, v := range req.Cluster { + // if _, ok := userClusterMap[v]; !ok { + // err = errors.New("no cluster permission") + // return + // } + //} + //for _, v := range req.Index { + // if _, ok := userClusterMap[v]; !ok { + // err = errors.New("no index permission") + // return + // } + //} + return +} diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 6c657966..1ca72c11 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -16,7 +16,6 @@ var InstanceAll = []string{"instance::read", "instance::write"} var Admin []string var BuildRoles = make(map[string]map[string]interface{}, 0) -var Permission = make(map[string][]string) func init() { Admin = append(Admin, UserAll...) diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 9ac146a7..6128d4ad 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -4,7 +4,19 @@ var ClusterApis = make(map[string][]string) var IndexApis = make([]string, 0) var RolePermission = make(map[string][]string) +var EsRolePermission = make(map[string]EsRole) +type EsRole struct { + Cluster []struct { + Id string `json:"id"` + Name string `json:"name"` + } `json:"cluster,omitempty"` + ClusterPrivilege []map[string][]string `json:"cluster_privilege,omitempty"` + Index []struct { + Name []string `json:"name"` + Privilege []string `json:"privilege"` + } `json:"index,omitempty"` +} type ConsolePermisson struct { Platform []Platform `json:"platform"` } diff --git a/internal/biz/role.go b/internal/biz/role.go index 0d15dce1..069b0780 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -135,7 +135,7 @@ func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { return } - newRole := rbac.ElasticRole{ + newRole := rbac.Role{ Name: role.Name, Description: role.Description, RoleType: role.RoleType, diff --git a/internal/middleware/user.go b/internal/middleware/user.go index 9b41edf8..fdfcf589 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -19,7 +19,19 @@ func LoginRequired(h httprouter.Handle) httprouter.Handle { h(w, r, ps) } } +func EsPermissionReqired(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 + } + r = r.WithContext(biz.NewUserContext(r.Context(), claims)) + h(w, r, ps) + } +} func PermissionRequired(h httprouter.Handle, permissions ...string) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { claims, err := biz.ValidateLogin(r.Header.Get("Authorization")) diff --git a/model/rbac/role.go b/model/rbac/role.go index 012219fe..41fb8cf1 100644 --- a/model/rbac/role.go +++ b/model/rbac/role.go @@ -12,6 +12,15 @@ type Role struct { Platform []string `json:"platform,omitempty" ` BuiltIn bool `json:"builtin" elastic_mapping:"builtin:{type:boolean}"` //是否内置 + Cluster []struct { + Id string `json:"id"` + Name string `json:"name"` + } `json:"cluster,omitempty"` + ClusterPrivilege []map[string][]string `json:"cluster_privilege,omitempty"` + Index []struct { + Name []string `json:"name"` + Privilege []string `json:"privilege"` + } `json:"index,omitempty"` } type ConsolePermission struct { Api []string `json:"api"` diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index e7a03a12..d01f3a4f 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -103,20 +103,31 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - //user, err := biz.GetUser(reqUser.UserId) - //if err != nil { - // h.Error(w, err) - // return - //} - //TODO get user from es - u := util.MapStr{ - "user_id": reqUser.UserId, - "username": reqUser.Username, - "email": "hello@infini.ltd", - "name": "admin", + if reqUser.UserId == "admin" { + + u := util.MapStr{ + "user_id": "admin", + "username": "admin", + "email": "admin@infini.ltd", + "name": "admin", + } + h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) + } else { + user, err := biz.GetUser(reqUser.UserId) + if err != nil { + h.Error(w, err) + return + } + u := util.MapStr{ + "user_id": user.ID, + "username": user.Username, + "email": user.Email, + "name": user.Name, + } + h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) } - h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) + return } func (h Account) UpdatePassword(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index 37845318..39dc2cd7 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -17,7 +17,7 @@ type Rbac struct { func registerRouter() { r := Rbac{} - api.HandleAPIMethod(api.GET, "/permission/:type", m.PermissionRequired(r.ListPermission, enum.RoleRead...)) + api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAll...)) api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleRead...)) api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAll...)) @@ -55,10 +55,11 @@ func loadRolePermission() { biz.RolePermission = make(map[string][]string) biz.RolePermission["admin"] = enum.Admin + } func init() { registerRouter() - + loadJsonConfig() loadRolePermission() } From eeb1953837a87ffd7da7ada2be271c6980c5644f Mon Sep 17 00:00:00 2001 From: xushuhui Date: Sun, 24 Apr 2022 12:23:47 +0800 Subject: [PATCH 44/75] fix: (rbac) role --- internal/biz/account.go | 9 +++++---- internal/biz/context.go | 20 +++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index ecaaca87..49641446 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -97,19 +97,20 @@ func authorize(user Account) (m map[string]interface{}, err error) { if err != nil { return } - var roles []string + var roles, privilege []string for _, v := range user.Roles { roles = append(roles, v.Name) + r, _ := GetRole(v.Id) + privilege = append(privilege, r.Platform...) } + m = util.MapStr{ "access_token": tokenString, "username": user.Username, "id": user.ID, "expire_in": 86400, "roles": roles, - "privilege": []string{ - "system.user:all", "system.role:all", "system.cluster:all", "system.command:all", - }, + "privilege": privilege, } return } diff --git a/internal/biz/context.go b/internal/biz/context.go index d6f41808..1a190cc2 100644 --- a/internal/biz/context.go +++ b/internal/biz/context.go @@ -31,7 +31,13 @@ func NewEsContext(ctx context.Context, role EsRole) { //get user es role } -func ValidateEsPermission(req, userRole EsRole) (err error) { + +type EsRequest struct { + Cluster []string `json:"cluster"` + Index []string `json:"index"` +} + +func ValidateEsPermission(req EsRequest, userRole EsRole) (err error) { userClusterMap := make(map[string]struct{}) userIndexMap := make(map[string]struct{}) for _, v := range userRole.Cluster { @@ -43,12 +49,12 @@ func ValidateEsPermission(req, userRole EsRole) (err error) { } } - //for _, v := range req.Cluster { - // if _, ok := userClusterMap[v]; !ok { - // err = errors.New("no cluster permission") - // return - // } - //} + for _, v := range req.Cluster { + if _, ok := userClusterMap[v]; !ok { + err = errors.New("no cluster permission") + return + } + } //for _, v := range req.Index { // if _, ok := userClusterMap[v]; !ok { // err = errors.New("no index permission") From 0a3aed312c418bbf8ea778c09904bff63a1b014c Mon Sep 17 00:00:00 2001 From: xushuhui Date: Sun, 24 Apr 2022 14:09:56 +0800 Subject: [PATCH 45/75] fix: (rbac) admin privilege --- internal/biz/account.go | 16 ++++++++++++---- internal/biz/enum/const.go | 4 +++- internal/biz/permission.go | 3 ++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index 49641446..d07b4113 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -6,6 +6,7 @@ import ( "github.com/golang-jwt/jwt" "github.com/mitchellh/mapstructure" "golang.org/x/crypto/bcrypt" + "infini.sh/console/internal/biz/enum" "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" "infini.sh/framework/core/event" @@ -98,10 +99,17 @@ func authorize(user Account) (m map[string]interface{}, err error) { return } var roles, privilege []string - for _, v := range user.Roles { - roles = append(roles, v.Name) - r, _ := GetRole(v.Id) - privilege = append(privilege, r.Platform...) + if user.Username == "admin" { + roles = append(roles, "admin") + privilege = append(privilege, enum.AdminPrivilege...) + } else { + for _, v := range user.Roles { + roles = append(roles, v.Name) + + r, _ := GetRole(v.Id) + + privilege = append(privilege, r.Platform...) + } } m = util.MapStr{ diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 1ca72c11..ea0ea393 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -13,7 +13,9 @@ var RuleAll = []string{"rule::read", "rule::write"} var InstanceRead = []string{"instance::read"} var InstanceAll = []string{"instance::read", "instance::write"} - +var AdminPrivilege = []string{ + "role::read", "role::all", "user::read", "user::all", +} var Admin []string var BuildRoles = make(map[string]map[string]interface{}, 0) diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 6128d4ad..62880ee9 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -7,7 +7,8 @@ var RolePermission = make(map[string][]string) var EsRolePermission = make(map[string]EsRole) type EsRole struct { - Cluster []struct { + Platform []string `json:"platform"` + Cluster []struct { Id string `json:"id"` Name string `json:"name"` } `json:"cluster,omitempty"` From a17d562c53d78fa1fbba18fe84de9b1a63db086e Mon Sep 17 00:00:00 2001 From: xushuhui Date: Sun, 24 Apr 2022 14:18:34 +0800 Subject: [PATCH 46/75] fix: (rbac) role --- internal/biz/enum/const.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index ea0ea393..f4b6a2ff 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -14,7 +14,7 @@ var RuleAll = []string{"rule::read", "rule::write"} var InstanceRead = []string{"instance::read"} var InstanceAll = []string{"instance::read", "instance::write"} var AdminPrivilege = []string{ - "role::read", "role::all", "user::read", "user::all", + "system.role:read", "system.role:all", "system.user:read", "system.user:all", } var Admin []string var BuildRoles = make(map[string]map[string]interface{}, 0) From 28f360eaf93390da1338a30b4a637812f3b55f99 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Sun, 24 Apr 2022 16:28:12 +0800 Subject: [PATCH 47/75] fix: (rbac) batch query index --- plugin/api/index_management/index.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugin/api/index_management/index.go b/plugin/api/index_management/index.go index 3c0be5e6..6c659afd 100644 --- a/plugin/api/index_management/index.go +++ b/plugin/api/index_management/index.go @@ -123,7 +123,12 @@ func (h APIHandler) ListIndex(w http.ResponseWriter, req *http.Request, ps httpr keyword := h.GetParameterOrDefault(req, "keyword", "") ids := strings.Split(clusterIds, ",") for i := range ids { - ids[i] = `"` + ids[i] + `"` + if i < len(ids)-1 { + ids[i] = `"` + ids[i] + `",` + } else { + ids[i] = `"` + ids[i] + `"` + } + } if len(ids) == 0 { h.Error400(w, "id is required") From e8b57f369a6d8ef81c959f8b613c07d6cfc5c9c2 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Sun, 24 Apr 2022 18:53:39 +0800 Subject: [PATCH 48/75] fix: (rbac) role update --- internal/biz/account.go | 6 +-- internal/biz/context.go | 50 +++++++++++++++--------- internal/biz/enum/const.go | 33 ++++++++++++---- internal/biz/permission.go | 10 +++-- internal/biz/role.go | 76 ++++++++++++++++++++++++++++++++++++- internal/dto/role.go | 17 ++++----- internal/middleware/user.go | 14 +++---- plugin/api/rbac/api.go | 12 +++++- plugin/api/rbac/role.go | 24 +++++++----- 9 files changed, 181 insertions(+), 61 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index d07b4113..e2a91213 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -225,17 +225,17 @@ func ValidatePermission(claims *UserClaims, permissions []string) (err error) { err = errors.New("api permission is empty") return } - + return nil // 权限校验 userPermissionMap := make(map[string]struct{}) for _, role := range reqUser.Roles { if _, ok := RolePermission[role]; ok { - for _, v := range RolePermission[role] { + for _, v := range RolePermission[role].Platform { userPermissionMap[v] = struct{}{} } } } - + //all=>read var count int for _, v := range permissions { if _, ok := userPermissionMap[v]; ok { diff --git a/internal/biz/context.go b/internal/biz/context.go index 1a190cc2..e2b595e6 100644 --- a/internal/biz/context.go +++ b/internal/biz/context.go @@ -3,6 +3,8 @@ package biz import ( "context" "errors" + httprouter "infini.sh/framework/core/api/router" + "net/http" ) const ctxUserKey = "user" @@ -22,27 +24,38 @@ func FromUserContext(ctx context.Context) (*User, error) { return reqUser.User, nil } -//type EsRole struct { -// Cluster []string `json:"cluster,omitempty"` -// Index []string `json:"index,omitempty"` -//} - -func NewEsContext(ctx context.Context, role EsRole) { - //get user es role - -} - type EsRequest struct { + Method string `json:"method"` Cluster []string `json:"cluster"` - Index []string `json:"index"` + + Index []string `json:"index"` + Doc string `json:"doc"` + Path string `json:"path"` } -func ValidateEsPermission(req EsRequest, userRole EsRole) (err error) { +func NewEsRequest(r *http.Request, ps httprouter.Params) EsRequest { + + //GET elasticsearch/c6dgjtgvi076f32oibj0/index/test/_mappings + clusterId := ps.ByName("id") + index := ps.ByName("index") + + doc := ps.ByName("docId") + //如果index存在,说明调用的是index api + return EsRequest{ + Cluster: []string{clusterId}, + Index: []string{index}, + Doc: doc, + Path: r.URL.Path, + Method: r.Method, + } +} +func ValidateEsPermission(req EsRequest, userRole Role) (err error) { userClusterMap := make(map[string]struct{}) userIndexMap := make(map[string]struct{}) for _, v := range userRole.Cluster { userClusterMap[v.Id] = struct{}{} } + //todo 启动内存 for _, val := range userRole.Index { for _, v := range val.Name { userIndexMap[v] = struct{}{} @@ -55,11 +68,12 @@ func ValidateEsPermission(req EsRequest, userRole EsRole) (err error) { return } } - //for _, v := range req.Index { - // if _, ok := userClusterMap[v]; !ok { - // err = errors.New("no index permission") - // return - // } - //} + for _, v := range req.Index { + if _, ok := userIndexMap[v]; !ok { + err = errors.New("no index permission") + return + } + } + return } diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index f4b6a2ff..45da1796 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -1,12 +1,14 @@ package enum -import "time" +import ( + "time" +) -var UserRead = []string{"user::read"} -var UserAll = []string{"user::read", "user::write"} +var UserRead = []string{"system.user:read"} +var UserAll = []string{"system.user:all"} -var RoleRead = []string{"role::read"} -var RoleAll = []string{"role::read", "role::write"} +var RoleRead = []string{"system.role:read"} +var RoleAll = []string{"system.role:all"} var RuleRead = []string{"rule::read"} var RuleAll = []string{"rule::read", "rule::write"} @@ -16,12 +18,27 @@ var InstanceAll = []string{"instance::read", "instance::write"} var AdminPrivilege = []string{ "system.role:read", "system.role:all", "system.user:read", "system.user:all", } -var Admin []string + +type Role struct { + Platform []string `json:"platform,omitempty"` + Cluster []struct { + Id string `json:"id"` + Name string `json:"name"` + } `json:"cluster,omitempty"` + ClusterPrivilege []map[string][]string `json:"cluster_privilege,omitempty"` + Index []struct { + Name []string `json:"name"` + Privilege []string `json:"privilege"` + } `json:"index,omitempty"` +} + +var Admin Role var BuildRoles = make(map[string]map[string]interface{}, 0) func init() { - Admin = append(Admin, UserAll...) - Admin = append(Admin, RoleAll...) + Admin = Role{ + Platform: AdminPrivilege, + } UserMenu := Menu{ Id: "system_user", diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 62880ee9..6619be5c 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -1,13 +1,15 @@ package biz +import "infini.sh/console/internal/biz/enum" + var ClusterApis = make(map[string][]string) var IndexApis = make([]string, 0) -var RolePermission = make(map[string][]string) -var EsRolePermission = make(map[string]EsRole) +var RolePermission = make(map[string]enum.Role) +var EsApiMap = make(map[string]string) -type EsRole struct { - Platform []string `json:"platform"` +type Role struct { + Platform []string `json:"platform,omitempty"` Cluster []struct { Id string `json:"id"` Name string `json:"name"` diff --git a/internal/biz/role.go b/internal/biz/role.go index 069b0780..1d6dbbe6 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -23,6 +23,7 @@ const ( type IRole interface { ListPermission() interface{} Create(localUser *User) (id string, err error) + Update(localUser *User, id string) (err error) //Delete(localUser *User, id string) (err error) } type ConsoleRole struct { @@ -59,7 +60,79 @@ func NewRole(typ string) (r IRole, err error) { } return } +func (role ConsoleRole) Update(localUser *User, id string) (err error) { + model := rbac.Role{} + model.ID = id + _, err = orm.Get(&model) + if err != nil { + err = ErrNotFound + return + } + changeLog, _ := util.DiffTwoObject(model, role) + model.Description = role.Description + model.Platform = role.Platform + model.Updated = time.Now() + err = orm.Save(model) + if err != nil { + return + } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "role", + Type: "update", + Labels: util.MapStr{ + "id": id, + "description": model.Description, + "platform": model.Platform, + "updated": model.Updated, + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, nil, changeLog)) + + return +} +func (role ElasticsearchRole) Update(localUser *User, id string) (err error) { + model := rbac.Role{} + model.ID = id + _, err = orm.Get(&model) + if err != nil { + err = ErrNotFound + return + } + changeLog, _ := util.DiffTwoObject(model, role) + model.Description = role.Description + model.Cluster = role.Cluster + model.Index = role.Index + model.ClusterPrivilege = role.ClusterPrivilege + model.Updated = time.Now() + err = orm.Save(model) + if err != nil { + return + } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "role", + Type: "update", + Labels: util.MapStr{ + "id": id, + "description": model.Description, + "platform": model.Platform, + "updated": model.Updated, + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, nil, changeLog)) + + return +} func (role ConsoleRole) Create(localUser *User) (id string, err error) { if _, ok := enum.BuildRoles[role.Name]; ok { err = fmt.Errorf("role name %s already exists", role.Name) @@ -213,7 +286,7 @@ func DeleteRole(localUser *User, id string) (err error) { return } -func UpdateRole(localUser *User, id string, req dto.UpdateConsoleRole) (err error) { +func UpdateRole(localUser *User, id string, req dto.UpdateRole) (err error) { role := rbac.Role{} role.ID = id _, err = orm.Get(&role) @@ -224,6 +297,7 @@ func UpdateRole(localUser *User, id string, req dto.UpdateConsoleRole) (err erro changeLog, _ := util.DiffTwoObject(role, req) role.Description = req.Description role.Platform = req.Platform + role.Updated = time.Now() err = orm.Save(role) if err != nil { diff --git a/internal/dto/role.go b/internal/dto/role.go index 9ab2e858..a1754213 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -9,16 +9,15 @@ type Menu struct { Name string `json:"name"` Privilege string `json:"privilege"` } -type UpdateConsoleRole struct { - Description string `json:"description" ` - Platform []string `json:"platform"` -} -type CreateEsRole struct { - Name string `json:"name"` - Description string `json:"description" ` - RoleType string `json:"type" ` - Permission ElasticsearchPermission `json:"permission"` +type UpdateRole struct { + Description string `json:"description" ` + Platform []string `json:"platform"` + Cluster []string `json:"cluster" ` + Index []string `json:"index" ` + ClusterPrivilege []string `json:"cluster_privilege" ` + IndexPrivilege []string `json:"index_privilege" ` } + type ElasticsearchPermission struct { Cluster []string `json:"cluster" ` Index []string `json:"index" ` diff --git a/internal/middleware/user.go b/internal/middleware/user.go index fdfcf589..a904cc97 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -19,16 +19,16 @@ func LoginRequired(h httprouter.Handle) httprouter.Handle { h(w, r, ps) } } -func EsPermissionReqired(h httprouter.Handle) httprouter.Handle { +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 - } - r = r.WithContext(biz.NewUserContext(r.Context(), claims)) + //req := biz.NewEsRequest(r, ps) + //err := biz.ValidateEsPermission(req) + //if err != nil { + // w = handleError(w, http.StatusForbidden, err) + // return + //} h(w, r, ps) } } diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index 39dc2cd7..c74ffd74 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -49,10 +49,20 @@ func loadJsonConfig() { biz.IndexApis = apis["indices"] delete(apis, "indices") biz.ClusterApis = apis + bytes, err = util.FileGetContent(path.Join(pwd, "/config/map.json")) + if err != nil { + panic("load json file err " + err.Error()) + + } + + err = json.Unmarshal(bytes, &biz.EsApiMap) + if err != nil { + panic("json config unmarshal err " + err.Error()) + } } func loadRolePermission() { - biz.RolePermission = make(map[string][]string) + biz.RolePermission = make(map[string]enum.Role) biz.RolePermission["admin"] = enum.Admin diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 92657cfa..ab5d8253 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -5,7 +5,6 @@ import ( "infini.sh/console/internal/biz" "infini.sh/console/internal/biz/enum" "infini.sh/console/internal/core" - "infini.sh/console/internal/dto" httprouter "infini.sh/framework/core/api/router" "infini.sh/framework/core/elastic" "infini.sh/framework/core/util" @@ -14,11 +13,7 @@ import ( func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { roleType := ps.MustGetParameter("type") - err := biz.IsAllowRoleType(roleType) - if err != nil { - h.Error400(w, err.Error()) - return - } + localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) @@ -125,20 +120,29 @@ func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.P func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") - - var req dto.UpdateConsoleRole - err := h.DecodeJSON(r, &req) + model, err := biz.GetRole(id) if err != nil { h.Error(w, err) return } + irole, err := biz.NewRole(model.RoleType) + if err != nil { + h.Error(w, err) + return + } + + err = h.DecodeJSON(r, &irole) + if err != nil { + h.Error400(w, err.Error()) + return + } localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) h.Error(w, err) return } - err = biz.UpdateRole(localUser, id, req) + err = irole.Update(localUser, id) if err != nil { _ = log.Error(err.Error()) From 2593d453e9866f93bc843977a3bfe8fe0ce6cccb Mon Sep 17 00:00:00 2001 From: xushuhui Date: Mon, 25 Apr 2022 10:24:05 +0800 Subject: [PATCH 49/75] fix: (rbac) login set role map --- internal/biz/account.go | 52 +++++++++++++++++++++++++---------------- plugin/api/rbac/api.go | 1 + 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index e2a91213..cfe7cd15 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -83,21 +83,7 @@ func authenticateAdmin(username string, password string) (user Account, err erro return user, nil } func authorize(user Account) (m map[string]interface{}, err error) { - token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims{ - User: &User{ - Username: user.Username, - UserId: user.ID, - Roles: []string{"admin"}, - }, - RegisteredClaims: &jwt.RegisteredClaims{ - ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), - }, - }) - tokenString, err := token.SignedString([]byte(Secret)) - if err != nil { - return - } var roles, privilege []string if user.Username == "admin" { roles = append(roles, "admin") @@ -109,9 +95,29 @@ func authorize(user Account) (m map[string]interface{}, err error) { r, _ := GetRole(v.Id) privilege = append(privilege, r.Platform...) + RolePermission[v.Name] = enum.Role{ + Platform: r.Platform, + Cluster: r.Cluster, + ClusterPrivilege: r.ClusterPrivilege, + Index: r.Index, + } } } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims{ + User: &User{ + Username: user.Username, + UserId: user.ID, + Roles: roles, + }, + RegisteredClaims: &jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), + }, + }) + tokenString, err := token.SignedString([]byte(Secret)) + if err != nil { + return + } m = util.MapStr{ "access_token": tokenString, "username": user.Username, @@ -215,27 +221,33 @@ func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { } func ValidatePermission(claims *UserClaims, permissions []string) (err error) { - reqUser := claims.User + user := claims.User - if reqUser.UserId == "" { + if user.UserId == "" { err = errors.New("user id is empty") return } - if reqUser.Roles == nil { + if user.Roles == nil { err = errors.New("api permission is empty") return } - return nil + // 权限校验 userPermissionMap := make(map[string]struct{}) - for _, role := range reqUser.Roles { + for _, role := range user.Roles { if _, ok := RolePermission[role]; ok { for _, v := range RolePermission[role].Platform { + userPermissionMap[v] = struct{}{} + //all include read + if strings.Contains(v, "all") { + key := v[:len(v)-3] + "read" + userPermissionMap[key] = struct{}{} + } } } } - //all=>read + var count int for _, v := range permissions { if _, ok := userPermissionMap[v]; ok { diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index c74ffd74..7abc09f5 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -73,6 +73,7 @@ func init() { loadRolePermission() } + func existInternalUser() { //user, err := biz.GetUser("admin") //if errors.Is(err, elastic.ErrNotFound) { From d09dda93e344ab4d6faabb32079b7e0d39f6e0af Mon Sep 17 00:00:00 2001 From: xushuhui Date: Mon, 25 Apr 2022 10:41:54 +0800 Subject: [PATCH 50/75] fix: (rbac) role --- config/map.json | 271 ++++++++++++++++++++++++++++++++++++++++ main.go | 9 +- plugin/api/rbac/api.go | 26 ++-- plugin/api/rbac/role.go | 15 +-- 4 files changed, 296 insertions(+), 25 deletions(-) create mode 100644 config/map.json diff --git a/config/map.json b/config/map.json new file mode 100644 index 00000000..4a9d3a34 --- /dev/null +++ b/config/map.json @@ -0,0 +1,271 @@ +{ + "DELETE/_ingest/pipeline/:id": "ingest.delete_pipeline", + "DELETE/_scripts/:id": "delete_script", + "DELETE/_search/scroll": "clear_scroll", + "DELETE/_search/scroll/:scroll_id": "clear_scroll", + "DELETE/_snapshot/:repository": "snapshot.delete_repository", + "DELETE/_snapshot/:repository/:snapshot": "snapshot.delete", + "DELETE/_template/:name": "indices.delete_template", + "DELETE/:index": "indices.delete", + "DELETE/:index/_alias/:name": "indices.delete_alias", + "DELETE/:index/_aliases/:name": "indices.delete_alias", + "DELETE/:index/_doc/:id": "delete", + + "GET/": "info", + "GET/_alias": "indices.get_alias", + "GET/_alias/:name": "indices.get_alias", + "GET/_analyze": "indices.analyze", + "GET/_cat": "cat.help", + "GET/_cat/aliases": "cat.aliases", + "GET/_cat/aliases/:name": "cat.aliases", + "GET/_cat/allocation": "cat.allocation", + "GET/_cat/allocation/:node_id": "cat.allocation", + "GET/_cat/count": "cat.count", + "GET/_cat/count/:index": "cat.count", + "GET/_cat/fielddata": "cat.fielddata", + "GET/_cat/fielddata/:fields": "cat.fielddata", + "GET/_cat/health": "cat.health", + "GET/_cat/indices": "cat.indices", + "GET/_cat/indices/:index": "cat.indices", + "GET/_cat/master": "cat.master", + "GET/_cat/nodeattrs": "cat.nodeattrs", + "GET/_cat/nodes": "cat.nodes", + "GET/_cat/pending_tasks": "cat.pending_tasks", + "GET/_cat/plugins": "cat.plugins", + "GET/_cat/recovery": "cat.recovery", + "GET/_cat/recovery/:index": "cat.recovery", + "GET/_cat/repositories": "cat.repositories", + "GET/_cat/segments": "cat.segments", + "GET/_cat/segments/:index": "cat.segments", + "GET/_cat/shards": "cat.shards", + "GET/_cat/shards/:index": "cat.shards", + "GET/_cat/snapshots": "cat.snapshots", + "GET/_cat/snapshots/:repository": "cat.snapshots", + "GET/_cat/tasks": "cat.tasks", + "GET/_cat/templates": "cat.templates", + "GET/_cat/templates/:name": "cat.templates", + "GET/_cat/thread_pool": "cat.thread_pool", + "GET/_cat/thread_pool/:thread_pool_patterns": "cat.thread_pool", + "GET/_cluster/allocation/explain": "cluster.allocation_explain", + "GET/_cluster/health": "cluster.health", + "GET/_cluster/health/:index": "cluster.health", + "GET/_cluster/nodes/hot_threads": "nodes.hot_threads", + "GET/_cluster/nodes/hotthreads": "nodes.hot_threads", + "GET/_cluster/nodes/:node_id/hot_threads": "nodes.hot_threads", + "GET/_cluster/nodes/:node_id/hotthreads": "nodes.hot_threads", + "GET/_cluster/pending_tasks": "cluster.pending_tasks", + "GET/_cluster/settings": "cluster.get_settings", + "GET/_cluster/state": "cluster.state", + "GET/_cluster/state/:metric": "cluster.state", + "GET/_cluster/state/:metric/:index": "cluster.state", + "GET/_cluster/stats": "cluster.stats", + "GET/_cluster/stats/nodes/:node_id": "cluster.stats", + "GET/_count": "count", + "GET/_field_caps": "field_caps", + "GET/_flush": "indices.flush", + "GET/_flush/synced": "indices.flush_synced", + "GET/_ingest/pipeline": "ingest.get_pipeline", + "GET/_ingest/pipeline/_simulate": "ingest.simulate", + "GET/_ingest/pipeline/:id": "ingest.get_pipeline", + "GET/_ingest/pipeline/:id/_simulate": "ingest.simulate", + "GET/_ingest/processor/grok": "ingest.processor_grok", + "GET/_mapping": "indices.get_mapping", + + "GET/_mapping/:index": "indices.get_mapping", + "GET/_mapping/:index/field/:fields": "indices.get_field_mapping", + "GET/_mget": "mget", + "GET/_msearch": "msearch", + "GET/_msearch/template": "msearch_template", + "GET/_mtermvectors": "mtermvectors", + "GET/_nodes": "nodes.info", + "GET/_nodes/hot_threads": "nodes.hot_threads", + "GET/_nodes/hotthreads": "nodes.hot_threads", + "GET/_nodes/stats": "nodes.stats", + "GET/_nodes/stats/:metric": "nodes.stats", + "GET/_nodes/stats/:metric/:index_metric": "nodes.stats", + "GET/_nodes/usage": "nodes.usage", + "GET/_nodes/usage/:metric": "nodes.usage", + "GET/_nodes/:metric": "nodes.info", + "GET/_nodes/:node_id": "nodes.info", + "GET/_nodes/:node_id/hot_threads": "nodes.hot_threads", + "GET/_nodes/:node_id/hotthreads": "nodes.hot_threads", + "GET/_nodes/:node_id/stats": "nodes.stats", + "GET/_nodes/:node_id/stats/:metric": "nodes.stats", + "GET/_nodes/:node_id/stats/:metric/:index_metric": "nodes.stats", + "GET/_nodes/:node_id/usage": "nodes.usage", + "GET/_nodes/:node_id/usage/:metric": "nodes.usage", + "GET/_nodes/:node_id/:metric": "nodes.info", + "GET/_rank_eval": "rank_eval", + "GET/_recovery": "indices.recovery", + "GET/_refresh": "indices.refresh", + "GET/_remote/info": "cluster.remote_info", + "GET/_render/template": "render_search_template", + "GET/_render/template/:id": "render_search_template", + "GET/_scripts/painless/_execute": "scripts_painless_execute", + "GET/_scripts/:id": "get_script", + "GET/_search": "search", + "GET/_search/scroll": "scroll", + "GET/_search/scroll/:scroll_id": "scroll", + "GET/_search/template": "search_template", + "GET/_search_shards": "search_shards", + "GET/_segments": "indices.segments", + "GET/_settings": "indices.get_settings", + "GET/_settings/:name": "indices.get_settings", + "GET/_shard_stores": "indices.shard_stores", + "GET/_snapshot": "snapshot.get_repository", + "GET/_snapshot/_status": "snapshot.status", + "GET/_snapshot/:repository": "snapshot.get_repository", + "GET/_snapshot/:repository/_status": "snapshot.status", + "GET/_snapshot/:repository/:snapshot": "snapshot.get", + "GET/_snapshot/:repository/:snapshot/_status": "snapshot.status", + "GET/_stats": "indices.stats", + "GET/_stats/:metric": "indices.stats", + "GET/_tasks": "tasks.list", + "GET/_tasks/:task_id": "tasks.get", + "GET/_template": "indices.get_template", + "GET/_template/:name": "indices.get_template", + "GET/_upgrade": "indices.get_upgrade", + "GET/_validate/query": "indices.validate_query", + "GET/:index": "indices.get", + "GET/:index/_alias": "indices.get_alias", + "GET/:index/_alias/:name": "indices.get_alias", + "GET/:index/_analyze": "indices.analyze", + "GET/:index/_count": "count", + "GET/:index/_doc/:id": "get", + "GET/:index/_field_caps": "field_caps", + "GET/:index/_flush": "indices.flush", + "GET/:index/_flush/synced": "indices.flush_synced", + "GET/:index/_mapping": "indices.get_mapping", + "GET/:index/_mapping/field/:fields": "indices.get_field_mapping", + + "GET/:index/_mget": "mget", + "GET/:index/_msearch": "msearch", + "GET/:index/_msearch/template": "msearch_template", + "GET/:index/_mtermvectors": "mtermvectors", + "GET/:index/_rank_eval": "rank_eval", + "GET/:index/_recovery": "indices.recovery", + "GET/:index/_refresh": "indices.refresh", + "GET/:index/_search": "search", + "GET/:index/_search/template": "search_template", + "GET/:index/_search_shards": "search_shards", + "GET/:index/_segments": "indices.segments", + "GET/:index/_settings": "indices.get_settings", + "GET/:index/_settings/:name": "indices.get_settings", + "GET/:index/_shard_stores": "indices.shard_stores", + "GET/:index/_stats": "indices.stats", + "GET/:index/_stats/:metric": "indices.stats", + "GET/:index/_upgrade": "indices.get_upgrade", + "GET/:index/_validate/query": "indices.validate_query", + + "HEAD/": "info", + "HEAD/_alias/:name": "indices.exists_alias", + "HEAD/_template/:name": "indices.exists_template", + "HEAD/:index": "indices.exists", + "HEAD/:index/_alias/:name": "indices.exists_alias", + + + "POST/_aliases": "indices.update_aliases", + "POST/_analyze": "indices.analyze", + "POST/_bulk": "bulk", + "POST/_cache/clear": "indices.clear_cache", + "POST/_cluster/allocation/explain": "cluster.allocation_explain", + "POST/_cluster/reroute": "cluster.reroute", + "POST/_count": "count", + "POST/_delete_by_query/:task_id/_rethrottle": "reindex_rethrottle", + "POST/_field_caps": "field_caps", + "POST/_flush": "indices.flush", + "POST/_flush/synced": "indices.flush_synced", + "POST/_forcemerge": "indices.forcemerge", + "POST/_ingest/pipeline/_simulate": "ingest.simulate", + "POST/_ingest/pipeline/:id/_simulate": "ingest.simulate", + + "POST/_mget": "mget", + "POST/_msearch": "msearch", + "POST/_msearch/template": "msearch_template", + "POST/_mtermvectors": "mtermvectors", + "POST/_nodes/reload_secure_settings": "nodes.reload_secure_settings", + "POST/_nodes/:node_id/reload_secure_settings": "nodes.reload_secure_settings", + "POST/_rank_eval": "rank_eval", + "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/_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/_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", + "POST/_snapshot/:repository/:snapshot/_restore": "snapshot.restore", + "POST/_tasks/_cancel": "tasks.cancel", + "POST/_tasks/:task_id/_cancel": "tasks.cancel", + "POST/_template/:name": "indices.put_template", + "POST/_update_by_query/:task_id/_rethrottle": "reindex_rethrottle", + "POST/_upgrade": "indices.upgrade", + "POST/_validate/query": "indices.validate_query", + "POST/:alias/_rollover": "indices.rollover", + "POST/:alias/_rollover/:new_index": "indices.rollover", + "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/_cache/clear": "indices.clear_cache", + "POST/:index/_close": "indices.close", + "POST/:index/_count": "count", + "POST/:index/_delete_by_query": "delete_by_query", + "POST/:index/_doc": "index", + "POST/:index/_doc/:id": "index", + "POST/:index/_doc/:id/_update": "update", + "POST/:index/_field_caps": "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/_open": "indices.open", + "POST/:index/_rank_eval": "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/_shrink/:target": "indices.shrink", + "POST/:index/_split/:target": "indices.split", + "POST/:index/_update_by_query": "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/_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/_snapshot/:repository": "snapshot.create_repository", + "PUT/_snapshot/:repository/:snapshot": "snapshot.create", + "PUT/_template/:name": "indices.put_template", + "PUT/:index": "indices.create", + "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/_settings": "indices.put_settings", + "PUT/:index/_shrink/:target": "indices.shrink", + "PUT/:index/_split/:target": "indices.split", + + "PUT:index/_mapping": "indices.put_mapping", + "PUT:index/_mappings": "indices.put_mapping" +} \ No newline at end of file diff --git a/main.go b/main.go index 8962147b..2ae5dca2 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "infini.sh/console/model/gateway" "infini.sh/console/model/rbac" _ "infini.sh/console/plugin" + rbacApi "infini.sh/console/plugin/api/rbac" alerting2 "infini.sh/console/service/alerting" "infini.sh/framework" "infini.sh/framework/core/elastic" @@ -52,7 +53,7 @@ func main() { terminalFooter := "" app := framework.NewApp("console", "INFINI Cloud Console, The easiest way to operate your own elasticsearch platform.", - config.Version,config.BuildNumber, config.LastCommitLog, config.BuildDate, config.EOLDate, terminalHeader, terminalFooter) + config.Version, config.BuildNumber, config.LastCommitLog, config.BuildDate, config.EOLDate, terminalHeader, terminalFooter) app.Init(nil) defer app.Shutdown() @@ -61,11 +62,10 @@ func main() { if app.Setup(func() { err := bootstrapRequirementCheck() - if err !=nil{ + if err != nil { panic(err) } - //load core modules first module.RegisterSystemModule(&elastic2.ElasticModule{}) module.RegisterSystemModule(&filter.FilterModule{}) @@ -120,7 +120,6 @@ func main() { module.Start() - orm.RegisterSchemaWithIndexName(model.Dict{}, "dict") orm.RegisterSchemaWithIndexName(model.Reindex{}, "reindex") orm.RegisterSchemaWithIndexName(elastic.View{}, "view") @@ -139,7 +138,9 @@ func main() { if err != nil { log.Errorf("init alerting task error: %v", err) } + rbacApi.Init() }() + }, nil) { app.Run() } diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index 7abc09f5..45a4eee9 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -15,7 +15,7 @@ type Rbac struct { api.Handler } -func registerRouter() { +func init() { r := Rbac{} api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAll...)) @@ -49,16 +49,16 @@ func loadJsonConfig() { biz.IndexApis = apis["indices"] delete(apis, "indices") biz.ClusterApis = apis - bytes, err = util.FileGetContent(path.Join(pwd, "/config/map.json")) - if err != nil { - panic("load json file err " + err.Error()) - - } - - err = json.Unmarshal(bytes, &biz.EsApiMap) - if err != nil { - panic("json config unmarshal err " + err.Error()) - } + //bytes, err = util.FileGetContent(path.Join(pwd, "/config/map.json")) + //if err != nil { + // panic("load json file err " + err.Error()) + // + //} + // + //err = json.Unmarshal(bytes, &biz.EsApiMap) + //if err != nil { + // panic("json config unmarshal err " + err.Error()) + //} } func loadRolePermission() { @@ -67,11 +67,9 @@ func loadRolePermission() { biz.RolePermission["admin"] = enum.Admin } -func init() { - registerRouter() +func Init() { loadJsonConfig() loadRolePermission() - } func existInternalUser() { diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index ab5d8253..267f14b3 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -120,6 +120,12 @@ func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.P func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") + localUser, err := biz.FromUserContext(r.Context()) + if err != nil { + log.Error(err.Error()) + h.Error(w, err) + return + } model, err := biz.GetRole(id) if err != nil { h.Error(w, err) @@ -136,13 +142,8 @@ func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error400(w, err.Error()) return } - localUser, err := biz.FromUserContext(r.Context()) - if err != nil { - log.Error(err.Error()) - h.Error(w, err) - return - } - err = irole.Update(localUser, id) + + err = irole.Update(localUser, model) if err != nil { _ = log.Error(err.Error()) From fcd2eb0073a238547bf81cef828a4c92793ddbdd Mon Sep 17 00:00:00 2001 From: xushuhui Date: Mon, 25 Apr 2022 10:46:26 +0800 Subject: [PATCH 51/75] fix: (rbac) role --- internal/biz/role.go | 62 +++++--------------------------------------- main.go | 3 +-- 2 files changed, 8 insertions(+), 57 deletions(-) diff --git a/internal/biz/role.go b/internal/biz/role.go index 1d6dbbe6..05bd64fb 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -3,7 +3,6 @@ package biz import ( "fmt" "infini.sh/console/internal/biz/enum" - "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" "infini.sh/framework/core/event" "infini.sh/framework/core/orm" @@ -23,7 +22,7 @@ const ( type IRole interface { ListPermission() interface{} Create(localUser *User) (id string, err error) - Update(localUser *User, id string) (err error) + Update(localUser *User, model rbac.Role) (err error) //Delete(localUser *User, id string) (err error) } type ConsoleRole struct { @@ -60,14 +59,8 @@ func NewRole(typ string) (r IRole, err error) { } return } -func (role ConsoleRole) Update(localUser *User, id string) (err error) { - model := rbac.Role{} - model.ID = id - _, err = orm.Get(&model) - if err != nil { - err = ErrNotFound - return - } +func (role ConsoleRole) Update(localUser *User, model rbac.Role) (err error) { + changeLog, _ := util.DiffTwoObject(model, role) model.Description = role.Description model.Platform = role.Platform @@ -83,7 +76,7 @@ func (role ConsoleRole) Update(localUser *User, id string) (err error) { Name: "role", Type: "update", Labels: util.MapStr{ - "id": id, + "id": model.ID, "description": model.Description, "platform": model.Platform, "updated": model.Updated, @@ -96,14 +89,8 @@ func (role ConsoleRole) Update(localUser *User, id string) (err error) { return } -func (role ElasticsearchRole) Update(localUser *User, id string) (err error) { - model := rbac.Role{} - model.ID = id - _, err = orm.Get(&model) - if err != nil { - err = ErrNotFound - return - } +func (role ElasticsearchRole) Update(localUser *User, model rbac.Role) (err error) { + changeLog, _ := util.DiffTwoObject(model, role) model.Description = role.Description model.Cluster = role.Cluster @@ -120,7 +107,7 @@ func (role ElasticsearchRole) Update(localUser *User, id string) (err error) { Name: "role", Type: "update", Labels: util.MapStr{ - "id": id, + "id": model.ID, "description": model.Description, "platform": model.Platform, "updated": model.Updated, @@ -286,41 +273,6 @@ func DeleteRole(localUser *User, id string) (err error) { return } -func UpdateRole(localUser *User, id string, req dto.UpdateRole) (err error) { - role := rbac.Role{} - role.ID = id - _, err = orm.Get(&role) - if err != nil { - err = ErrNotFound - return - } - changeLog, _ := util.DiffTwoObject(role, req) - role.Description = req.Description - role.Platform = req.Platform - - role.Updated = time.Now() - err = orm.Save(role) - if err != nil { - return - } - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "role", - Type: "update", - Labels: util.MapStr{ - "id": id, - "description": role.Description, - "platform": role.Platform, - "updated": role.Updated, - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, nil, changeLog)) - return -} func GetRole(id string) (role rbac.Role, err error) { role.ID = id diff --git a/main.go b/main.go index 2ae5dca2..e08cec7b 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,6 @@ import ( "infini.sh/console/model/gateway" "infini.sh/console/model/rbac" _ "infini.sh/console/plugin" - rbacApi "infini.sh/console/plugin/api/rbac" alerting2 "infini.sh/console/service/alerting" "infini.sh/framework" "infini.sh/framework/core/elastic" @@ -138,7 +137,7 @@ func main() { if err != nil { log.Errorf("init alerting task error: %v", err) } - rbacApi.Init() + }() }, nil) { From 98db1cdff746cc96c713aea3e9f8db0690c0466c Mon Sep 17 00:00:00 2001 From: xushuhui Date: Mon, 25 Apr 2022 10:53:52 +0800 Subject: [PATCH 52/75] fix: (rbac) close permission --- internal/biz/account.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index cfe7cd15..98619ec1 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -231,7 +231,7 @@ func ValidatePermission(claims *UserClaims, permissions []string) (err error) { err = errors.New("api permission is empty") return } - + return nil // 权限校验 userPermissionMap := make(map[string]struct{}) for _, role := range user.Roles { From c000596e6626d4121a9c9eb141ae13b685e12ce2 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Mon, 25 Apr 2022 15:27:18 +0800 Subject: [PATCH 53/75] fix: (rbac) update user roles --- config/map.json | 513 +++++++++++++++++------------------ config/permission.json | 14 +- internal/biz/account.go | 8 +- internal/biz/context.go | 56 ---- internal/biz/enum/const.go | 41 +-- internal/biz/permission.go | 7 +- internal/biz/user.go | 9 + internal/biz/validate.go | 112 ++++++++ internal/core/router.go | 94 +++++++ internal/core/router_test.go | 79 ++++++ internal/core/trie.go | 83 ++++++ internal/dto/role.go | 10 +- internal/middleware/user.go | 20 +- main.go | 3 +- plugin/api/rbac/api.go | 72 ++--- 15 files changed, 706 insertions(+), 415 deletions(-) create mode 100644 internal/biz/validate.go create mode 100644 internal/core/router.go create mode 100644 internal/core/router_test.go create mode 100644 internal/core/trie.go diff --git a/config/map.json b/config/map.json index 4a9d3a34..c05ac5b3 100644 --- a/config/map.json +++ b/config/map.json @@ -1,271 +1,270 @@ { - "DELETE/_ingest/pipeline/:id": "ingest.delete_pipeline", - "DELETE/_scripts/:id": "delete_script", - "DELETE/_search/scroll": "clear_scroll", - "DELETE/_search/scroll/:scroll_id": "clear_scroll", - "DELETE/_snapshot/:repository": "snapshot.delete_repository", - "DELETE/_snapshot/:repository/:snapshot": "snapshot.delete", - "DELETE/_template/:name": "indices.delete_template", - "DELETE/:index": "indices.delete", - "DELETE/:index/_alias/:name": "indices.delete_alias", - "DELETE/:index/_aliases/:name": "indices.delete_alias", - "DELETE/:index/_doc/:id": "delete", + "DELETE-/_ingest/pipeline/:id": "ingest.delete_pipeline", + "DELETE-/_scripts/:id": "DELETE-_script", + "DELETE-/_search/scroll": "clear_scroll", + "DELETE-/_search/scroll/:scroll_id": "clear_scroll", + "DELETE-/_snapshot/:repository": "snapshot.delete_repository", + "DELETE-/_snapshot/:repository/:snapshot": "snapshot.delete", + "DELETE-/_template/:name": "indices.delete_template", + "DELETE-/:index": "indices.delete", + "DELETE-/:index/_alias/:name": "indices.delete_alias", + "DELETE-/:index/_aliases/:name": "indices.delete_alias", + "DELETE-/:index/_doc/:id": "doc.delete", - "GET/": "info", - "GET/_alias": "indices.get_alias", - "GET/_alias/:name": "indices.get_alias", - "GET/_analyze": "indices.analyze", - "GET/_cat": "cat.help", - "GET/_cat/aliases": "cat.aliases", - "GET/_cat/aliases/:name": "cat.aliases", - "GET/_cat/allocation": "cat.allocation", - "GET/_cat/allocation/:node_id": "cat.allocation", - "GET/_cat/count": "cat.count", - "GET/_cat/count/:index": "cat.count", - "GET/_cat/fielddata": "cat.fielddata", - "GET/_cat/fielddata/:fields": "cat.fielddata", - "GET/_cat/health": "cat.health", - "GET/_cat/indices": "cat.indices", - "GET/_cat/indices/:index": "cat.indices", - "GET/_cat/master": "cat.master", - "GET/_cat/nodeattrs": "cat.nodeattrs", - "GET/_cat/nodes": "cat.nodes", - "GET/_cat/pending_tasks": "cat.pending_tasks", - "GET/_cat/plugins": "cat.plugins", - "GET/_cat/recovery": "cat.recovery", - "GET/_cat/recovery/:index": "cat.recovery", - "GET/_cat/repositories": "cat.repositories", - "GET/_cat/segments": "cat.segments", - "GET/_cat/segments/:index": "cat.segments", - "GET/_cat/shards": "cat.shards", - "GET/_cat/shards/:index": "cat.shards", - "GET/_cat/snapshots": "cat.snapshots", - "GET/_cat/snapshots/:repository": "cat.snapshots", - "GET/_cat/tasks": "cat.tasks", - "GET/_cat/templates": "cat.templates", - "GET/_cat/templates/:name": "cat.templates", - "GET/_cat/thread_pool": "cat.thread_pool", - "GET/_cat/thread_pool/:thread_pool_patterns": "cat.thread_pool", - "GET/_cluster/allocation/explain": "cluster.allocation_explain", - "GET/_cluster/health": "cluster.health", - "GET/_cluster/health/:index": "cluster.health", - "GET/_cluster/nodes/hot_threads": "nodes.hot_threads", - "GET/_cluster/nodes/hotthreads": "nodes.hot_threads", - "GET/_cluster/nodes/:node_id/hot_threads": "nodes.hot_threads", - "GET/_cluster/nodes/:node_id/hotthreads": "nodes.hot_threads", - "GET/_cluster/pending_tasks": "cluster.pending_tasks", - "GET/_cluster/settings": "cluster.get_settings", - "GET/_cluster/state": "cluster.state", - "GET/_cluster/state/:metric": "cluster.state", - "GET/_cluster/state/:metric/:index": "cluster.state", - "GET/_cluster/stats": "cluster.stats", - "GET/_cluster/stats/nodes/:node_id": "cluster.stats", - "GET/_count": "count", - "GET/_field_caps": "field_caps", - "GET/_flush": "indices.flush", - "GET/_flush/synced": "indices.flush_synced", - "GET/_ingest/pipeline": "ingest.get_pipeline", - "GET/_ingest/pipeline/_simulate": "ingest.simulate", - "GET/_ingest/pipeline/:id": "ingest.get_pipeline", - "GET/_ingest/pipeline/:id/_simulate": "ingest.simulate", - "GET/_ingest/processor/grok": "ingest.processor_grok", - "GET/_mapping": "indices.get_mapping", + "GET-/": "info", + "GET-/_alias": "indices.get_alias", + "GET-/_alias/:name": "indices.get_alias", + "GET-/_analyze": "indices.analyze", + "GET-/_cat": "cat.help", + "GET-/_cat/aliases": "cat.aliases", + "GET-/_cat/aliases/:name": "cat.aliases", + "GET-/_cat/allocation": "cat.allocation", + "GET-/_cat/allocation/:node_id": "cat.allocation", + "GET-/_cat/count": "cat.count", + "GET-/_cat/count/:index": "cat.count", + "GET-/_cat/fielddata": "cat.fielddata", + "GET-/_cat/fielddata/:fields": "cat.fielddata", + "GET-/_cat/health": "cat.health", + "GET-/_cat/indices": "cat.indices", + "GET-/_cat/indices/:index": "cat.indices", + "GET-/_cat/master": "cat.master", + "GET-/_cat/nodeattrs": "cat.nodeattrs", + "GET-/_cat/nodes": "cat.nodes", + "GET-/_cat/pending_tasks": "cat.pending_tasks", + "GET-/_cat/plugins": "cat.plugins", + "GET-/_cat/recovery": "cat.recovery", + "GET-/_cat/recovery/:index": "cat.recovery", + "GET-/_cat/repositories": "cat.repositories", + "GET-/_cat/segments": "cat.segments", + "GET-/_cat/segments/:index": "cat.segments", + "GET-/_cat/shards": "cat.shards", + "GET-/_cat/shards/:index": "cat.shards", + "GET-/_cat/snapshots": "cat.snapshots", + "GET-/_cat/snapshots/:repository": "cat.snapshots", + "GET-/_cat/tasks": "cat.tasks", + "GET-/_cat/templates": "cat.templates", + "GET-/_cat/templates/:name": "cat.templates", + "GET-/_cat/thread_pool": "cat.thread_pool", + "GET-/_cat/thread_pool/:thread_pool_patterns": "cat.thread_pool", + "GET-/_cluster/allocation/explain": "cluster.allocation_explain", + "GET-/_cluster/health": "cluster.health", + "GET-/_cluster/health/:index": "cluster.health", + "GET-/_cluster/nodes/hot_threads": "nodes.hot_threads", + "GET-/_cluster/nodes/hotthreads": "nodes.hot_threads", + "GET-/_cluster/nodes/:node_id/hot_threads": "nodes.hot_threads", + "GET-/_cluster/nodes/:node_id/hotthreads": "nodes.hot_threads", + "GET-/_cluster/pending_tasks": "cluster.pending_tasks", + "GET-/_cluster/settings": "cluster.get_settings", + "GET-/_cluster/state": "cluster.state", + "GET-/_cluster/state/:metric": "cluster.state", + "GET-/_cluster/state/:metric/:index": "cluster.state", + "GET-/_cluster/stats": "cluster.stats", + "GET-/_cluster/stats/nodes/:node_id": "cluster.stats", + "GET-/_count": "count", + "GET-/_field_caps": "field_caps", + "GET-/_flush": "indices.flush", + "GET-/_flush/synced": "indices.flush_synced", + "GET-/_ingest/pipeline": "ingest.get_pipeline", + "GET-/_ingest/pipeline/_simulate": "ingest.simulate", + "GET-/_ingest/pipeline/:id": "ingest.get_pipeline", + "GET-/_ingest/pipeline/:id/_simulate": "ingest.simulate", + "GET-/_ingest/processor/grok": "ingest.processor_grok", + "GET-/_mapping": "indices.get_mapping", - "GET/_mapping/:index": "indices.get_mapping", - "GET/_mapping/:index/field/:fields": "indices.get_field_mapping", - "GET/_mget": "mget", - "GET/_msearch": "msearch", - "GET/_msearch/template": "msearch_template", - "GET/_mtermvectors": "mtermvectors", - "GET/_nodes": "nodes.info", - "GET/_nodes/hot_threads": "nodes.hot_threads", - "GET/_nodes/hotthreads": "nodes.hot_threads", - "GET/_nodes/stats": "nodes.stats", - "GET/_nodes/stats/:metric": "nodes.stats", - "GET/_nodes/stats/:metric/:index_metric": "nodes.stats", - "GET/_nodes/usage": "nodes.usage", - "GET/_nodes/usage/:metric": "nodes.usage", - "GET/_nodes/:metric": "nodes.info", - "GET/_nodes/:node_id": "nodes.info", - "GET/_nodes/:node_id/hot_threads": "nodes.hot_threads", - "GET/_nodes/:node_id/hotthreads": "nodes.hot_threads", - "GET/_nodes/:node_id/stats": "nodes.stats", - "GET/_nodes/:node_id/stats/:metric": "nodes.stats", - "GET/_nodes/:node_id/stats/:metric/:index_metric": "nodes.stats", - "GET/_nodes/:node_id/usage": "nodes.usage", - "GET/_nodes/:node_id/usage/:metric": "nodes.usage", - "GET/_nodes/:node_id/:metric": "nodes.info", - "GET/_rank_eval": "rank_eval", - "GET/_recovery": "indices.recovery", - "GET/_refresh": "indices.refresh", - "GET/_remote/info": "cluster.remote_info", - "GET/_render/template": "render_search_template", - "GET/_render/template/:id": "render_search_template", - "GET/_scripts/painless/_execute": "scripts_painless_execute", - "GET/_scripts/:id": "get_script", - "GET/_search": "search", - "GET/_search/scroll": "scroll", - "GET/_search/scroll/:scroll_id": "scroll", - "GET/_search/template": "search_template", - "GET/_search_shards": "search_shards", - "GET/_segments": "indices.segments", - "GET/_settings": "indices.get_settings", - "GET/_settings/:name": "indices.get_settings", - "GET/_shard_stores": "indices.shard_stores", - "GET/_snapshot": "snapshot.get_repository", - "GET/_snapshot/_status": "snapshot.status", - "GET/_snapshot/:repository": "snapshot.get_repository", - "GET/_snapshot/:repository/_status": "snapshot.status", - "GET/_snapshot/:repository/:snapshot": "snapshot.get", - "GET/_snapshot/:repository/:snapshot/_status": "snapshot.status", - "GET/_stats": "indices.stats", - "GET/_stats/:metric": "indices.stats", - "GET/_tasks": "tasks.list", - "GET/_tasks/:task_id": "tasks.get", - "GET/_template": "indices.get_template", - "GET/_template/:name": "indices.get_template", - "GET/_upgrade": "indices.get_upgrade", - "GET/_validate/query": "indices.validate_query", - "GET/:index": "indices.get", - "GET/:index/_alias": "indices.get_alias", - "GET/:index/_alias/:name": "indices.get_alias", - "GET/:index/_analyze": "indices.analyze", - "GET/:index/_count": "count", - "GET/:index/_doc/:id": "get", - "GET/:index/_field_caps": "field_caps", - "GET/:index/_flush": "indices.flush", - "GET/:index/_flush/synced": "indices.flush_synced", - "GET/:index/_mapping": "indices.get_mapping", - "GET/:index/_mapping/field/:fields": "indices.get_field_mapping", + "GET-/_mget": "mget", + "GET-/_msearch": "msearch", + "GET-/_msearch/template": "msearch_template", + "GET-/_mtermvectors": "mtermvectors", + "GET-/_nodes": "nodes.info", + "GET-/_nodes/hot_threads": "nodes.hot_threads", + "GET-/_nodes/hotthreads": "nodes.hot_threads", + "GET-/_nodes/stats": "nodes.stats", + "GET-/_nodes/stats/:metric": "nodes.stats", + "GET-/_nodes/stats/:metric/:index_metric": "nodes.stats", + "GET-/_nodes/usage": "nodes.usage", + "GET-/_nodes/usage/:metric": "nodes.usage", + "GET-/_nodes/:metric": "nodes.info", + "GET-/_nodes/:node_id": "nodes.info", + "GET-/_nodes/:node_id/hot_threads": "nodes.hot_threads", + "GET-/_nodes/:node_id/hotthreads": "nodes.hot_threads", + "GET-/_nodes/:node_id/stats": "nodes.stats", + "GET-/_nodes/:node_id/stats/:metric": "nodes.stats", + "GET-/_nodes/:node_id/stats/:metric/:index_metric": "nodes.stats", + "GET-/_nodes/:node_id/usage": "nodes.usage", + "GET-/_nodes/:node_id/usage/:metric": "nodes.usage", + "GET-/_nodes/:node_id/:metric": "nodes.info", + "GET-/_rank_eval": "rank_eval", + "GET-/_recovery": "indices.recovery", + "GET-/_refresh": "indices.refresh", + "GET-/_remote/info": "cluster.remote_info", + "GET-/_render/template": "render_search_template", + "GET-/_render/template/:id": "render_search_template", + "GET-/_scripts/painless/_execute": "scripts_painless_execute", + "GET-/_scripts/:id": "get_script", + "GET-/_search": "search", + "GET-/_search/scroll": "scroll", + "GET-/_search/scroll/:scroll_id": "scroll", + "GET-/_search/template": "search_template", + "GET-/_search_shards": "search_shards", + "GET-/_segments": "indices.segments", + "GET-/_settings": "indices.get_settings", + "GET-/_settings/:name": "indices.get_settings", + "GET-/_shard_stores": "indices.shard_stores", + "GET-/_snapshot": "snapshot.get_repository", + "GET-/_snapshot/_status": "snapshot.status", + "GET-/_snapshot/:repository": "snapshot.get_repository", + "GET-/_snapshot/:repository/_status": "snapshot.status", + "GET-/_snapshot/:repository/:snapshot": "snapshot.get", + "GET-/_snapshot/:repository/:snapshot/_status": "snapshot.status", + "GET-/_stats": "indices.stats", + "GET-/_stats/:metric": "indices.stats", + "GET-/_tasks": "tasks.list", + "GET-/_tasks/:task_id": "tasks.get", + "GET-/_template": "indices.get_template", + "GET-/_template/:name": "indices.get_template", + "GET-/_upgrade": "indices.get_upgrade", + "GET-/_validate/query": "indices.validate_query", + "GET-/:index": "indices.get", + "GET-/:index/_alias": "indices.get_alias", + "GET-/:index/_alias/:name": "indices.get_alias", + "GET-/:index/_analyze": "indices.analyze", + "GET-/:index/_count": "count", + "GET-/:index/_doc/:id": "doc.get", + "GET-/:index/_field_caps": "field_caps", + "GET-/:index/_flush": "indices.flush", + "GET-/:index/_flush/synced": "indices.flush_synced", + "GET-/:index/_mapping": "indices.get_mapping", + "GET-/:index/_mappings": "indices.get_mapping", + "GET-/:index/_mapping/field/:fields": "indices.get_field_mapping", - "GET/:index/_mget": "mget", - "GET/:index/_msearch": "msearch", - "GET/:index/_msearch/template": "msearch_template", - "GET/:index/_mtermvectors": "mtermvectors", - "GET/:index/_rank_eval": "rank_eval", - "GET/:index/_recovery": "indices.recovery", - "GET/:index/_refresh": "indices.refresh", - "GET/:index/_search": "search", - "GET/:index/_search/template": "search_template", - "GET/:index/_search_shards": "search_shards", - "GET/:index/_segments": "indices.segments", - "GET/:index/_settings": "indices.get_settings", - "GET/:index/_settings/:name": "indices.get_settings", - "GET/:index/_shard_stores": "indices.shard_stores", - "GET/:index/_stats": "indices.stats", - "GET/:index/_stats/:metric": "indices.stats", - "GET/:index/_upgrade": "indices.get_upgrade", - "GET/:index/_validate/query": "indices.validate_query", + "GET-/:index/_mget": "mget", + "GET-/:index/_msearch": "msearch", + "GET-/:index/_msearch/template": "msearch_template", + "GET-/:index/_mtermvectors": "mtermvectors", + "GET-/:index/_rank_eval": "rank_eval", + "GET-/:index/_recovery": "indices.recovery", + "GET-/:index/_refresh": "indices.refresh", + "GET-/:index/_search": "search", + "GET-/:index/_search/template": "search_template", + "GET-/:index/_search_shards": "search_shards", + "GET-/:index/_segments": "indices.segments", + "GET-/:index/_settings": "indices.get_settings", + "GET-/:index/_settings/:name": "indices.get_settings", + "GET-/:index/_shard_stores": "indices.shard_stores", + "GET-/:index/_stats": "indices.stats", + "GET-/:index/_stats/:metric": "indices.stats", + "GET-/:index/_upgrade": "indices.get_upgrade", + "GET-/:index/_validate/query": "indices.validate_query", - "HEAD/": "info", - "HEAD/_alias/:name": "indices.exists_alias", - "HEAD/_template/:name": "indices.exists_template", - "HEAD/:index": "indices.exists", - "HEAD/:index/_alias/:name": "indices.exists_alias", + "HEAD-/": "info", + "HEAD-/_alias/:name": "indices.exists_alias", + "HEAD-/_template/:name": "indices.exists_template", + "HEAD-/:index": "indices.exists", + "HEAD-/:index/_alias/:name": "indices.exists_alias", - "POST/_aliases": "indices.update_aliases", - "POST/_analyze": "indices.analyze", - "POST/_bulk": "bulk", - "POST/_cache/clear": "indices.clear_cache", - "POST/_cluster/allocation/explain": "cluster.allocation_explain", - "POST/_cluster/reroute": "cluster.reroute", - "POST/_count": "count", - "POST/_delete_by_query/:task_id/_rethrottle": "reindex_rethrottle", - "POST/_field_caps": "field_caps", - "POST/_flush": "indices.flush", - "POST/_flush/synced": "indices.flush_synced", - "POST/_forcemerge": "indices.forcemerge", - "POST/_ingest/pipeline/_simulate": "ingest.simulate", - "POST/_ingest/pipeline/:id/_simulate": "ingest.simulate", + "POST-/_aliases": "indices.update_aliases", + "POST-/_analyze": "indices.analyze", + "POST-/_bulk": "bulk", + "POST-/_cache/clear": "indices.clear_cache", + "POST-/_cluster/allocation/explain": "cluster.allocation_explain", + "POST-/_cluster/reroute": "cluster.reroute", + "POST-/_count": "count", + "POST-/_DELETE-_by_query/:task_id/_rethrottle": "reindex_rethrottle", + "POST-/_field_caps": "field_caps", + "POST-/_flush": "indices.flush", + "POST-/_flush/synced": "indices.flush_synced", + "POST-/_forcemerge": "indices.forcemerge", + "POST-/_ingest/pipeline/_simulate": "ingest.simulate", + "POST-/_ingest/pipeline/:id/_simulate": "ingest.simulate", - "POST/_mget": "mget", - "POST/_msearch": "msearch", - "POST/_msearch/template": "msearch_template", - "POST/_mtermvectors": "mtermvectors", - "POST/_nodes/reload_secure_settings": "nodes.reload_secure_settings", - "POST/_nodes/:node_id/reload_secure_settings": "nodes.reload_secure_settings", - "POST/_rank_eval": "rank_eval", - "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/_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/_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", - "POST/_snapshot/:repository/:snapshot/_restore": "snapshot.restore", - "POST/_tasks/_cancel": "tasks.cancel", - "POST/_tasks/:task_id/_cancel": "tasks.cancel", - "POST/_template/:name": "indices.put_template", - "POST/_update_by_query/:task_id/_rethrottle": "reindex_rethrottle", - "POST/_upgrade": "indices.upgrade", - "POST/_validate/query": "indices.validate_query", - "POST/:alias/_rollover": "indices.rollover", - "POST/:alias/_rollover/:new_index": "indices.rollover", - "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/_cache/clear": "indices.clear_cache", - "POST/:index/_close": "indices.close", - "POST/:index/_count": "count", - "POST/:index/_delete_by_query": "delete_by_query", - "POST/:index/_doc": "index", - "POST/:index/_doc/:id": "index", - "POST/:index/_doc/:id/_update": "update", - "POST/:index/_field_caps": "field_caps", - "POST/:index/_flush": "indices.flush", - "POST/:index/_flush/synced": "indices.flush_synced", - "POST/:index/_forcemerge": "indices.forcemerge", + "POST-/_mget": "mget", + "POST-/_msearch": "msearch", + "POST-/_msearch/template": "msearch_template", + "POST-/_mtermvectors": "mtermvectors", + "POST-/_nodes/reload_secure_settings": "nodes.reload_secure_settings", + "POST-/_nodes/:node_id/reload_secure_settings": "nodes.reload_secure_settings", + "POST-/_rank_eval": "rank_eval", + "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-/_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-/_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", + "POST-/_snapshot/:repository/:snapshot/_restore": "snapshot.restore", + "POST-/_tasks/_cancel": "tasks.cancel", + "POST-/_tasks/:task_id/_cancel": "tasks.cancel", + "POST-/_template/:name": "indices.put_template", + "POST-/_update_by_query/:task_id/_rethrottle": "reindex_rethrottle", + "POST-/_upgrade": "indices.upgrade", + "POST-/_validate/query": "indices.validate_query", + "POST-/:alias/_rollover": "indices.rollover", + "POST-/:alias/_rollover/:new_index": "indices.rollover", + "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/_cache/clear": "indices.clear_cache", + "POST-/:index/_close": "indices.close", + "POST-/:index/_count": "count", + "POST-/:index/_DELETE-_by_query": "DELETE-_by_query", + "POST-/:index/_doc": "doc.create", + "POST-/:index/_doc/:id": "doc.put", + "POST-/:index/_doc/:id/_update": "doc.update", + "POST-/:index/_field_caps": "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/_open": "indices.open", - "POST/:index/_rank_eval": "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/_shrink/:target": "indices.shrink", - "POST/:index/_split/:target": "indices.split", - "POST/:index/_update_by_query": "update_by_query", - "POST/:index/_upgrade": "indices.upgrade", - "POST/:index/_validate/query": "indices.validate_query", + "POST-/:index/_mget": "mget", + "POST-/:index/_msearch": "msearch", + "POST-/:index/_msearch/template": "msearch_template", + "POST-/:index/_mtermvectors": "mtermvectors", + "POST-/:index/_open": "indices.open", + "POST-/:index/_rank_eval": "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/_shrink/:target": "indices.shrink", + "POST-/:index/_split/:target": "indices.split", + "POST-/:index/_update_by_query": "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/_cluster/settings": "cluster.put_settings", - "PUT/_ingest/pipeline/:id": "ingest.put_pipeline", + "POST-/:index/_mapping": "indices.put_mapping", + "POST-/:index/_mappings": "indices.put_mapping", + "PUT-/_bulk": "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/_snapshot/:repository": "snapshot.create_repository", - "PUT/_snapshot/:repository/:snapshot": "snapshot.create", - "PUT/_template/:name": "indices.put_template", - "PUT/:index": "indices.create", - "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-/_scripts/:id": "put_script", + "PUT-/_scripts/:id/:context": "put_script", + "PUT-/_settings": "indices.put_settings", + "PUT-/_snapshot/:repository": "snapshot.create_repository", + "PUT-/_snapshot/:repository/:snapshot": "snapshot.create", + "PUT-/_template/:name": "indices.put_template", + "PUT-/:index": "indices.create", + "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/_settings": "indices.put_settings", - "PUT/:index/_shrink/:target": "indices.shrink", - "PUT/:index/_split/:target": "indices.split", + "PUT-/:index/_settings": "indices.put_settings", + "PUT-/:index/_shrink/:target": "indices.shrink", + "PUT-/:index/_split/:target": "indices.split", - "PUT:index/_mapping": "indices.put_mapping", - "PUT:index/_mappings": "indices.put_mapping" + "PUT-/:index/_mapping": "indices.put_mapping", + "PUT-/:index/_mappings": "indices.put_mapping" } \ No newline at end of file diff --git a/config/permission.json b/config/permission.json index f44ec1c2..cd79821e 100644 --- a/config/permission.json +++ b/config/permission.json @@ -4,7 +4,7 @@ "bulk" ], "cat": [ - "*", + "cat.*", "cat.indices", "cat.help", "cat.repositories", @@ -27,7 +27,7 @@ "cat.master" ], "cluster": [ - "*", + "cluster.*", "cluster.health", "cluster.get_settings", "cluster.pending_tasks", @@ -43,14 +43,14 @@ "count" ], "doc": [ - "*", + "doc.*", "doc.update", "doc.put", "doc.create", "doc.delete" ], "exists": [ - "*", + "exists" ], "explain": [ @@ -63,6 +63,7 @@ "get" ], "indices": [ + "indices.*", "indices.exists_alias", "indices.get_alias", "indices.recovery", @@ -108,6 +109,7 @@ "info" ], "ingest": [ + "ingest.*", "ingest.delete_pipeline", "ingest.put_pipeline", "ingest.simulate", @@ -127,6 +129,7 @@ "mtermvectors" ], "nodes": [ + "nodes.*", "nodes.info", "nodes.stats", "nodes.reload_secure_settings", @@ -149,6 +152,7 @@ "render_search_template" ], "scripts": [ + "scripts.*", "scripts.get", "scripts.put", "scripts.delete" @@ -169,6 +173,7 @@ "search_template" ], "snapshot": [ + "snapshot.*", "snapshot.get_repository", "snapshot.create_repository", "snapshot.create", @@ -180,6 +185,7 @@ "snapshot.get" ], "source": [ + "source.*", "source.head", "source.get" ], diff --git a/internal/biz/account.go b/internal/biz/account.go index 98619ec1..47c313ed 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -95,7 +95,7 @@ func authorize(user Account) (m map[string]interface{}, err error) { r, _ := GetRole(v.Id) privilege = append(privilege, r.Platform...) - RolePermission[v.Name] = enum.Role{ + RoleMap[v.Name] = Role{ Platform: r.Platform, Cluster: r.Cluster, ClusterPrivilege: r.ClusterPrivilege, @@ -231,12 +231,12 @@ func ValidatePermission(claims *UserClaims, permissions []string) (err error) { err = errors.New("api permission is empty") return } - return nil + // 权限校验 userPermissionMap := make(map[string]struct{}) for _, role := range user.Roles { - if _, ok := RolePermission[role]; ok { - for _, v := range RolePermission[role].Platform { + if _, ok := RoleMap[role]; ok { + for _, v := range RoleMap[role].Platform { userPermissionMap[v] = struct{}{} //all include read diff --git a/internal/biz/context.go b/internal/biz/context.go index e2b595e6..2d4a8e49 100644 --- a/internal/biz/context.go +++ b/internal/biz/context.go @@ -3,8 +3,6 @@ package biz import ( "context" "errors" - httprouter "infini.sh/framework/core/api/router" - "net/http" ) const ctxUserKey = "user" @@ -23,57 +21,3 @@ func FromUserContext(ctx context.Context) (*User, error) { } return reqUser.User, nil } - -type EsRequest struct { - Method string `json:"method"` - Cluster []string `json:"cluster"` - - Index []string `json:"index"` - Doc string `json:"doc"` - Path string `json:"path"` -} - -func NewEsRequest(r *http.Request, ps httprouter.Params) EsRequest { - - //GET elasticsearch/c6dgjtgvi076f32oibj0/index/test/_mappings - clusterId := ps.ByName("id") - index := ps.ByName("index") - - doc := ps.ByName("docId") - //如果index存在,说明调用的是index api - return EsRequest{ - Cluster: []string{clusterId}, - Index: []string{index}, - Doc: doc, - Path: r.URL.Path, - Method: r.Method, - } -} -func ValidateEsPermission(req EsRequest, userRole Role) (err error) { - userClusterMap := make(map[string]struct{}) - userIndexMap := make(map[string]struct{}) - for _, v := range userRole.Cluster { - userClusterMap[v.Id] = struct{}{} - } - //todo 启动内存 - for _, val := range userRole.Index { - for _, v := range val.Name { - userIndexMap[v] = struct{}{} - } - - } - for _, v := range req.Cluster { - if _, ok := userClusterMap[v]; !ok { - err = errors.New("no cluster permission") - return - } - } - for _, v := range req.Index { - if _, ok := userIndexMap[v]; !ok { - err = errors.New("no index permission") - return - } - } - - return -} diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 45da1796..6309252c 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -19,58 +19,19 @@ var AdminPrivilege = []string{ "system.role:read", "system.role:all", "system.user:read", "system.user:all", } -type Role struct { - Platform []string `json:"platform,omitempty"` - Cluster []struct { - Id string `json:"id"` - Name string `json:"name"` - } `json:"cluster,omitempty"` - ClusterPrivilege []map[string][]string `json:"cluster_privilege,omitempty"` - Index []struct { - Name []string `json:"name"` - Privilege []string `json:"privilege"` - } `json:"index,omitempty"` -} - -var Admin Role var BuildRoles = make(map[string]map[string]interface{}, 0) func init() { - Admin = Role{ - Platform: AdminPrivilege, - } - - UserMenu := Menu{ - Id: "system_user", - Privilege: "all", - } - RoleMenu := Menu{ - Id: "system_role", - - Privilege: "all", - } - AdminMenu := []Menu{ - UserMenu, RoleMenu, - } BuildRoles["admin"] = map[string]interface{}{ "id": "admin", "name": "管理员", - "permission": AdminMenu, + "platform": []string{"system.role:all", "system.user:all"}, "builtin": true, "description": "is admin", "created": time.Now(), } - BuildRoles["user_admin"] = map[string]interface{}{ - "id": "user_admin", - "name": "用户管理员", - "permission": UserMenu, - "builtin": true, - "description": "is user admin", - "created": time.Now(), - } - //自定义角色=》 =》permissionKey // userrole=> [cluster::all,clust] => permissionValue [cluster::read,cluster::write] // login=> userrole=> cluster::all =>permissionList[] diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 6619be5c..93f3a1f5 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -1,14 +1,15 @@ package biz -import "infini.sh/console/internal/biz/enum" +import "infini.sh/console/internal/core" var ClusterApis = make(map[string][]string) var IndexApis = make([]string, 0) -var RolePermission = make(map[string]enum.Role) -var EsApiMap = make(map[string]string) +var RoleMap = make(map[string]Role) +var EsApiRoutes = core.NewRouter() type Role struct { + Name string `json:"name"` Platform []string `json:"platform,omitempty"` Cluster []struct { Id string `json:"id"` diff --git a/internal/biz/user.go b/internal/biz/user.go index 45c43a1a..85c6d715 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -129,11 +129,19 @@ func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { err = ErrNotFound return } + roles := make([]rbac.UserRole, 0) + for _, v := range req.Roles { + roles = append(roles, rbac.UserRole{ + Id: v.Id, + Name: v.Name, + }) + } changeLog, _ := util.DiffTwoObject(user, req) user.Name = req.Name user.Email = req.Email user.Phone = req.Phone user.Tags = req.Tags + user.Roles = roles user.Updated = time.Now() err = orm.Save(&user) if err != nil { @@ -150,6 +158,7 @@ func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { "phone": user.Phone, "name": user.Name, "tags": user.Tags, + "roles": roles, "updated": user.Updated, }, User: util.MapStr{ diff --git a/internal/biz/validate.go b/internal/biz/validate.go new file mode 100644 index 00000000..2020cdfa --- /dev/null +++ b/internal/biz/validate.go @@ -0,0 +1,112 @@ +package biz + +import ( + "errors" + httprouter "infini.sh/framework/core/api/router" + "net/http" +) + +type EsRequest struct { + Method string `json:"method"` + Cluster []string `json:"cluster"` + + Index []string `json:"index"` + Doc string `json:"doc"` + Path string `json:"path"` +} + +func NewEsRequest(r *http.Request, ps httprouter.Params) EsRequest { + + //GET elasticsearch/c6dgjtgvi076f32oibj0/index/test/_mappings + clusterId := ps.ByName("id") + index := ps.ByName("index") + + doc := ps.ByName("docId") + //如果index存在,说明调用的是index api + return EsRequest{ + Cluster: []string{clusterId}, + Index: []string{index}, + Doc: doc, + Path: r.URL.Path, + Method: r.Method, + } +} +func ValidateEsPermission(req EsRequest, userRole Role) (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 EsRequest, userRole Role, route string) (err error) { + userIndexMap := make(map[string]struct{}) + privilegeMap := make(map[string]struct{}) + for _, val := range userRole.Index { + for _, v := range val.Name { + userIndexMap[v] = struct{}{} + } + for _, v := range val.Privilege { + privilegeMap[v] = struct{}{} + } + } + + for _, v := range req.Index { + if _, ok := userIndexMap[v]; !ok { + err = errors.New("no index permission") + return + } + } + + if _, ok := privilegeMap[route]; !ok { + err = errors.New("no index api permission") + return + } + + return +} +func validateCluster(req EsRequest, userRole Role, route string) (err error) { + userClusterMap := make(map[string]struct{}) + for _, v := range userRole.Cluster { + userClusterMap[v.Id] = struct{}{} + } + for _, v := range req.Cluster { + if _, ok := userClusterMap[v]; !ok { + err = errors.New("no cluster permission") + return + } + } + + tmp := make([]string, 0) + for _, val := range userRole.ClusterPrivilege { + for _, v := range val { + tmp = append(tmp, v...) + } + + } + for _, v := range tmp { + if v == route { + return nil + } + } + return errors.New("no cluster api permission") +} +func CombineUserRoles(roleNames []string) Role { + newRole := Role{} + for _, v := range roleNames { + r := RoleMap[v] + newRole.Cluster = append(newRole.Cluster, r.Cluster...) + newRole.Platform = append(newRole.Platform, r.Platform...) + newRole.Index = append(newRole.Index, r.Index...) + newRole.ClusterPrivilege = append(newRole.ClusterPrivilege, r.ClusterPrivilege...) + } + return newRole +} diff --git a/internal/core/router.go b/internal/core/router.go new file mode 100644 index 00000000..faeced25 --- /dev/null +++ b/internal/core/router.go @@ -0,0 +1,94 @@ +package core + +import ( + "errors" + "strings" +) + +type Router struct { + roots map[string]*node + handlers map[string]string +} + +func NewRouter() *Router { + return &Router{ + roots: make(map[string]*node), + handlers: make(map[string]string), + } +} + +// Only one * is allowed +func parsePattern(pattern string) []string { + vs := strings.Split(pattern, "/") + + parts := make([]string, 0) + for _, item := range vs { + if item != "" { + parts = append(parts, item) + if item[0] == '*' { + break + } + } + } + return parts +} + +func (r *Router) AddRoute(method string, pattern string, handler string) { + parts := parsePattern(pattern) + + key := method + "-" + pattern + _, ok := r.roots[method] + if !ok { + r.roots[method] = &node{} + } + r.roots[method].insert(pattern, parts, 0) + r.handlers[key] = handler +} + +func (r *Router) GetRoute(method string, path string) (*node, map[string]string) { + searchParts := parsePattern(path) + params := make(map[string]string) + root, ok := r.roots[method] + + if !ok { + return nil, nil + } + + n := root.search(searchParts, 0) + + if n != nil { + parts := parsePattern(n.pattern) + for index, part := range parts { + if part[0] == ':' { + params[part[1:]] = searchParts[index] + } + //if part[0] == '*' && len(part) > 1 { + // params[part[1:]] = strings.Join(searchParts[index:], "/") + // break + //} + } + return n, params + } + + return nil, nil +} + +func (r *Router) getRoutes(method string) []*node { + root, ok := r.roots[method] + if !ok { + return nil + } + nodes := make([]*node, 0) + root.travel(&nodes) + return nodes +} + +func (r *Router) Handle(method string, path string) (handle string, err error) { + n, _ := r.GetRoute(method, path) + if n == nil { + err = errors.New("router not match") + return + + } + return r.handlers[method+"-"+n.pattern], nil +} diff --git a/internal/core/router_test.go b/internal/core/router_test.go new file mode 100644 index 00000000..ea49bbf2 --- /dev/null +++ b/internal/core/router_test.go @@ -0,0 +1,79 @@ +package core + +import ( + "fmt" + "reflect" + "testing" +) + +func newTestRouter() *Router { + r := NewRouter() + //GET "GET/_mapping/:index": "indices.get_mapping", + r.AddRoute("GET", "/:index/_mappings", "indices.get_mapping") + r.AddRoute("GET", "/hello/:name", "gethello") + r.AddRoute("GET", "/hello/b/c", "hellobc") + r.AddRoute("GET", "/hi/:name", "getHi") + r.AddRoute("GET", "/role/xushuhui", "getRole") + + return r +} + +func TestParsePattern(t *testing.T) { + ok := reflect.DeepEqual(parsePattern("/p/:name"), []string{"p", ":name"}) + ok = ok && reflect.DeepEqual(parsePattern("/p/*"), []string{"p", "*"}) + ok = ok && reflect.DeepEqual(parsePattern("/p/*name/*"), []string{"p", "*name"}) + if !ok { + t.Fatal("test parsePattern failed") + } +} + +func TestGetRoute(t *testing.T) { + //r := newTestRouter() + //path := "/elasticsearch/c6dgjtgvi076f32oibj0/index/test/_mappings" + //paths := strings.Split(path, "/") + //newPath := "/" + strings.Join(paths[4:], "/") + //t.Log(newPath) + + //if n == nil { + // t.Fatal("nil shouldn't be returned") + //} + + //if n.pattern != "/hello/:name" { + // t.Fatal("should match /hello/:name") + //} + // + //if ps["name"] != "geektutu" { + // t.Fatal("name should be equal to 'geektutu'") + //} + + //fmt.Printf("matched path: %s, params['name']: %s\n", n.pattern, ps["name"]) + +} + +func TestGetRoute2(t *testing.T) { + r := newTestRouter() + n1, ps1 := r.GetRoute("GET", "/assets/file1.txt") + ok1 := n1.pattern == "/assets/*filepath" && ps1["filepath"] == "file1.txt" + if !ok1 { + t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be file1.txt") + } + + n2, ps2 := r.GetRoute("GET", "/assets/css/test.css") + ok2 := n2.pattern == "/assets/*filepath" && ps2["filepath"] == "css/test.css" + if !ok2 { + t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be css/test.css") + } + +} + +func TestGetRoutes(t *testing.T) { + r := newTestRouter() + nodes := r.getRoutes("GET") + for i, n := range nodes { + fmt.Println(i+1, n) + } + + if len(nodes) != 5 { + t.Fatal("the number of routes shoule be 4") + } +} diff --git a/internal/core/trie.go b/internal/core/trie.go new file mode 100644 index 00000000..2fcb5b5e --- /dev/null +++ b/internal/core/trie.go @@ -0,0 +1,83 @@ +package core + +import ( + "fmt" + "strings" +) + +type node struct { + pattern string // 待匹配路由,例如 /p/:lang + part string // 路由中的一部分,例如 :lang + children []*node // 子节点,例如 [doc, tutorial, intro] + isWild bool // 是否精确匹配,part 含有 : 或 * 时为true +} + +func (n *node) String() string { + return fmt.Sprintf("node{pattern=%s, part=%s, isWild=%t}", n.pattern, n.part, n.isWild) +} + +func (n *node) insert(pattern string, parts []string, height int) { + if len(parts) == height { + n.pattern = pattern + return + } + + part := parts[height] + child := n.matchChild(part) + if child == nil { + child = &node{part: part, isWild: part[0] == ':' || part[0] == '*'} + n.children = append(n.children, child) + } + child.insert(pattern, parts, height+1) +} + +func (n *node) search(parts []string, height int) *node { + if len(parts) == height || strings.HasPrefix(n.part, "*") { + if n.pattern == "" { + return nil + } + return n + } + + part := parts[height] + children := n.matchChildren(part) + + for _, child := range children { + result := child.search(parts, height+1) + if result != nil { + return result + } + } + + return nil +} + +func (n *node) travel(list *[]*node) { + if n.pattern != "" { + *list = append(*list, n) + } + for _, child := range n.children { + child.travel(list) + } +} + +// 第一个匹配成功的节点,用于插入 +func (n *node) matchChild(part string) *node { + for _, child := range n.children { + if child.part == part || child.isWild { + return child + } + } + return nil +} + +// 所有匹配成功的节点,用于查找 +func (n *node) matchChildren(part string) []*node { + nodes := make([]*node, 0) + for _, child := range n.children { + if child.part == part || child.isWild { + nodes = append(nodes, child) + } + } + return nodes +} diff --git a/internal/dto/role.go b/internal/dto/role.go index a1754213..1fc41450 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -1,14 +1,5 @@ package dto -type RolePermission struct { - Api []string `json:"api"` - Menu []Menu `json:"menu"` -} -type Menu struct { - Id string `json:"id"` - Name string `json:"name"` - Privilege string `json:"privilege"` -} type UpdateRole struct { Description string `json:"description" ` Platform []string `json:"platform"` @@ -42,6 +33,7 @@ type UpdateUser struct { Email string `json:"email"` Phone string `json:"phone"` Tags []string `json:"tags"` + Roles []Role `json:"roles"` } type UpdateUserRole struct { Roles []Role `json:"roles"` diff --git a/internal/middleware/user.go b/internal/middleware/user.go index a904cc97..9e6c0579 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -22,16 +22,22 @@ func LoginRequired(h httprouter.Handle) httprouter.Handle { func EsPermissionRequired(h httprouter.Handle) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - - //req := biz.NewEsRequest(r, ps) - //err := biz.ValidateEsPermission(req) - //if err != nil { - // w = handleError(w, http.StatusForbidden, err) - // return - //} + 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) { claims, err := biz.ValidateLogin(r.Header.Get("Authorization")) diff --git a/main.go b/main.go index e08cec7b..2ae5dca2 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "infini.sh/console/model/gateway" "infini.sh/console/model/rbac" _ "infini.sh/console/plugin" + rbacApi "infini.sh/console/plugin/api/rbac" alerting2 "infini.sh/console/service/alerting" "infini.sh/framework" "infini.sh/framework/core/elastic" @@ -137,7 +138,7 @@ func main() { if err != nil { log.Errorf("init alerting task error: %v", err) } - + rbacApi.Init() }() }, nil) { diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index 45a4eee9..c34ef3af 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -6,9 +6,13 @@ import ( "infini.sh/console/internal/biz/enum" m "infini.sh/console/internal/middleware" "infini.sh/framework/core/api" + "infini.sh/framework/core/elastic" "infini.sh/framework/core/util" "os" "path" + log "src/github.com/cihub/seelog" + "src/github.com/mitchellh/mapstructure" + "strings" ) type Rbac struct { @@ -49,47 +53,47 @@ func loadJsonConfig() { biz.IndexApis = apis["indices"] delete(apis, "indices") biz.ClusterApis = apis - //bytes, err = util.FileGetContent(path.Join(pwd, "/config/map.json")) - //if err != nil { - // panic("load json file err " + err.Error()) - // - //} - // - //err = json.Unmarshal(bytes, &biz.EsApiMap) - //if err != nil { - // panic("json config unmarshal err " + err.Error()) - //} + + bytes, err = util.FileGetContent(path.Join(pwd, "/config/map.json")) + if err != nil { + panic("load json file err " + err.Error()) + } + esapiMap := make(map[string]string) + err = json.Unmarshal(bytes, &esapiMap) + if err != nil { + panic("json config unmarshal err " + err.Error()) + } + for k, v := range esapiMap { + s := strings.Split(k, "-") + biz.EsApiRoutes.AddRoute(s[0], s[1], v) + } } func loadRolePermission() { - biz.RolePermission = make(map[string]enum.Role) + biz.RoleMap = make(map[string]biz.Role) - biz.RolePermission["admin"] = enum.Admin + biz.RoleMap["admin"] = biz.Role{ + Platform: enum.AdminPrivilege, + } + res, err := biz.SearchRole("", 0, 100) + if err != nil { + log.Error(err) + return + } + response := elastic.SearchResponse{} + util.FromJSONBytes(res.Raw, &response) + + for _, v := range response.Hits.Hits { + var role biz.Role + err = mapstructure.Decode(v.Source, &role) + if err != nil { + return + } + biz.RoleMap[role.Name] = role + } } func Init() { loadJsonConfig() loadRolePermission() } - -func existInternalUser() { - //user, err := biz.GetUser("admin") - //if errors.Is(err, elastic.ErrNotFound) { - // user.ID = "admin" - // user.Username = "admin" - // hash, _ := bcrypt.GenerateFromPassword([]byte("admin"), bcrypt.DefaultCost) - // - // user.Password = string(hash) - // user.Email = "" - // user.Phone = "" - // user.Name = "" - // - // - // user.Created = time.Now() - // user.Updated = time.Now() - // - //} -} -func existInternalRole() { - -} From c879a6aa9eb4e3d80833ba6040f98363d049cb08 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Mon, 25 Apr 2022 18:31:34 +0800 Subject: [PATCH 54/75] fix: (rbac) ValidateEsPermission --- internal/biz/account.go | 22 +++------------- internal/biz/permission.go | 7 +++++ internal/biz/role.go | 38 +++++++++++++++++----------- internal/biz/validate.go | 52 ++++++++++++++++++-------------------- 4 files changed, 59 insertions(+), 60 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index 47c313ed..ae23b002 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -6,7 +6,6 @@ import ( "github.com/golang-jwt/jwt" "github.com/mitchellh/mapstructure" "golang.org/x/crypto/bcrypt" - "infini.sh/console/internal/biz/enum" "infini.sh/console/internal/dto" "infini.sh/console/model/rbac" "infini.sh/framework/core/event" @@ -85,23 +84,10 @@ func authenticateAdmin(username string, password string) (user Account, err erro func authorize(user Account) (m map[string]interface{}, err error) { var roles, privilege []string - if user.Username == "admin" { - roles = append(roles, "admin") - privilege = append(privilege, enum.AdminPrivilege...) - } else { - for _, v := range user.Roles { - roles = append(roles, v.Name) - - r, _ := GetRole(v.Id) - - privilege = append(privilege, r.Platform...) - RoleMap[v.Name] = Role{ - Platform: r.Platform, - Cluster: r.Cluster, - ClusterPrivilege: r.ClusterPrivilege, - Index: r.Index, - } - } + for _, v := range user.Roles { + role := RoleMap[v.Name] + roles = append(roles, v.Name) + privilege = append(privilege, role.Platform...) } token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims{ User: &User{ diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 93f3a1f5..994a5aae 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -21,6 +21,13 @@ type Role struct { Privilege []string `json:"privilege"` } `json:"index,omitempty"` } +type RolePermission struct { + Platform []string `json:"platform,omitempty"` + Cluster []string `json:"cluster"` + ClusterPrivilege []string `json:"cluster_privilege"` + Index []string `json:"index"` + IndexPrivilege []string `json:"index_privilege"` +} type ConsolePermisson struct { Platform []Platform `json:"platform"` } diff --git a/internal/biz/role.go b/internal/biz/role.go index 05bd64fb..942a10df 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -23,7 +23,6 @@ type IRole interface { ListPermission() interface{} Create(localUser *User) (id string, err error) Update(localUser *User, model rbac.Role) (err error) - //Delete(localUser *User, id string) (err error) } type ConsoleRole struct { Name string `json:"name"` @@ -217,13 +216,15 @@ func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { Name: "role", Type: "create", Labels: util.MapStr{ - "id": id, - "name": role.Name, - "description": role.Description, - - "type": role.RoleType, - "created": newRole.Created.Format("2006-01-02 15:04:05"), - "updated": newRole.Updated.Format("2006-01-02 15:04:05"), + "id": id, + "name": newRole.Name, + "description": newRole.Description, + "cluster": newRole.Cluster, + "index": newRole.Index, + "cluster_privilege": newRole.ClusterPrivilege, + "type": newRole.RoleType, + "created": newRole.Created.Format("2006-01-02 15:04:05"), + "updated": newRole.Updated.Format("2006-01-02 15:04:05"), }, User: util.MapStr{ "userid": localUser.UserId, @@ -261,13 +262,16 @@ func DeleteRole(localUser *User, id string) (err error) { "username": localUser.Username, }, }, util.MapStr{ - "id": id, - "name": role.Name, - "description": role.Description, - "platform": role.Platform, - "type": role.RoleType, - "created": role.Created.Format("2006-01-02 15:04:05"), - "updated": role.Updated.Format("2006-01-02 15:04:05"), + "id": id, + "name": role.Name, + "description": role.Description, + "platform": role.Platform, + "cluster": role.Cluster, + "index": role.Index, + "cluster_privilege": role.ClusterPrivilege, + "type": role.RoleType, + "created": role.Created.Format("2006-01-02 15:04:05"), + "updated": role.Updated.Format("2006-01-02 15:04:05"), }, nil)) return @@ -283,6 +287,10 @@ func GetRole(id string) (role rbac.Role, err error) { } return } +func ListRoleByName(names []string) (roles []rbac.Role, err error) { + + return +} func SearchRole(keyword string, from, size int) (roles orm.Result, err error) { query := orm.Query{} diff --git a/internal/biz/validate.go b/internal/biz/validate.go index 2020cdfa..1d46ccfa 100644 --- a/internal/biz/validate.go +++ b/internal/biz/validate.go @@ -31,7 +31,7 @@ func NewEsRequest(r *http.Request, ps httprouter.Params) EsRequest { Method: r.Method, } } -func ValidateEsPermission(req EsRequest, userRole Role) (err error) { +func ValidateEsPermission(req EsRequest, userRole RolePermission) (err error) { route, err := EsApiRoutes.Handle(req.Method, req.Path) if err != nil { @@ -47,18 +47,16 @@ func ValidateEsPermission(req EsRequest, userRole Role) (err error) { err = validateCluster(req, userRole, route) return } -func validateIndex(req EsRequest, userRole Role, route string) (err error) { +func validateIndex(req EsRequest, userRole RolePermission, route string) (err error) { userIndexMap := make(map[string]struct{}) privilegeMap := make(map[string]struct{}) - for _, val := range userRole.Index { - for _, v := range val.Name { - userIndexMap[v] = struct{}{} - } - for _, v := range val.Privilege { - privilegeMap[v] = struct{}{} - } - } + for _, v := range userRole.Index { + userIndexMap[v] = struct{}{} + } + for _, v := range userRole.IndexPrivilege { + privilegeMap[v] = struct{}{} + } for _, v := range req.Index { if _, ok := userIndexMap[v]; !ok { err = errors.New("no index permission") @@ -73,10 +71,10 @@ func validateIndex(req EsRequest, userRole Role, route string) (err error) { return } -func validateCluster(req EsRequest, userRole Role, route string) (err error) { +func validateCluster(req EsRequest, userRole RolePermission, route string) (err error) { userClusterMap := make(map[string]struct{}) for _, v := range userRole.Cluster { - userClusterMap[v.Id] = struct{}{} + userClusterMap[v] = struct{}{} } for _, v := range req.Cluster { if _, ok := userClusterMap[v]; !ok { @@ -85,28 +83,28 @@ func validateCluster(req EsRequest, userRole Role, route string) (err error) { } } - tmp := make([]string, 0) - for _, val := range userRole.ClusterPrivilege { - for _, v := range val { - tmp = append(tmp, v...) - } - - } - for _, v := range tmp { + for _, v := range userRole.ClusterPrivilege { if v == route { return nil } } return errors.New("no cluster api permission") } -func CombineUserRoles(roleNames []string) Role { - newRole := Role{} +func CombineUserRoles(roleNames []string) RolePermission { + newRole := RolePermission{} for _, v := range roleNames { - r := RoleMap[v] - newRole.Cluster = append(newRole.Cluster, r.Cluster...) - newRole.Platform = append(newRole.Platform, r.Platform...) - newRole.Index = append(newRole.Index, r.Index...) - newRole.ClusterPrivilege = append(newRole.ClusterPrivilege, r.ClusterPrivilege...) + role := RoleMap[v] + for _, v := range role.Cluster { + newRole.Cluster = append(newRole.Cluster, v.Id) + } + for _, v := range role.Platform { + newRole.Platform = append(newRole.Platform, v) + } + + for _, v := range role.Index { + newRole.Index = append(newRole.Index, v.Name...) + newRole.IndexPrivilege = append(newRole.IndexPrivilege, v.Privilege...) + } } return newRole } From a051fe3debb05dba6c6a13bc24350fb33d24ba3e Mon Sep 17 00:00:00 2001 From: xushuhui Date: Tue, 26 Apr 2022 10:52:32 +0800 Subject: [PATCH 55/75] fix: (rbac) cluster privilege change map to []string --- internal/biz/permission.go | 2 +- internal/biz/role.go | 36 ++++++-- internal/biz/user.go | 2 + internal/biz/validate.go | 11 ++- internal/biz/validate_test.go | 155 ++++++++++++++++++++++++++++++++++ model/rbac/role.go | 2 +- 6 files changed, 197 insertions(+), 11 deletions(-) create mode 100644 internal/biz/validate_test.go diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 994a5aae..c2d2af7a 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -15,7 +15,7 @@ type Role struct { Id string `json:"id"` Name string `json:"name"` } `json:"cluster,omitempty"` - ClusterPrivilege []map[string][]string `json:"cluster_privilege,omitempty"` + ClusterPrivilege []string `json:"cluster_privilege,omitempty"` Index []struct { Name []string `json:"name"` Privilege []string `json:"privilege"` diff --git a/internal/biz/role.go b/internal/biz/role.go index 942a10df..899be203 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -31,15 +31,19 @@ type ConsoleRole struct { Platform []string `json:"platform,omitempty"` } -type MenuPermission struct { - Id string `json:"id"` - Privilege string `json:"privilege"` -} type ElasticsearchRole struct { Name string `json:"name"` Description string `json:"description" ` RoleType string `json:"type" ` - rbac.ElasticRole + Cluster []struct { + Id string `json:"id"` + Name string `json:"name"` + } `json:"cluster,omitempty"` + ClusterPrivilege []string `json:"cluster_privilege,omitempty"` + Index []struct { + Name []string `json:"name"` + Privilege []string `json:"privilege"` + } `json:"index,omitempty"` } func NewRole(typ string) (r IRole, err error) { @@ -63,12 +67,15 @@ func (role ConsoleRole) Update(localUser *User, model rbac.Role) (err error) { changeLog, _ := util.DiffTwoObject(model, role) model.Description = role.Description model.Platform = role.Platform - model.Updated = time.Now() err = orm.Save(model) if err != nil { return } + RoleMap[role.Name] = Role{ + Name: model.Name, + Platform: model.Platform, + } err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -100,6 +107,12 @@ func (role ElasticsearchRole) Update(localUser *User, model rbac.Role) (err erro if err != nil { return } + RoleMap[role.Name] = Role{ + Name: model.Name, + Cluster: model.Cluster, + ClusterPrivilege: model.ClusterPrivilege, + Index: model.Index, + } err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -150,6 +163,10 @@ func (role ConsoleRole) Create(localUser *User) (id string, err error) { return } id = newRole.ID + RoleMap[role.Name] = Role{ + Name: newRole.Name, + Platform: newRole.Platform, + } err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -210,6 +227,12 @@ func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { return } id = newRole.ID + RoleMap[role.Name] = Role{ + Name: newRole.Name, + Cluster: newRole.Cluster, + ClusterPrivilege: newRole.ClusterPrivilege, + Index: newRole.Index, + } err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -249,6 +272,7 @@ func DeleteRole(localUser *User, id string) (err error) { if err != nil { return } + delete(RoleMap, role.Name) err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", diff --git a/internal/biz/user.go b/internal/biz/user.go index 85c6d715..b9a1f3f1 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -28,6 +28,7 @@ func DeleteUser(localUser *User, id string) (err error) { if err != nil { return } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -190,6 +191,7 @@ func UpdateUserRole(localUser *User, id string, req dto.UpdateUserRole) (err err if err != nil { return } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", diff --git a/internal/biz/validate.go b/internal/biz/validate.go index 1d46ccfa..80e6a818 100644 --- a/internal/biz/validate.go +++ b/internal/biz/validate.go @@ -89,18 +89,23 @@ func validateCluster(req EsRequest, userRole RolePermission, route string) (err } } return errors.New("no cluster api permission") +} +func FilterCluster() { + } func CombineUserRoles(roleNames []string) RolePermission { newRole := RolePermission{} - for _, v := range roleNames { - role := RoleMap[v] + for _, val := range roleNames { + role := RoleMap[val] for _, v := range role.Cluster { newRole.Cluster = append(newRole.Cluster, v.Id) } + for _, v := range role.ClusterPrivilege { + newRole.ClusterPrivilege = append(newRole.ClusterPrivilege, v) + } for _, v := range role.Platform { newRole.Platform = append(newRole.Platform, v) } - for _, v := range role.Index { newRole.Index = append(newRole.Index, v.Name...) newRole.IndexPrivilege = append(newRole.IndexPrivilege, v.Privilege...) diff --git a/internal/biz/validate_test.go b/internal/biz/validate_test.go new file mode 100644 index 00000000..cd7fc47f --- /dev/null +++ b/internal/biz/validate_test.go @@ -0,0 +1,155 @@ +package biz + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func Test_validateIndex(t *testing.T) { + type args struct { + req EsRequest + 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", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + got := validateIndex(tt.args.req, tt.args.userRole, tt.args.route) + + assert.EqualError(t, got, tt.want) + }) + } +} +func Test_validateCluster(t *testing.T) { + type args struct { + req EsRequest + userRole RolePermission + route string + } + tests := []struct { + name string + args args + want string + }{ + {"no cluster permission", + args{ + req: EsRequest{ + Method: "GET", + Cluster: []string{"cluster1"}, + Index: []string{"index2"}, + Path: "/index1/_mapping", + }, + userRole: RolePermission{ + Cluster: []string{ + "cluster2", + }, + Index: []string{ + "index1", + }, + ClusterPrivilege: []string{ + "cat.*", + }, + IndexPrivilege: []string{ + "indices.get_mapping", + }, + }, + route: "indices.get_mapping", + }, "no cluster permission", + }, + {"no cluster 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 cluster api permission", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + got := validateCluster(tt.args.req, tt.args.userRole, tt.args.route) + + assert.EqualError(t, got, tt.want) + }) + } +} diff --git a/model/rbac/role.go b/model/rbac/role.go index 41fb8cf1..ae17b596 100644 --- a/model/rbac/role.go +++ b/model/rbac/role.go @@ -16,7 +16,7 @@ type Role struct { Id string `json:"id"` Name string `json:"name"` } `json:"cluster,omitempty"` - ClusterPrivilege []map[string][]string `json:"cluster_privilege,omitempty"` + ClusterPrivilege []string `json:"cluster_privilege,omitempty"` Index []struct { Name []string `json:"name"` Privilege []string `json:"privilege"` From 0fea8b97b3fa1d152cfc1828dd654e54210940cc Mon Sep 17 00:00:00 2001 From: xushuhui Date: Tue, 26 Apr 2022 11:19:56 +0800 Subject: [PATCH 56/75] fix: (rbac) --- internal/biz/role.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/biz/role.go b/internal/biz/role.go index 899be203..13d652f2 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -265,7 +265,6 @@ func DeleteRole(localUser *User, id string) (err error) { role.ID = id _, err = orm.Get(&role) if err != nil { - err = ErrNotFound return } err = orm.Delete(role) @@ -306,7 +305,6 @@ func GetRole(id string) (role rbac.Role, err error) { role.ID = id _, err = orm.Get(&role) if err != nil { - err = ErrNotFound return } return From 46025622975d08def59a17da9bea0113287e77ed Mon Sep 17 00:00:00 2001 From: xushuhui Date: Tue, 26 Apr 2022 11:23:02 +0800 Subject: [PATCH 57/75] fix: (rbac) delete role --- internal/biz/role.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/internal/biz/role.go b/internal/biz/role.go index 13d652f2..8a927102 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -263,11 +263,8 @@ func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { func DeleteRole(localUser *User, id string) (err error) { role := rbac.Role{} role.ID = id - _, err = orm.Get(&role) - if err != nil { - return - } - err = orm.Delete(role) + + err = orm.Delete(&role) if err != nil { return } From 236d340b3bf97dcced68eea01103773984fa7c8a Mon Sep 17 00:00:00 2001 From: xushuhui Date: Tue, 26 Apr 2022 18:45:15 +0800 Subject: [PATCH 58/75] fix: (rbac) validate es permission --- config/map.json | 70 +++++++------- config/permission.json | 116 ++++++++++------------- internal/biz/permission.go | 10 +- internal/biz/role.go | 3 - internal/biz/user.go | 4 + internal/biz/validate.go | 170 +++++++++++++++++++++------------- internal/biz/validate_test.go | 139 +++++++++++++-------------- internal/middleware/user.go | 63 ++++++++++--- plugin/api/init.go | 16 ++-- plugin/api/rbac/api.go | 23 +++++ 10 files changed, 349 insertions(+), 265 deletions(-) diff --git a/config/map.json b/config/map.json index c05ac5b3..9b00c6e7 100644 --- a/config/map.json +++ b/config/map.json @@ -1,6 +1,6 @@ { "DELETE-/_ingest/pipeline/:id": "ingest.delete_pipeline", - "DELETE-/_scripts/:id": "DELETE-_script", + "DELETE-/_scripts/:id": "script.delete", "DELETE-/_search/scroll": "clear_scroll", "DELETE-/_search/scroll/:scroll_id": "clear_scroll", "DELETE-/_snapshot/:repository": "snapshot.delete_repository", @@ -11,7 +11,7 @@ "DELETE-/:index/_aliases/:name": "indices.delete_alias", "DELETE-/:index/_doc/:id": "doc.delete", - "GET-/": "info", + "GET-/": "cluster.info", "GET-/_alias": "indices.get_alias", "GET-/_alias/:name": "indices.get_alias", "GET-/_analyze": "indices.analyze", @@ -60,8 +60,8 @@ "GET-/_cluster/state/:metric/:index": "cluster.state", "GET-/_cluster/stats": "cluster.stats", "GET-/_cluster/stats/nodes/:node_id": "cluster.stats", - "GET-/_count": "count", - "GET-/_field_caps": "field_caps", + "GET-/_count": "cluster.count", + "GET-/_flush": "indices.flush", "GET-/_flush/synced": "indices.flush_synced", "GET-/_ingest/pipeline": "ingest.get_pipeline", @@ -71,10 +71,10 @@ "GET-/_ingest/processor/grok": "ingest.processor_grok", "GET-/_mapping": "indices.get_mapping", - "GET-/_mget": "mget", - "GET-/_msearch": "msearch", - "GET-/_msearch/template": "msearch_template", - "GET-/_mtermvectors": "mtermvectors", + "GET-/_mget": "cluster.mget", + "GET-/_msearch": "cluster.msearch", + "GET-/_msearch/template": "cluster.msearch_template", + "GET-/_mtermvectors": "cluster.mtermvectors", "GET-/_nodes": "nodes.info", "GET-/_nodes/hot_threads": "nodes.hot_threads", "GET-/_nodes/hotthreads": "nodes.hot_threads", @@ -93,15 +93,15 @@ "GET-/_nodes/:node_id/usage": "nodes.usage", "GET-/_nodes/:node_id/usage/:metric": "nodes.usage", "GET-/_nodes/:node_id/:metric": "nodes.info", - "GET-/_rank_eval": "rank_eval", + "GET-/_rank_eval": "cluster.rank_eval", "GET-/_recovery": "indices.recovery", "GET-/_refresh": "indices.refresh", "GET-/_remote/info": "cluster.remote_info", "GET-/_render/template": "render_search_template", "GET-/_render/template/:id": "render_search_template", - "GET-/_scripts/painless/_execute": "scripts_painless_execute", - "GET-/_scripts/:id": "get_script", - "GET-/_search": "search", + "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/template": "search_template", @@ -128,25 +128,25 @@ "GET-/:index/_alias": "indices.get_alias", "GET-/:index/_alias/:name": "indices.get_alias", "GET-/:index/_analyze": "indices.analyze", - "GET-/:index/_count": "count", + "GET-/:index/_count": "indices.count", "GET-/:index/_doc/:id": "doc.get", - "GET-/:index/_field_caps": "field_caps", + "GET-/:index/_field_caps": "indices.field_caps", "GET-/:index/_flush": "indices.flush", "GET-/:index/_flush/synced": "indices.flush_synced", "GET-/:index/_mapping": "indices.get_mapping", "GET-/:index/_mappings": "indices.get_mapping", "GET-/:index/_mapping/field/:fields": "indices.get_field_mapping", - "GET-/:index/_mget": "mget", - "GET-/:index/_msearch": "msearch", - "GET-/:index/_msearch/template": "msearch_template", - "GET-/:index/_mtermvectors": "mtermvectors", - "GET-/:index/_rank_eval": "rank_eval", + "GET-/:index/_mget": "indices.mget", + "GET-/:index/_msearch": "indices.msearch", + "GET-/:index/_msearch/template": "indices.msearch_template", + "GET-/:index/_mtermvectors": "indices.mtermvectors", + "GET-/:index/_rank_eval": "indices.rank_eval", "GET-/:index/_recovery": "indices.recovery", "GET-/:index/_refresh": "indices.refresh", - "GET-/:index/_search": "search", - "GET-/:index/_search/template": "search_template", - "GET-/:index/_search_shards": "search_shards", + "GET-/:index/_search": "indices.search", + "GET-/:index/_search/template": "indices.search_template", + "GET-/:index/_search_shards": "indices.search_shards", "GET-/:index/_segments": "indices.segments", "GET-/:index/_settings": "indices.get_settings", "GET-/:index/_settings/:name": "indices.get_settings", @@ -156,35 +156,39 @@ "GET-/:index/_upgrade": "indices.get_upgrade", "GET-/:index/_validate/query": "indices.validate_query", - "HEAD-/": "info", + "HEAD-/": "cluster.info", "HEAD-/_alias/:name": "indices.exists_alias", "HEAD-/_template/:name": "indices.exists_template", "HEAD-/:index": "indices.exists", "HEAD-/:index/_alias/:name": "indices.exists_alias", + "HEAD-/:index/_analyze": "indices.analyze", + "HEAD-/:index/_mapping/{type}": "indices.exists_type", + "HEAD-/:index/_doc/{id}": "doc.exists", + "HEAD-/:index/_doc/{id}/_source": "doc.exists_source", "POST-/_aliases": "indices.update_aliases", "POST-/_analyze": "indices.analyze", - "POST-/_bulk": "bulk", + "POST-/_bulk": "cluster.bulk", "POST-/_cache/clear": "indices.clear_cache", "POST-/_cluster/allocation/explain": "cluster.allocation_explain", "POST-/_cluster/reroute": "cluster.reroute", - "POST-/_count": "count", - "POST-/_DELETE-_by_query/:task_id/_rethrottle": "reindex_rethrottle", - "POST-/_field_caps": "field_caps", + "POST-/_count": "cluster.count", + "POST-/_delete_by_query/:task_id/_rethrottle": "reindex_rethrottle", + "POST-/_field_caps": "cluster.field_caps", "POST-/_flush": "indices.flush", "POST-/_flush/synced": "indices.flush_synced", "POST-/_forcemerge": "indices.forcemerge", "POST-/_ingest/pipeline/_simulate": "ingest.simulate", "POST-/_ingest/pipeline/:id/_simulate": "ingest.simulate", - "POST-/_mget": "mget", - "POST-/_msearch": "msearch", - "POST-/_msearch/template": "msearch_template", - "POST-/_mtermvectors": "mtermvectors", + "POST-/_mget": "cluster.mget", + "POST-/_msearch": "cluster.msearch", + "POST-/_msearch/template": "cluster.msearch_template", + "POST-/_mtermvectors": "cluster.mtermvectors", "POST-/_nodes/reload_secure_settings": "nodes.reload_secure_settings", "POST-/_nodes/:node_id/reload_secure_settings": "nodes.reload_secure_settings", - "POST-/_rank_eval": "rank_eval", + "POST-/_rank_eval": "cluster.rank_eval", "POST-/_refresh": "indices.refresh", "POST-/_reindex": "reindex", "POST-/_reindex/:task_id/_rethrottle": "reindex_rethrottle", @@ -217,7 +221,7 @@ "POST-/:index/_cache/clear": "indices.clear_cache", "POST-/:index/_close": "indices.close", "POST-/:index/_count": "count", - "POST-/:index/_DELETE-_by_query": "DELETE-_by_query", + "POST-/:index/_delete_by_query": "indices.delete_by_query", "POST-/:index/_doc": "doc.create", "POST-/:index/_doc/:id": "doc.put", "POST-/:index/_doc/:id/_update": "doc.update", diff --git a/config/permission.json b/config/permission.json index cd79821e..28fb3a84 100644 --- a/config/permission.json +++ b/config/permission.json @@ -1,8 +1,5 @@ { - "bulk": [ - "bulk" - ], "cat": [ "cat.*", "cat.indices", @@ -36,32 +33,38 @@ "cluster.allocation_explain", "cluster.put_settings", "cluster.reroute", - "cluster.state" - ], - "count": [ - "*", - "count" + "cluster.count", + "cluster.state", + "cluster.info", + "cluster.bulk", + "cluster.mget", + "cluster.ping", + "cluster.msearch", + "cluster.msearch_template", + "cluster.mtermvectors", + "cluster.rank_eval", + "cluster.search" ], + "doc": [ "doc.*", "doc.update", "doc.put", "doc.create", - "doc.delete" + "doc.delete", + "doc.get", + "doc.exists", + "doc.count", + "doc.exists_source", + "doc.bulk", + "doc.explain", + "doc.mget", + "doc.msearch", + "doc.msearch_template", + "doc.mtermvectors", + "doc.search" ], - "exists": [ - "exists" - ], - "explain": [ - "explain" - ], - "field_caps": [ - "field_caps" - ], - "get": [ - "get" - ], "indices": [ "indices.*", "indices.exists_alias", @@ -103,11 +106,19 @@ "indices.stats", "indices.delete_by_query", "indices.rollover", - "indices.shard_stores" - ], - "info": [ - "info" + "indices.count", + "indices.shard_stores", + "indices.bulk", + "indices.mget", + "indices.msearch", + "indices.msearch_template", + "indices.mtermvectors", + "indices.rank_eval", + "indices.search", + "indices.search_shards", + "indices.field_caps" ], + "ingest": [ "ingest.*", "ingest.delete_pipeline", @@ -116,18 +127,7 @@ "ingest.get_pipeline", "ingest.processor_grok" ], - "mget": [ - "mget" - ], - "msearch": [ - "msearch" - ], - "msearch_template": [ - "msearch_template" - ], - "mtermvectors": [ - "mtermvectors" - ], + "nodes": [ "nodes.*", "nodes.info", @@ -136,42 +136,27 @@ "nodes.usage", "nodes.hot_threads" ], - "ping": [ - "ping" - ], - "rank_eval": [ - "rank_eval" - ], + "reindex": [ - "reindex" - ], - "reindex_rethrottle": [ - "reindex_rethrottle" + "reindex.*", + "reindex.rethrottle" ], + "render_search_template": [ - "render_search_template" + "render_search_template.*" ], "scripts": [ "scripts.*", "scripts.get", "scripts.put", - "scripts.delete" - ], - "scripts_painless_execute": [ - "scripts_painless_execute" + "scripts.delete", + "scripts.painless_execute" ], + "scroll": [ - "scroll.delete" - ], - "search": [ - "search" - ], - "search_shards": [ - "search_shards" - ], - "search_template": [ - "search_template" + "scroll.*" ], + "snapshot": [ "snapshot.*", "snapshot.get_repository", @@ -184,12 +169,9 @@ "snapshot.verify_repository", "snapshot.get" ], - "source": [ - "source.*", - "source.head", - "source.get" - ], + "tasks": [ + "tasks.*", "tasks.list", "tasks.cancel", "tasks.get" diff --git a/internal/biz/permission.go b/internal/biz/permission.go index c2d2af7a..d8f0cbb6 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -22,11 +22,11 @@ type Role struct { } `json:"index,omitempty"` } type RolePermission struct { - Platform []string `json:"platform,omitempty"` - Cluster []string `json:"cluster"` - ClusterPrivilege []string `json:"cluster_privilege"` - Index []string `json:"index"` - IndexPrivilege []string `json:"index_privilege"` + 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 { Platform []Platform `json:"platform"` diff --git a/internal/biz/role.go b/internal/biz/role.go index 8a927102..74e2bb00 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -306,10 +306,7 @@ func GetRole(id string) (role rbac.Role, err error) { } return } -func ListRoleByName(names []string) (roles []rbac.Role, err error) { - return -} func SearchRole(keyword string, from, size int) (roles orm.Result, err error) { query := orm.Query{} diff --git a/internal/biz/user.go b/internal/biz/user.go index b9a1f3f1..fef24840 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -75,6 +75,7 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) { Name: v.Name, }) } + hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) if err != nil { @@ -237,3 +238,6 @@ func SearchUser(keyword string, from, size int) (users orm.Result, err error) { return } +func UpdateUserPassword(localUser *User, id string, password string) (err error) { + return +} diff --git a/internal/biz/validate.go b/internal/biz/validate.go index 80e6a818..ccab4af0 100644 --- a/internal/biz/validate.go +++ b/internal/biz/validate.go @@ -3,75 +3,61 @@ package biz import ( "errors" httprouter "infini.sh/framework/core/api/router" - "net/http" + "strings" ) type EsRequest struct { - Method string `json:"method"` - Cluster []string `json:"cluster"` - - Index []string `json:"index"` - Doc string `json:"doc"` - Path string `json:"path"` + Doc string `json:"doc"` + Privilege string `json:"privilege"` + ClusterRequest + IndexRequest +} +type ClusterRequest struct { + Cluster []string `json:"cluster"` + Privilege []string `json:"privilege"` +} +type IndexRequest struct { + Cluster []string `json:"cluster"` + Index []string `json:"index"` + Privilege []string `json:"privilege"` } -func NewEsRequest(r *http.Request, ps httprouter.Params) EsRequest { - - //GET elasticsearch/c6dgjtgvi076f32oibj0/index/test/_mappings - clusterId := ps.ByName("id") +func NewIndexRequest(ps httprouter.Params, privilege []string) IndexRequest { index := ps.ByName("index") - - doc := ps.ByName("docId") - //如果index存在,说明调用的是index api - return EsRequest{ - Cluster: []string{clusterId}, - Index: []string{index}, - Doc: doc, - Path: r.URL.Path, - Method: r.Method, + clusterId := ps.ByName("id") + return IndexRequest{ + Cluster: []string{clusterId}, + Index: []string{index}, + Privilege: privilege, } } -func ValidateEsPermission(req EsRequest, userRole RolePermission) (err error) { - - route, err := EsApiRoutes.Handle(req.Method, req.Path) - if err != nil { - - return +func NewClusterRequest(ps httprouter.Params, privilege []string) ClusterRequest { + clusterId := ps.ByName("id") + return ClusterRequest{ + Cluster: []string{clusterId}, + Privilege: privilege, } - if len(req.Index) > 0 { - err = validateIndex(req, userRole, route) - if err != nil { - return err - } - } - err = validateCluster(req, userRole, route) - return } -func validateIndex(req EsRequest, userRole RolePermission, route string) (err error) { + +//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{}) - privilegeMap := make(map[string]struct{}) - for _, v := range userRole.Index { - userIndexMap[v] = struct{}{} - } - for _, v := range userRole.IndexPrivilege { - privilegeMap[v] = struct{}{} - } - for _, v := range req.Index { - if _, ok := userIndexMap[v]; !ok { - err = errors.New("no index permission") - return - } - } - - if _, ok := privilegeMap[route]; !ok { - err = errors.New("no index api permission") - return - } - - return -} -func validateCluster(req EsRequest, userRole RolePermission, route string) (err error) { userClusterMap := make(map[string]struct{}) for _, v := range userRole.Cluster { userClusterMap[v] = struct{}{} @@ -82,19 +68,68 @@ func validateCluster(req EsRequest, userRole RolePermission, route string) (err return } } + for _, v := range userRole.Index { + userIndexMap[v] = struct{}{} + } - for _, v := range userRole.ClusterPrivilege { - if v == route { - return nil + 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, ".")] + for _, v := range req.Index { + privilege, ok := userRole.IndexPrivilege[v] + if !ok { + err = errors.New("no index api permission in user role") + return err + } + for _, p := range privilege { + if p == prefix+".*" { + return nil + } + if p == val { + return nil + } + } + } + } + + return errors.New("no index api permission in user role") +} +func ValidateCluster(req ClusterRequest, userRole RolePermission) (err error) { + userClusterMap := make(map[string]struct{}) + for _, v := range userRole.Cluster { + userClusterMap[v] = struct{}{} + } + for _, v := range req.Cluster { + if _, ok := userClusterMap[v]; !ok { + err = errors.New("no cluster permission") + 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+".*" { + + return nil + } + if v == privilege { + return nil + } + } + } + return errors.New("no cluster api permission") } -func FilterCluster() { -} func CombineUserRoles(roleNames []string) RolePermission { newRole := RolePermission{} + m := make(map[string][]string) for _, val := range roleNames { role := RoleMap[val] for _, v := range role.Cluster { @@ -108,8 +143,17 @@ func CombineUserRoles(roleNames []string) RolePermission { } for _, v := range role.Index { newRole.Index = append(newRole.Index, v.Name...) - newRole.IndexPrivilege = append(newRole.IndexPrivilege, v.Privilege...) + for _, name := range v.Name { + if _, ok := m[name]; ok { + m[name] = append(m[name], v.Privilege...) + } else { + m[name] = v.Privilege + } + + } + } } + newRole.IndexPrivilege = m return newRole } diff --git a/internal/biz/validate_test.go b/internal/biz/validate_test.go index cd7fc47f..caf1e9ab 100644 --- a/internal/biz/validate_test.go +++ b/internal/biz/validate_test.go @@ -7,7 +7,7 @@ import ( func Test_validateIndex(t *testing.T) { type args struct { - req EsRequest + req IndexRequest userRole RolePermission route string } @@ -16,64 +16,64 @@ func Test_validateIndex(t *testing.T) { 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: 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", + //}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := validateIndex(tt.args.req, tt.args.userRole, tt.args.route) + got := ValidateIndex(tt.args.req, tt.args.userRole) assert.EqualError(t, got, tt.want) }) @@ -81,9 +81,8 @@ func Test_validateIndex(t *testing.T) { } func Test_validateCluster(t *testing.T) { type args struct { - req EsRequest + req ClusterRequest userRole RolePermission - route string } tests := []struct { name string @@ -92,11 +91,10 @@ func Test_validateCluster(t *testing.T) { }{ {"no cluster permission", args{ - req: EsRequest{ - Method: "GET", - Cluster: []string{"cluster1"}, - Index: []string{"index2"}, - Path: "/index1/_mapping", + req: ClusterRequest{ + + Cluster: []string{"cluster1"}, + Privilege: []string{"indices.get_mapping"}, }, userRole: RolePermission{ Cluster: []string{ @@ -108,20 +106,15 @@ func Test_validateCluster(t *testing.T) { ClusterPrivilege: []string{ "cat.*", }, - IndexPrivilege: []string{ - "indices.get_mapping", - }, }, - route: "indices.get_mapping", }, "no cluster permission", }, {"no cluster api permission", args{ - req: EsRequest{ - Method: "GET", - Cluster: []string{"cluster1"}, - Index: []string{"index1"}, - Path: "/index1/_mapping", + req: ClusterRequest{ + + Cluster: []string{"cluster1"}, + Privilege: []string{"indices.get_mapping"}, }, userRole: RolePermission{ Cluster: []string{ @@ -134,11 +127,7 @@ func Test_validateCluster(t *testing.T) { ClusterPrivilege: []string{ "cat.*", }, - IndexPrivilege: []string{ - "indices.delete", - }, }, - route: "indices.get_mapping", }, "no cluster api permission", }, @@ -147,7 +136,7 @@ func Test_validateCluster(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := validateCluster(tt.args.req, tt.args.userRole, tt.args.route) + got := ValidateCluster(tt.args.req, tt.args.userRole) assert.EqualError(t, got, tt.want) }) diff --git a/internal/middleware/user.go b/internal/middleware/user.go index 9e6c0579..cc919d2e 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -19,21 +19,60 @@ 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 - } + //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) } } diff --git a/plugin/api/init.go b/plugin/api/init.go index df7775d2..c7086030 100644 --- a/plugin/api/init.go +++ b/plugin/api/init.go @@ -2,6 +2,7 @@ package api import ( "infini.sh/console/config" + m "infini.sh/console/internal/middleware" "infini.sh/console/plugin/api/alerting" "infini.sh/console/plugin/api/index_management" "infini.sh/framework/core/api" @@ -23,22 +24,23 @@ func Init(cfg *config.AppConfig) { //api.HandleAPIMethod(api.GET, "/api/dict/:id",handler.GetDictItemAction) api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "dict/:id"), handler.DeleteDictItemAction) api.HandleAPIMethod(api.PUT, path.Join(pathPrefix, "dict/:id"), handler.UpdateDictItemAction) + api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index/_search"), handler.HandleSearchDocumentAction) api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index"), handler.HandleAddDocumentAction) api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "doc/:index/:docId"), handler.HandleUpdateDocumentAction) - api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "doc/:index/:docId"), handler.HandleDeleteDocumentAction) + api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "doc/:index/:docId"), m.ClusterRequired(handler.HandleDeleteDocumentAction, "doc.delete")) api.HandleAPIMethod(api.GET, path.Join(esPrefix, "doc/_validate"), handler.ValidateDocIDAction) api.HandleAPIMethod(api.POST, path.Join(pathPrefix, "rebuild/*id"), handler.HandleReindexAction) api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "rebuild/_search"), handler.HandleGetRebuildListAction) api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "rebuild/:id"), handler.HandleDeleteRebuildAction) - api.HandleAPIMethod(api.GET, path.Join(esPrefix, "_cat/indices"), handler.HandleGetIndicesAction) - api.HandleAPIMethod(api.GET, path.Join(esPrefix, "index/:index/_mappings"), handler.HandleGetMappingsAction) - api.HandleAPIMethod(api.GET, path.Join(esPrefix, "index/:index/_settings"), handler.HandleGetSettingsAction) - api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "index/:index/_settings"), handler.HandleUpdateSettingsAction) - api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "index/:index"), handler.HandleDeleteIndexAction) - api.HandleAPIMethod(api.POST, path.Join(esPrefix, "index/:index"), handler.HandleCreateIndexAction) + api.HandleAPIMethod(api.GET, path.Join(esPrefix, "_cat/indices"), m.ClusterRequired(handler.HandleGetIndicesAction, "cat.indices")) + api.HandleAPIMethod(api.GET, path.Join(esPrefix, "index/:index/_mappings"), m.IndexRequired(handler.HandleGetMappingsAction, "indices.get_mapping")) + api.HandleAPIMethod(api.GET, path.Join(esPrefix, "index/:index/_settings"), m.IndexRequired(handler.HandleGetSettingsAction, "indices.get_settings")) + api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "index/:index/_settings"), m.IndexRequired(handler.HandleUpdateSettingsAction, "indices.put_mapping")) + api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "index/:index"), m.IndexRequired(handler.HandleDeleteIndexAction, "indices.delete")) + api.HandleAPIMethod(api.POST, path.Join(esPrefix, "index/:index"), m.IndexRequired(handler.HandleCreateIndexAction, "indices.create")) api.HandleAPIMethod(api.POST, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleAddCommonCommandAction) api.HandleAPIMethod(api.PUT, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleSaveCommonCommandAction) diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index c34ef3af..3997ce28 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -74,6 +74,29 @@ func loadRolePermission() { biz.RoleMap["admin"] = biz.Role{ Platform: enum.AdminPrivilege, + Cluster: []struct { + Id string `json:"id"` + Name string `json:"name"` + }{ + { + Id: "c97rd2les10hml00pgh0", + Name: "docker-cluster", + }, + }, + ClusterPrivilege: []string{"cat.*"}, + Index: []struct { + Name []string `json:"name"` + Privilege []string `json:"privilege"` + }{ + { + Name: []string{".infini_rbac-role"}, + Privilege: []string{"indices.get_mapping"}, + }, + { + Name: []string{".infini_rbac-user", ".infini_rbac-role"}, + Privilege: []string{"cat.*"}, + }, + }, } res, err := biz.SearchRole("", 0, 100) if err != nil { From 8bcda063fb5d8cfccfbefe7f5ddb34764a57da79 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Tue, 26 Apr 2022 20:04:11 +0800 Subject: [PATCH 59/75] feat: (rbac) update user password --- internal/biz/role.go | 8 +++++--- internal/biz/user.go | 45 ++++++++++++++++++++++++++++++++++------- internal/dto/role.go | 3 +++ plugin/api/rbac/api.go | 2 +- plugin/api/rbac/user.go | 35 ++++++++++++++++++++++++++++++-- 5 files changed, 80 insertions(+), 13 deletions(-) diff --git a/internal/biz/role.go b/internal/biz/role.go index 74e2bb00..d9c7b8e5 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -72,10 +72,12 @@ func (role ConsoleRole) Update(localUser *User, model rbac.Role) (err error) { if err != nil { return } - RoleMap[role.Name] = Role{ + + RoleMap[model.Name] = Role{ Name: model.Name, Platform: model.Platform, } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -107,7 +109,7 @@ func (role ElasticsearchRole) Update(localUser *User, model rbac.Role) (err erro if err != nil { return } - RoleMap[role.Name] = Role{ + RoleMap[model.Name] = Role{ Name: model.Name, Cluster: model.Cluster, ClusterPrivilege: model.ClusterPrivilege, @@ -227,7 +229,7 @@ func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { return } id = newRole.ID - RoleMap[role.Name] = Role{ + RoleMap[newRole.Name] = Role{ Name: newRole.Name, Cluster: newRole.Cluster, ClusterPrivilege: newRole.ClusterPrivilege, diff --git a/internal/biz/user.go b/internal/biz/user.go index fef24840..7b92d07e 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -21,7 +21,6 @@ func DeleteUser(localUser *User, id string) (err error) { user.ID = id _, err = orm.Get(&user) if err != nil { - err = ErrNotFound return } err = orm.Delete(user) @@ -55,7 +54,7 @@ func DeleteUser(localUser *User, id string) (err error) { }, nil)) return } -func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) { +func CreateUser(localUser *User, req dto.CreateUser) (id string, password string, err error) { q := orm.Query{Size: 1000} q.Conds = orm.And(orm.Eq("username", req.Username)) @@ -75,10 +74,9 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) { Name: v.Name, }) } - - hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost) + randStr := util.GenerateRandomString(8) + hash, err := bcrypt.GenerateFromPassword([]byte(randStr), bcrypt.DefaultCost) if err != nil { - return } user := rbac.User{ @@ -99,6 +97,7 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, err error) { return } id = user.ID + password = randStr err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -128,7 +127,6 @@ func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { user.ID = id _, err = orm.Get(&user) if err != nil { - err = ErrNotFound return } roles := make([]rbac.UserRole, 0) @@ -175,7 +173,7 @@ func UpdateUserRole(localUser *User, id string, req dto.UpdateUserRole) (err err user.ID = id _, err = orm.Get(&user) if err != nil { - err = ErrNotFound + return } changeLog, _ := util.DiffTwoObject(user, req) @@ -239,5 +237,38 @@ func SearchUser(keyword string, from, size int) (users orm.Result, err error) { } func UpdateUserPassword(localUser *User, id string, password string) (err error) { + user := rbac.User{} + user.ID = id + _, err = orm.Get(&user) + if err != nil { + + return + } + hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return + } + user.Password = string(hash) + user.Updated = time.Now() + err = orm.Save(&user) + if err != nil { + return + } + + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "user", + Type: "update", + Labels: util.MapStr{ + "id": id, + "password": password, + "updated": user.Updated, + }, + User: util.MapStr{ + "userid": localUser.UserId, + "username": localUser.Username, + }, + }, nil, nil)) return } diff --git a/internal/dto/role.go b/internal/dto/role.go index 1fc41450..eeb4484f 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -38,3 +38,6 @@ type UpdateUser struct { type UpdateUserRole struct { Roles []Role `json:"roles"` } +type UpdateUserPassword struct { + Password string `json:"password"` +} diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index 3997ce28..1eb847c9 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -34,7 +34,7 @@ func init() { api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAll...)) api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAll...)) api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserRead...)) - + api.HandleAPIMethod(api.PUT, "/user/:id/password", m.PermissionRequired(r.UpdateUserPassword, enum.UserAll...)) } func loadJsonConfig() { diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index 9bdb7f18..f42c060b 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -6,6 +6,7 @@ import ( "infini.sh/console/internal/core" "infini.sh/console/internal/dto" httprouter "infini.sh/framework/core/api/router" + "infini.sh/framework/core/util" "infini.sh/framework/modules/elastic" "net/http" log "src/github.com/cihub/seelog" @@ -39,13 +40,17 @@ func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error(w, err) return } - id, err := biz.CreateUser(localUser, req) + id, pass, err := biz.CreateUser(localUser, req) if err != nil { _ = log.Error(err.Error()) h.Error(w, err) return } - _ = h.WriteOKJSON(w, core.CreateResponse(id)) + _ = h.WriteOKJSON(w, util.MapStr{ + "_id": id, + "password": pass, + "result": "created", + }) return } @@ -159,3 +164,29 @@ func (h Rbac) SearchUser(w http.ResponseWriter, r *http.Request, ps httprouter.P return } +func (h Rbac) UpdateUserPassword(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + id := ps.MustGetParameter("id") + var req dto.UpdateUserPassword + err := h.DecodeJSON(r, &req) + if err != nil { + _ = log.Error(err.Error()) + h.Error400(w, err.Error()) + return + } + localUser, err := biz.FromUserContext(r.Context()) + if err != nil { + log.Error(err.Error()) + h.Error(w, err) + return + } + err = biz.UpdateUserPassword(localUser, id, req.Password) + if err != nil { + _ = log.Error(err.Error()) + h.Error(w, err) + return + } + + _ = h.WriteOKJSON(w, core.UpdateResponse(id)) + return + +} From f95a336098d24c991d7cabc749b6ad4e16b4aa73 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Tue, 26 Apr 2022 20:35:12 +0800 Subject: [PATCH 60/75] fix: (rbac) update user privilege where update role or delete role --- internal/biz/role.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/biz/role.go b/internal/biz/role.go index d9c7b8e5..bda17896 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -265,12 +265,19 @@ func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { func DeleteRole(localUser *User, id string) (err error) { role := rbac.Role{} role.ID = id + roleName := role.Name + _, err = orm.Get(&role) + if err != nil { + return + } err = orm.Delete(&role) if err != nil { return } - delete(RoleMap, role.Name) + + delete(RoleMap, roleName) + err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", From 598c655a445872dcbb9b44aed8d89c2179943b54 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 27 Apr 2022 10:22:35 +0800 Subject: [PATCH 61/75] fix: (rbac) handle error --- internal/biz/enum/const.go | 8 +++--- internal/biz/role.go | 12 ++++++-- internal/dto/role.go | 14 ++++----- internal/middleware/user.go | 54 +++++++++++++++++------------------ plugin/api/account/account.go | 14 ++++----- plugin/api/init.go | 6 ++-- plugin/api/rbac/api.go | 53 +++++++++++++++++----------------- plugin/api/rbac/permission.go | 2 +- plugin/api/rbac/role.go | 24 +++++++++------- plugin/api/rbac/user.go | 28 +++++++++--------- 10 files changed, 112 insertions(+), 103 deletions(-) diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 6309252c..a0dcefea 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -4,11 +4,11 @@ import ( "time" ) -var UserRead = []string{"system.user:read"} -var UserAll = []string{"system.user:all"} +const UserRead = "system.user:read" +const UserAll = "system.user:all" -var RoleRead = []string{"system.role:read"} -var RoleAll = []string{"system.role:all"} +const RoleRead = "system.role:read" +const RoleAll = "system.role:all" var RuleRead = []string{"rule::read"} var RuleAll = []string{"rule::read", "rule::write"} diff --git a/internal/biz/role.go b/internal/biz/role.go index bda17896..dc17d724 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -1,6 +1,7 @@ package biz import ( + "errors" "fmt" "infini.sh/console/internal/biz/enum" "infini.sh/console/model/rbac" @@ -26,7 +27,7 @@ type IRole interface { } type ConsoleRole struct { Name string `json:"name"` - Description string `json:"description" ` + Description string `json:"description"` RoleType string `json:"type" ` Platform []string `json:"platform,omitempty"` } @@ -135,6 +136,10 @@ func (role ElasticsearchRole) Update(localUser *User, model rbac.Role) (err erro return } func (role ConsoleRole) Create(localUser *User) (id string, err error) { + if role.Name == "" { + err = errors.New("role name is require") + return + } if _, ok := enum.BuildRoles[role.Name]; ok { err = fmt.Errorf("role name %s already exists", role.Name) return @@ -196,7 +201,10 @@ func (role ConsoleRole) Create(localUser *User) (id string, err error) { } func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { - + if role.Name == "" { + err = errors.New("role name is require") + return + } if _, ok := enum.BuildRoles[role.Name]; ok { err = fmt.Errorf("role name %s already exists", role.Name) return diff --git a/internal/dto/role.go b/internal/dto/role.go index eeb4484f..e0ca51f0 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -16,13 +16,13 @@ type ElasticsearchPermission struct { IndexPrivilege []string `json:"index_privilege" ` } type CreateUser struct { - Username string `json:"username"` - Password string `json:"password"` - Name string `json:"name"` - Email string `json:"email"` - Phone string `json:"phone"` - Roles []Role `json:"roles"` - Tags []string `json:"tags"` + Username string `json:"username"` + + Name string `json:"name"` + Email string `json:"email"` + Phone string `json:"phone"` + Roles []Role `json:"roles"` + Tags []string `json:"tags"` } type Role struct { Id string `json:"id"` diff --git a/internal/middleware/user.go b/internal/middleware/user.go index cc919d2e..46fcc0fa 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -22,39 +22,39 @@ func LoginRequired(h httprouter.Handle) httprouter.Handle { 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 - //} + 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 - //} + 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) } } diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index d01f3a4f..d10f93ec 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -33,13 +33,13 @@ func (h Account) Login(w http.ResponseWriter, r *http.Request, ps httprouter.Par var req dto.Login err := h.DecodeJSON(r, &req) if err != nil { - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } data, err := biz.Login(req.Username, req.Password) if err != nil { - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } data["status"] = "ok" @@ -100,7 +100,7 @@ func (h Account) Logout(w http.ResponseWriter, r *http.Request, ps httprouter.Pa func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { reqUser, err := biz.FromUserContext(r.Context()) if err != nil { - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } @@ -116,7 +116,7 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P } else { user, err := biz.GetUser(reqUser.UserId) if err != nil { - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } u := util.MapStr{ @@ -133,18 +133,18 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P func (h Account) UpdatePassword(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { reqUser, err := biz.FromUserContext(r.Context()) if err != nil { - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } var req dto.UpdatePassword err = h.DecodeJSON(r, &req) if err != nil { - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } err = biz.UpdatePassword(reqUser, req) if err != nil { - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } h.WriteOKJSON(w, util.MapStr{ diff --git a/plugin/api/init.go b/plugin/api/init.go index c7086030..b4b2f4ec 100644 --- a/plugin/api/init.go +++ b/plugin/api/init.go @@ -25,9 +25,9 @@ func Init(cfg *config.AppConfig) { api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "dict/:id"), handler.DeleteDictItemAction) api.HandleAPIMethod(api.PUT, path.Join(pathPrefix, "dict/:id"), handler.UpdateDictItemAction) - api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index/_search"), handler.HandleSearchDocumentAction) - api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index"), handler.HandleAddDocumentAction) - api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "doc/:index/:docId"), handler.HandleUpdateDocumentAction) + api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index/_search"), m.IndexRequired(handler.HandleSearchDocumentAction, "doc.search")) + api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index"), m.IndexRequired(handler.HandleAddDocumentAction, "doc.create")) + api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "doc/:index/:docId"), m.IndexRequired(handler.HandleUpdateDocumentAction, "doc.create")) api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "doc/:index/:docId"), m.ClusterRequired(handler.HandleDeleteDocumentAction, "doc.delete")) api.HandleAPIMethod(api.GET, path.Join(esPrefix, "doc/_validate"), handler.ValidateDocIDAction) diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index 1eb847c9..49993a27 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -12,7 +12,6 @@ import ( "path" log "src/github.com/cihub/seelog" "src/github.com/mitchellh/mapstructure" - "strings" ) type Rbac struct { @@ -22,19 +21,19 @@ type Rbac struct { func init() { r := Rbac{} api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) - api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAll...)) - api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleRead...)) - api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAll...)) - api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.RoleAll...)) - api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.RoleRead...)) + api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAll)) + api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleRead)) + api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAll)) + api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.RoleAll)) + api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.RoleRead)) - api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.UserAll...)) - api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.UserRead...)) - api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.UserAll...)) - api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAll...)) - api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAll...)) - api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserRead...)) - api.HandleAPIMethod(api.PUT, "/user/:id/password", m.PermissionRequired(r.UpdateUserPassword, enum.UserAll...)) + api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.UserAll)) + api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.UserRead)) + api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.UserAll)) + api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAll)) + api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAll)) + api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserRead)) + api.HandleAPIMethod(api.PUT, "/user/:id/password", m.PermissionRequired(r.UpdateUserPassword, enum.UserAll)) } func loadJsonConfig() { @@ -54,19 +53,19 @@ func loadJsonConfig() { delete(apis, "indices") biz.ClusterApis = apis - bytes, err = util.FileGetContent(path.Join(pwd, "/config/map.json")) - if err != nil { - panic("load json file err " + err.Error()) - } - esapiMap := make(map[string]string) - err = json.Unmarshal(bytes, &esapiMap) - if err != nil { - panic("json config unmarshal err " + err.Error()) - } - for k, v := range esapiMap { - s := strings.Split(k, "-") - biz.EsApiRoutes.AddRoute(s[0], s[1], v) - } + //bytes, err = util.FileGetContent(path.Join(pwd, "/config/map.json")) + //if err != nil { + // panic("load json file err " + err.Error()) + //} + //esapiMap := make(map[string]string) + //err = json.Unmarshal(bytes, &esapiMap) + //if err != nil { + // panic("json config unmarshal err " + err.Error()) + //} + //for k, v := range esapiMap { + // s := strings.Split(k, "-") + // biz.EsApiRoutes.AddRoute(s[0], s[1], v) + //} } func loadRolePermission() { @@ -98,7 +97,7 @@ func loadRolePermission() { }, }, } - res, err := biz.SearchRole("", 0, 100) + res, err := biz.SearchRole("", 0, 1000) if err != nil { log.Error(err) return diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index 7a356cc8..1f30c770 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -19,7 +19,7 @@ func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprout if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } permissions := role.ListPermission() diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 267f14b3..5de2fcfb 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -17,12 +17,12 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } irole, err := biz.NewRole(roleType) if err != nil { - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } @@ -31,12 +31,13 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error400(w, err.Error()) return } + var id string id, err = irole.Create(localUser) if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } _ = h.WriteOKJSON(w, core.CreateResponse(id)) @@ -55,7 +56,8 @@ func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.P res, err := biz.SearchRole(keyword, from, size) if err != nil { log.Error(err) - h.Error(w, err) + + h.ErrorInternalServer(w, err.Error()) return } response := elastic.SearchResponse{} @@ -91,7 +93,7 @@ func (h Rbac) GetRole(w http.ResponseWriter, r *http.Request, ps httprouter.Para if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } h.WriteOKJSON(w, core.Response{Hit: role}) @@ -104,14 +106,14 @@ func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.P localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } err = biz.DeleteRole(localUser, id) if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } _ = h.WriteOKJSON(w, core.DeleteResponse(id)) @@ -123,17 +125,17 @@ func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } model, err := biz.GetRole(id) if err != nil { - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } irole, err := biz.NewRole(model.RoleType) if err != nil { - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } @@ -147,7 +149,7 @@ func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } _ = h.WriteOKJSON(w, core.UpdateResponse(id)) diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index f42c060b..9423b729 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -29,21 +29,21 @@ func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error400(w, err.Error()) return } - if req.Username == "" || req.Password == "" { + if req.Username == "" || req.Phone == "" || req.Email == "" { - h.Error400(w, "username or password require") + h.Error400(w, "username and phone and email is require") return } localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } id, pass, err := biz.CreateUser(localUser, req) if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } _ = h.WriteOKJSON(w, util.MapStr{ @@ -65,7 +65,7 @@ func (h Rbac) GetUser(w http.ResponseWriter, r *http.Request, ps httprouter.Para if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } h.WriteOKJSON(w, core.FoundResponse(id, user)) @@ -84,14 +84,14 @@ func (h Rbac) UpdateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } err = biz.UpdateUser(localUser, id, req) if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } _ = h.WriteOKJSON(w, core.UpdateResponse(id)) @@ -110,14 +110,14 @@ func (h Rbac) UpdateUserRole(w http.ResponseWriter, r *http.Request, ps httprout localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } err = biz.UpdateUserRole(localUser, id, req) if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } _ = h.WriteOKJSON(w, core.UpdateResponse(id)) @@ -129,7 +129,7 @@ func (h Rbac) DeleteUser(w http.ResponseWriter, r *http.Request, ps httprouter.P localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } err = biz.DeleteUser(localUser, id) @@ -139,7 +139,7 @@ func (h Rbac) DeleteUser(w http.ResponseWriter, r *http.Request, ps httprouter.P } if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } _ = h.WriteOKJSON(w, core.DeleteResponse(id)) @@ -156,7 +156,7 @@ func (h Rbac) SearchUser(w http.ResponseWriter, r *http.Request, ps httprouter.P res, err := biz.SearchUser(keyword, from, size) if err != nil { log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } @@ -176,13 +176,13 @@ func (h Rbac) UpdateUserPassword(w http.ResponseWriter, r *http.Request, ps http localUser, err := biz.FromUserContext(r.Context()) if err != nil { log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } err = biz.UpdateUserPassword(localUser, id, req.Password) if err != nil { _ = log.Error(err.Error()) - h.Error(w, err) + h.ErrorInternalServer(w, err.Error()) return } From e865ee5f67c89a94289c9523e70be5f80d195905 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 27 Apr 2022 14:22:12 +0800 Subject: [PATCH 62/75] test: (rbac) validate index and cluster unit test --- config/map.json | 68 ++++++++++----------- config/permission.json | 13 +++- internal/biz/enum/const.go | 23 ++----- internal/biz/permission.go | 12 ++-- internal/biz/validate.go | 66 +++++++------------- internal/biz/validate_test.go | 109 +++++++++++++++------------------- internal/middleware/es.go | 47 +++++++++++++++ internal/middleware/user.go | 57 ------------------ 8 files changed, 173 insertions(+), 222 deletions(-) create mode 100644 internal/middleware/es.go diff --git a/config/map.json b/config/map.json index 9b00c6e7..cb35bded 100644 --- a/config/map.json +++ b/config/map.json @@ -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", diff --git a/config/permission.json b/config/permission.json index 28fb3a84..c5d94519 100644 --- a/config/permission.json +++ b/config/permission.json @@ -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": [ diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index a0dcefea..88926055 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -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) - } diff --git a/internal/biz/permission.go b/internal/biz/permission.go index d8f0cbb6..2db9398d 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -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() @@ -22,11 +22,11 @@ type Role struct { } `json:"index,omitempty"` } 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"` + Platform []string `json:"platform,omitempty"` + Cluster []string `json:"cluster"` + ClusterPrivilege []string `json:"cluster_privilege"` + + IndexPrivilege map[string][]string `json:"index_privilege"` } type ConsolePermisson struct { Platform []Platform `json:"platform"` diff --git a/internal/biz/validate.go b/internal/biz/validate.go index ccab4af0..37b3ec35 100644 --- a/internal/biz/validate.go +++ b/internal/biz/validate.go @@ -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+".*" { - return nil - } - if p == val { - return nil - } + if util.StringInArray(privilege, prefix+".*") { + return nil } + 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,17 +89,16 @@ 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+".*" { - return nil - } - if v == privilege { - return nil - } + if util.StringInArray(userRole.ClusterPrivilege, prefix+".*") { + return nil + } + if util.StringInArray(userRole.ClusterPrivilege, privilege) { + return nil } } @@ -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...) diff --git a/internal/biz/validate_test.go b/internal/biz/validate_test.go index caf1e9ab..befa264f 100644 --- a/internal/biz/validate_test.go +++ b/internal/biz/validate_test.go @@ -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.*", }, diff --git a/internal/middleware/es.go b/internal/middleware/es.go new file mode 100644 index 00000000..32e4ca94 --- /dev/null +++ b/internal/middleware/es.go @@ -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) + } +} diff --git a/internal/middleware/user.go b/internal/middleware/user.go index 46fcc0fa..9b41edf8 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -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) { From 7006c0b256d85af5285a13727d67f8d5d24cd371 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 27 Apr 2022 16:49:03 +0800 Subject: [PATCH 63/75] feat: (rbac) validate index and cluster unit test --- internal/biz/enum/const.go | 3 +- internal/biz/validate.go | 24 +++++ internal/biz/validate_test.go | 169 +++++++++++++++++++++++++++++++++- internal/middleware/user.go | 1 - main.go | 2 +- plugin/api/init.go | 2 +- plugin/api/rbac/api.go | 26 +----- plugin/api/rbac/role.go | 8 +- 8 files changed, 201 insertions(+), 34 deletions(-) diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 88926055..218f4bfc 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -27,7 +27,8 @@ func init() { BuildRoles["admin"] = map[string]interface{}{ "id": "admin", "name": "管理员", - "platform": []string{"system.role:all", "system.user:all"}, + "type": "console", + "platform": AdminPrivilege, "builtin": true, "description": "is admin", "created": time.Now(), diff --git a/internal/biz/validate.go b/internal/biz/validate.go index 37b3ec35..b35ffad9 100644 --- a/internal/biz/validate.go +++ b/internal/biz/validate.go @@ -135,3 +135,27 @@ func CombineUserRoles(roleNames []string) RolePermission { newRole.IndexPrivilege = m return newRole } +func FilterCluster(roles []string, cluster []string) []string { + newRole := CombineUserRoles(roles) + userClusterMap := make(map[string]struct{}, 0) + for _, v := range newRole.Cluster { + userClusterMap[v] = struct{}{} + } + realCluster := make([]string, 0) + for _, v := range cluster { + if _, ok := userClusterMap[v]; ok { + realCluster = append(realCluster, v) + } + } + return realCluster +} +func FilterIndex(roles []string, index []string) []string { + realIndex := make([]string, 0) + newRole := CombineUserRoles(roles) + for _, v := range index { + if _, ok := newRole.IndexPrivilege[v]; ok { + realIndex = append(realIndex, v) + } + } + return realIndex +} diff --git a/internal/biz/validate_test.go b/internal/biz/validate_test.go index befa264f..a1b82c1c 100644 --- a/internal/biz/validate_test.go +++ b/internal/biz/validate_test.go @@ -2,6 +2,7 @@ package biz import ( "github.com/stretchr/testify/assert" + "infini.sh/framework/core/util" "testing" ) @@ -99,6 +100,18 @@ func Test_validateCluster(t *testing.T) { }, }, "no cluster permission", }, + {"no cluster", + args{ + req: ClusterRequest{ + Cluster: []string{"cluster1"}, + Privilege: []string{"indices.get_mapping"}, + }, + userRole: RolePermission{ + Cluster: []string{}, + ClusterPrivilege: []string{}, + }, + }, "no cluster permission", + }, {"no cluster api", args{ req: ClusterRequest{ @@ -122,10 +135,162 @@ func Test_validateCluster(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := ValidateCluster(tt.args.req, tt.args.userRole) - assert.EqualError(t, got, tt.want) }) } } +func TestStringInArray(t *testing.T) { + array := []string{"a", "b", "c", "d", "e"} + assert.Equal(t, true, util.StringInArray(array, "c")) + assert.Equal(t, false, util.StringInArray(array, "h")) +} +func TestFilterCluster(t *testing.T) { + RoleMap["test"] = Role{ + Cluster: []struct { + Id string `json:"id"` + Name string `json:"name"` + }{ + { + Id: "c97rd2les10hml00pgh0", + Name: "docker-cluster", + }, + }, + ClusterPrivilege: []string{"cat.*"}, + Index: []struct { + Name []string `json:"name"` + Privilege []string `json:"privilege"` + }{ + { + Name: []string{".infini_rbac-role"}, + Privilege: []string{"indices.get_mapping"}, + }, + { + Name: []string{".infini_rbac-user", ".infini_rbac-role"}, + Privilege: []string{"cat.*"}, + }, + }, + } + type args struct { + roles []string + cluster []string + } + tests := []struct { + name string + args args + want []string + }{ + { + name: "empty", + args: args{ + roles: []string{"test"}, + cluster: []string{ + "cluser1", "cluster2", + }, + }, + want: []string{}, + }, + { + name: "one", + args: args{ + roles: []string{"test"}, + cluster: []string{ + "cluser1", "cluster2", "c97rd2les10hml00pgh0", + }, + }, + want: []string{"c97rd2les10hml00pgh0"}, + }, + { + name: "only", + args: args{ + roles: []string{"test"}, + cluster: []string{ + "c97rd2les10hml00pgh0", + }, + }, + want: []string{"c97rd2les10hml00pgh0"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := FilterCluster(tt.args.roles, tt.args.cluster) + assert.Equal(t, got, tt.want) + }) + } + +} +func TestFilterIndex(t *testing.T) { + RoleMap["test"] = Role{ + Cluster: []struct { + Id string `json:"id"` + Name string `json:"name"` + }{ + { + Id: "c97rd2les10hml00pgh0", + Name: "docker-cluster", + }, + }, + ClusterPrivilege: []string{"cat.*"}, + Index: []struct { + Name []string `json:"name"` + Privilege []string `json:"privilege"` + }{ + { + Name: []string{".infini_rbac-role"}, + Privilege: []string{"indices.get_mapping"}, + }, + { + Name: []string{".infini_rbac-user", ".infini_rbac-role"}, + Privilege: []string{"cat.*"}, + }, + }, + } + + type args struct { + roles []string + index []string + } + tests := []struct { + name string + args args + want []string + }{ + { + name: "empty", + args: args{ + roles: []string{"test"}, + index: []string{ + "index1", "index2", + }, + }, + want: []string{}, + }, + { + name: "one", + args: args{ + roles: []string{"test"}, + index: []string{ + "index1", "index2", ".infini_rbac-user", + }, + }, + want: []string{".infini_rbac-user"}, + }, + { + name: "only", + args: args{ + roles: []string{"test"}, + index: []string{ + ".infini_rbac-user", + }, + }, + want: []string{".infini_rbac-user"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := FilterIndex(tt.args.roles, tt.args.index) + assert.Equal(t, got, tt.want) + }) + } + +} diff --git a/internal/middleware/user.go b/internal/middleware/user.go index 9b41edf8..3f13b419 100644 --- a/internal/middleware/user.go +++ b/internal/middleware/user.go @@ -26,7 +26,6 @@ func PermissionRequired(h httprouter.Handle, permissions ...string) httprouter.H if err != nil { w = handleError(w, http.StatusUnauthorized, err) - return } err = biz.ValidatePermission(claims, permissions) diff --git a/main.go b/main.go index 2ae5dca2..ce11dd6f 100644 --- a/main.go +++ b/main.go @@ -138,8 +138,8 @@ func main() { if err != nil { log.Errorf("init alerting task error: %v", err) } - rbacApi.Init() }() + go rbacApi.Init() }, nil) { app.Run() diff --git a/plugin/api/init.go b/plugin/api/init.go index b4b2f4ec..5de226e1 100644 --- a/plugin/api/init.go +++ b/plugin/api/init.go @@ -27,7 +27,7 @@ func Init(cfg *config.AppConfig) { api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index/_search"), m.IndexRequired(handler.HandleSearchDocumentAction, "doc.search")) api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index"), m.IndexRequired(handler.HandleAddDocumentAction, "doc.create")) - api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "doc/:index/:docId"), m.IndexRequired(handler.HandleUpdateDocumentAction, "doc.create")) + api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "doc/:index/:docId"), m.IndexRequired(handler.HandleUpdateDocumentAction, "doc.update")) api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "doc/:index/:docId"), m.ClusterRequired(handler.HandleDeleteDocumentAction, "doc.delete")) api.HandleAPIMethod(api.GET, path.Join(esPrefix, "doc/_validate"), handler.ValidateDocIDAction) diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index 49993a27..1fecaa7d 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -2,6 +2,7 @@ package rbac import ( "encoding/json" + "github.com/mitchellh/mapstructure" "infini.sh/console/internal/biz" "infini.sh/console/internal/biz/enum" m "infini.sh/console/internal/middleware" @@ -11,7 +12,6 @@ import ( "os" "path" log "src/github.com/cihub/seelog" - "src/github.com/mitchellh/mapstructure" ) type Rbac struct { @@ -73,30 +73,8 @@ func loadRolePermission() { biz.RoleMap["admin"] = biz.Role{ Platform: enum.AdminPrivilege, - Cluster: []struct { - Id string `json:"id"` - Name string `json:"name"` - }{ - { - Id: "c97rd2les10hml00pgh0", - Name: "docker-cluster", - }, - }, - ClusterPrivilege: []string{"cat.*"}, - Index: []struct { - Name []string `json:"name"` - Privilege []string `json:"privilege"` - }{ - { - Name: []string{".infini_rbac-role"}, - Privilege: []string{"indices.get_mapping"}, - }, - { - Name: []string{".infini_rbac-user", ".infini_rbac-role"}, - Privilege: []string{"cat.*"}, - }, - }, } + res, err := biz.SearchRole("", 0, 1000) if err != nil { log.Error(err) diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 5de2fcfb..403f8f3b 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -56,17 +56,17 @@ func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.P res, err := biz.SearchRole(keyword, from, size) if err != nil { log.Error(err) - h.ErrorInternalServer(w, err.Error()) return } response := elastic.SearchResponse{} util.FromJSONBytes(res.Raw, &response) - list := response.Hits.Hits + hits := response.Hits.Hits + list := make([]elastic.IndexDocument, 0) total := response.GetTotal() var index string - for _, v := range list { + for _, v := range hits { index = v.Index } for k, v := range enum.BuildRoles { @@ -78,7 +78,7 @@ func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.P }) total++ } - + list = append(list, hits...) response.Hits.Hits = list response.Hits.Total = total From 2acae3582a546b8c9e9ec2c804bbc30535b8dac7 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Wed, 27 Apr 2022 18:20:50 +0800 Subject: [PATCH 64/75] fix: (rbac) user profile phone --- internal/biz/account.go | 23 +++++++++++++++++++---- internal/biz/enum/menu.go | 7 ------- internal/biz/permission.go | 9 +++++++++ internal/biz/user.go | 3 ++- plugin/api/account/account.go | 2 ++ plugin/api/init.go | 2 +- plugin/api/rbac/api.go | 1 + 7 files changed, 34 insertions(+), 13 deletions(-) delete mode 100644 internal/biz/enum/menu.go diff --git a/internal/biz/account.go b/internal/biz/account.go index ae23b002..b3dfd653 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -104,6 +104,7 @@ func authorize(user Account) (m map[string]interface{}, err error) { if err != nil { return } + m = util.MapStr{ "access_token": tokenString, "username": user.Username, @@ -133,6 +134,7 @@ func Login(username string, password string) (m map[string]interface{}, err erro if err != nil { return } + TokenMap[user.ID] = Token{ExpireIn: time.Now().Unix() + 86400} err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -185,23 +187,36 @@ func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { return } tokenString := fields[1] + token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } - return []byte(Secret), nil }) if err != nil { return } - if clams, ok := token.Claims.(*UserClaims); ok && token.Valid { - return clams, nil - } + clams, ok := token.Claims.(*UserClaims) + if clams.UserId == "" { err = errors.New("user id is empty") return } + fmt.Println("user token", clams.UserId, TokenMap[clams.UserId]) + tokenVal, ok := TokenMap[clams.UserId] + if !ok { + err = errors.New("token is invalid") + return + } + if tokenVal.ExpireIn < time.Now().Unix() { + err = errors.New("token is expire in") + delete(TokenMap, clams.UserId) + return + } + if ok && token.Valid { + return clams, nil + } return } diff --git a/internal/biz/enum/menu.go b/internal/biz/enum/menu.go deleted file mode 100644 index 3d75ee6e..00000000 --- a/internal/biz/enum/menu.go +++ /dev/null @@ -1,7 +0,0 @@ -package enum - -type Menu struct { - Id string `json:"id"` - - Privilege string `json:"privilege,omitempty"` -} diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 2db9398d..b4199c64 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -6,6 +6,15 @@ var ClusterApis = make(map[string][]string) var IndexApis = make([]string, 50) var RoleMap = make(map[string]Role) + +type Token struct { + JwtStr string `json:"jwt_str"` + Value string `json:"value"` + ExpireIn int64 `json:"expire_in"` +} + +var TokenMap = make(map[string]Token) + var EsApiRoutes = core.NewRouter() type Role struct { diff --git a/internal/biz/user.go b/internal/biz/user.go index 7b92d07e..b5acafd2 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -27,7 +27,8 @@ func DeleteUser(localUser *User, id string) (err error) { if err != nil { return } - + fmt.Println("tokenmap", TokenMap) + delete(TokenMap, id) err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index d10f93ec..06048cf7 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -111,6 +111,7 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P "username": "admin", "email": "admin@infini.ltd", "name": "admin", + "phone": "13011111111", } h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) } else { @@ -124,6 +125,7 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P "username": user.Username, "email": user.Email, "name": user.Name, + "phone": user.Phone, } h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) } diff --git a/plugin/api/init.go b/plugin/api/init.go index 5de226e1..0d66b36b 100644 --- a/plugin/api/init.go +++ b/plugin/api/init.go @@ -28,7 +28,7 @@ func Init(cfg *config.AppConfig) { api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index/_search"), m.IndexRequired(handler.HandleSearchDocumentAction, "doc.search")) api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index"), m.IndexRequired(handler.HandleAddDocumentAction, "doc.create")) api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "doc/:index/:docId"), m.IndexRequired(handler.HandleUpdateDocumentAction, "doc.update")) - api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "doc/:index/:docId"), m.ClusterRequired(handler.HandleDeleteDocumentAction, "doc.delete")) + api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "doc/:index/:docId"), m.IndexRequired(handler.HandleDeleteDocumentAction, "doc.delete")) api.HandleAPIMethod(api.GET, path.Join(esPrefix, "doc/_validate"), handler.ValidateDocIDAction) api.HandleAPIMethod(api.POST, path.Join(pathPrefix, "rebuild/*id"), handler.HandleReindexAction) diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index 1fecaa7d..2578f9e5 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -19,6 +19,7 @@ type Rbac struct { } func init() { + r := Rbac{} api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAll)) From c472adbf32aff41cb011f4d277568d41a7a13c5e Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 28 Apr 2022 10:50:57 +0800 Subject: [PATCH 65/75] feat: (rbac) permission map --- internal/biz/account.go | 123 +++++++++++----------------------- internal/biz/enum/const.go | 72 +++++++++++++++++--- internal/biz/validate.go | 99 +++++++++++++++++++++++++++ internal/dto/user.go | 5 ++ plugin/api/account/account.go | 28 ++++++-- plugin/api/rbac/api.go | 24 +++---- plugin/api/rbac/user.go | 2 +- 7 files changed, 243 insertions(+), 110 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index b3dfd653..47d62fc8 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -2,7 +2,6 @@ package biz import ( "errors" - "fmt" "github.com/golang-jwt/jwt" "github.com/mitchellh/mapstructure" "golang.org/x/crypto/bcrypt" @@ -13,7 +12,6 @@ import ( "infini.sh/framework/core/orm" "infini.sh/framework/core/util" - "strings" "time" ) @@ -156,7 +154,7 @@ func UpdatePassword(localUser *User, req dto.UpdatePassword) (err error) { user.ID = localUser.UserId _, err = orm.Get(&user) if err != nil { - err = ErrNotFound + return } err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword)) @@ -173,93 +171,50 @@ func UpdatePassword(localUser *User, req dto.UpdatePassword) (err error) { if err != nil { return } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "user", + Type: "update", + Labels: util.MapStr{ + "old_password": req.OldPassword, + "new_password": req.NewPassword, + }, + User: util.MapStr{ + "userid": user.ID, + "username": user.Username, + }, + }, nil, nil)) return } -func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { - - if authorizationHeader == "" { - err = errors.New("authorization header is empty") - return - } - fields := strings.Fields(authorizationHeader) - if fields[0] != "Bearer" || len(fields) != 2 { - err = errors.New("authorization header is invalid") - return - } - tokenString := fields[1] - - token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) { - if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { - return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) - } - return []byte(Secret), nil - }) +func UpdateProfile(localUser *User, req dto.UpdateProfile) (err error) { + user := rbac.User{} + user.ID = localUser.UserId + _, err = orm.Get(&user) if err != nil { return } - clams, ok := token.Claims.(*UserClaims) - - if clams.UserId == "" { - err = errors.New("user id is empty") + user.Name = req.Name + user.Email = req.Email + user.Phone = req.Phone + err = orm.Save(&user) + if err != nil { return } - fmt.Println("user token", clams.UserId, TokenMap[clams.UserId]) - tokenVal, ok := TokenMap[clams.UserId] - if !ok { - err = errors.New("token is invalid") - return - } - if tokenVal.ExpireIn < time.Now().Unix() { - err = errors.New("token is expire in") - delete(TokenMap, clams.UserId) - return - } - if ok && token.Valid { - return clams, nil - } + err = orm.Save(GenerateEvent(event.ActivityMetadata{ + Category: "platform", + Group: "rbac", + Name: "user", + Type: "update", + Labels: util.MapStr{ + "name": req.Name, + "email": req.Email, + "phone": req.Phone, + }, + User: util.MapStr{ + "userid": user.ID, + "username": user.Username, + }, + }, nil, nil)) return - -} -func ValidatePermission(claims *UserClaims, permissions []string) (err error) { - - user := claims.User - - if user.UserId == "" { - err = errors.New("user id is empty") - return - } - if user.Roles == nil { - err = errors.New("api permission is empty") - return - } - - // 权限校验 - userPermissionMap := make(map[string]struct{}) - for _, role := range user.Roles { - if _, ok := RoleMap[role]; ok { - for _, v := range RoleMap[role].Platform { - - userPermissionMap[v] = struct{}{} - //all include read - if strings.Contains(v, "all") { - key := v[:len(v)-3] + "read" - userPermissionMap[key] = struct{}{} - } - } - } - } - - var count int - for _, v := range permissions { - if _, ok := userPermissionMap[v]; ok { - count++ - continue - } - } - if count == len(permissions) { - return nil - } - err = errors.New("permission denied") - return - } diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 218f4bfc..09345fdd 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -4,20 +4,60 @@ import ( "time" ) -const UserRead = "system.user:read" -const UserAll = "system.user:all" +var PermissionMap = make(map[string][]string) -const RoleRead = "system.role:read" -const RoleAll = "system.role:all" +const ( + UserRead = "system.user:read" + UserAll = "system.user:all" + RoleRead = "system.role:read" + RoleAll = "system.role:all" + RuleRead = "alerting.rule:read" + RuleAll = "alerting.rule:all" + InstanceRead = "gateway.instance:read" + InstanceAll = "gateway.instance:all" + FlowRead = "gateway.flow:read" + FlowAll = "gateway.flow:all" + IndexAll = "data.index:read" + IndexRead = "data.index:all" + ViewsAll = "data.views:read" + ViewsRead = "data.views:all" + DiscoverAll = "data.discover:read" + DiscoverRead = "data.discover:all" + ClusterAll = "system.cluster:all" + ClusterRead = "system.cluster:read" -const RuleRead = "alerting.rule:read" -const RuleAll = "alerting.rule:all" + CommandAll = "system.command:all" + CommandRead = "system.command:read" -const InstanceRead = "gateway.instance:read" -const InstanceAll = "gateway.instance:all" + EntryAll = "gateway.entry:all" + EntryRead = "gateway.entry:read" + RouterRead = "gateway.router:read" + RouterAll = "gateway.router:all" +) + +var UserReadPermission = []string{"user:read"} +var UserAllPermission = []string{"user:read", "user:write"} + +var RoleReadPermission = []string{"role:read"} +var RoleAllPermission = []string{"role:read", "role:write"} + +var RuleReadPermission = []string{"rule:read"} +var RuleAllPermission = []string{"rule:read", "rule:write"} + +var InstanceReadPermission = []string{"instance:read"} +var InstanceAllPermission = []string{"instance:all"} + +var EntryReadPermission = []string{"entry:read"} +var EntryAllPermission = []string{"entry:all"} + +var RouterReadPermission = []string{"router:read"} +var RouterAllPermission = []string{"router:all"} var AdminPrivilege = []string{ - UserRead, UserAll, RoleRead, RoleAll, + UserAll, RoleAll, RuleAll, EntryAll, + InstanceAll, ClusterAll, CommandAll, RouterAll, + FlowRead, FlowAll, IndexAll, ViewsAll, + DiscoverAll, } var BuildRoles = make(map[string]map[string]interface{}, 0) @@ -33,5 +73,19 @@ func init() { "description": "is admin", "created": time.Now(), } + PermissionMap = map[string][]string{ + UserRead: UserReadPermission, + UserAll: UserAllPermission, + RoleRead: RoleReadPermission, + RoleAll: RoleAllPermission, + RuleRead: RuleReadPermission, + RuleAll: RuleAllPermission, + InstanceRead: InstanceReadPermission, + InstanceAll: InstanceAllPermission, + EntryRead: EntryReadPermission, + EntryAll: EntryAllPermission, + RouterRead: RouterReadPermission, + RouterAll: RouterAllPermission, + } } diff --git a/internal/biz/validate.go b/internal/biz/validate.go index b35ffad9..ebd1bf3b 100644 --- a/internal/biz/validate.go +++ b/internal/biz/validate.go @@ -2,9 +2,13 @@ package biz import ( "errors" + "fmt" + "infini.sh/console/internal/biz/enum" httprouter "infini.sh/framework/core/api/router" "infini.sh/framework/core/util" + "src/github.com/golang-jwt/jwt" "strings" + "time" ) type EsRequest struct { @@ -159,3 +163,98 @@ func FilterIndex(roles []string, index []string) []string { } return realIndex } +func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { + + if authorizationHeader == "" { + err = errors.New("authorization header is empty") + return + } + fields := strings.Fields(authorizationHeader) + if fields[0] != "Bearer" || len(fields) != 2 { + err = errors.New("authorization header is invalid") + return + } + tokenString := fields[1] + + token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + return []byte(Secret), nil + }) + if err != nil { + return + } + clams, ok := token.Claims.(*UserClaims) + + if clams.UserId == "" { + err = errors.New("user id is empty") + return + } + fmt.Println("user token", clams.UserId, TokenMap[clams.UserId]) + tokenVal, ok := TokenMap[clams.UserId] + if !ok { + err = errors.New("token is invalid") + return + } + if tokenVal.ExpireIn < time.Now().Unix() { + err = errors.New("token is expire in") + delete(TokenMap, clams.UserId) + return + } + if ok && token.Valid { + return clams, nil + } + return + +} +func ValidatePermission(claims *UserClaims, permissions []string) (err error) { + + user := claims.User + + if user.UserId == "" { + err = errors.New("user id is empty") + return + } + if user.Roles == nil { + err = errors.New("api permission is empty") + return + } + + // 权限校验 + userPermissions := make([]string, 0) + for _, role := range user.Roles { + if _, ok := RoleMap[role]; ok { + for _, v := range RoleMap[role].Platform { + userPermissions = append(userPermissions, v) + + //all include read + if strings.Contains(v, "all") { + key := v[:len(v)-3] + "read" + userPermissions = append(userPermissions, key) + } + } + } + } + userPermissionMap := make(map[string]struct{}) + for _, val := range userPermissions { + for _, v := range enum.PermissionMap[val] { + userPermissionMap[v] = struct{}{} + } + + } + + var count int + for _, v := range permissions { + if _, ok := userPermissionMap[v]; ok { + count++ + continue + } + } + if count == len(permissions) { + return nil + } + err = errors.New("permission denied") + return + +} diff --git a/internal/dto/user.go b/internal/dto/user.go index a9b4dde7..68d7ed83 100644 --- a/internal/dto/user.go +++ b/internal/dto/user.go @@ -8,3 +8,8 @@ type UpdatePassword struct { OldPassword string `json:"old_password"` NewPassword string `json:"new_password"` } +type UpdateProfile struct { + Name string `json:"name"` + Phone string `json:"phone"` + Email string `json:"email"` +} diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index 06048cf7..638ddcc9 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -92,7 +92,13 @@ func (h Account) CurrentUser(w http.ResponseWriter, req *http.Request, ps httpro } } func (h Account) Logout(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + reqUser, err := biz.FromUserContext(r.Context()) + if err != nil { + h.ErrorInternalServer(w, err.Error()) + return + } + delete(biz.TokenMap, reqUser.UserId) h.WriteOKJSON(w, util.MapStr{ "status": "ok", }) @@ -149,8 +155,22 @@ func (h Account) UpdatePassword(w http.ResponseWriter, r *http.Request, ps httpr h.ErrorInternalServer(w, err.Error()) return } - h.WriteOKJSON(w, util.MapStr{ - "status": "ok", - }) - + h.WriteOKJSON(w, core.UpdateResponse(reqUser.UserId)) + return +} +func (h Account) UpdateProfile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + reqUser, err := biz.FromUserContext(r.Context()) + if err != nil { + h.ErrorInternalServer(w, err.Error()) + return + } + var req dto.UpdateProfile + err = h.DecodeJSON(r, &req) + err = biz.UpdateProfile(reqUser, req) + if err != nil { + h.ErrorInternalServer(w, err.Error()) + return + } + h.WriteOKJSON(w, core.UpdateResponse(reqUser.UserId)) + return } diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index 2578f9e5..591dcb3a 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -22,19 +22,19 @@ func init() { r := Rbac{} api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) - api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAll)) - api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleRead)) - api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAll)) - api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.RoleAll)) - api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.RoleRead)) + api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAllPermission...)) + api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleReadPermission...)) + api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAllPermission...)) + api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.RoleAllPermission...)) + api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.RoleReadPermission...)) - api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.UserAll)) - api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.UserRead)) - api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.UserAll)) - api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAll)) - api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAll)) - api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserRead)) - api.HandleAPIMethod(api.PUT, "/user/:id/password", m.PermissionRequired(r.UpdateUserPassword, enum.UserAll)) + api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.UserAllPermission...)) + api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.UserReadPermission...)) + api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.UserAllPermission...)) + api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAllPermission...)) + api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAllPermission...)) + api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserReadPermission...)) + api.HandleAPIMethod(api.PUT, "/user/:id/password", m.PermissionRequired(r.UpdateUserPassword, enum.UserAllPermission...)) } func loadJsonConfig() { diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index 9423b729..7a00f798 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -185,7 +185,7 @@ func (h Rbac) UpdateUserPassword(w http.ResponseWriter, r *http.Request, ps http h.ErrorInternalServer(w, err.Error()) return } - + delete(biz.TokenMap, localUser.UserId) _ = h.WriteOKJSON(w, core.UpdateResponse(id)) return From 14b2f71af68d717bda0cd7be1578dbc953313026 Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 28 Apr 2022 11:54:49 +0800 Subject: [PATCH 66/75] fix: (rbac) token map --- internal/biz/user.go | 8 +++++--- plugin/api/rbac/permission.go | 5 ----- plugin/api/rbac/user.go | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/internal/biz/user.go b/internal/biz/user.go index b5acafd2..5777ad56 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -27,7 +27,7 @@ func DeleteUser(localUser *User, id string) (err error) { if err != nil { return } - fmt.Println("tokenmap", TokenMap) + delete(TokenMap, id) err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", @@ -148,6 +148,8 @@ func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { if err != nil { return } + delete(TokenMap, id) + err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -191,7 +193,7 @@ func UpdateUserRole(localUser *User, id string, req dto.UpdateUserRole) (err err if err != nil { return } - + delete(TokenMap, id) err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -255,7 +257,7 @@ func UpdateUserPassword(localUser *User, id string, password string) (err error) if err != nil { return } - + delete(TokenMap, localUser.UserId) err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index 1f30c770..a77038a6 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -10,11 +10,6 @@ import ( func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { typ := ps.MustGetParameter("type") - err := biz.IsAllowRoleType(typ) - if err != nil { - h.Error400(w, err.Error()) - return - } role, err := biz.NewRole(typ) if err != nil { diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index 7a00f798..9423b729 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -185,7 +185,7 @@ func (h Rbac) UpdateUserPassword(w http.ResponseWriter, r *http.Request, ps http h.ErrorInternalServer(w, err.Error()) return } - delete(biz.TokenMap, localUser.UserId) + _ = h.WriteOKJSON(w, core.UpdateResponse(id)) return From d7af5dfe126f99fc19a6f7ba3baa0d743dcd12fe Mon Sep 17 00:00:00 2001 From: xushuhui Date: Thu, 28 Apr 2022 14:08:29 +0800 Subject: [PATCH 67/75] feat: (rbac) permission map --- internal/biz/enum/const.go | 160 ++++++++++++++++++++++++++----------- 1 file changed, 115 insertions(+), 45 deletions(-) diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 09345fdd..249bfc4e 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -7,57 +7,101 @@ import ( var PermissionMap = make(map[string][]string) const ( - UserRead = "system.user:read" - UserAll = "system.user:all" - RoleRead = "system.role:read" - RoleAll = "system.role:all" - RuleRead = "alerting.rule:read" - RuleAll = "alerting.rule:all" - InstanceRead = "gateway.instance:read" - InstanceAll = "gateway.instance:all" - FlowRead = "gateway.flow:read" - FlowAll = "gateway.flow:all" - IndexAll = "data.index:read" - IndexRead = "data.index:all" - ViewsAll = "data.views:read" - ViewsRead = "data.views:all" - DiscoverAll = "data.discover:read" - DiscoverRead = "data.discover:all" - ClusterAll = "system.cluster:all" - ClusterRead = "system.cluster:read" - + UserRead = "system.user:read" + UserAll = "system.user:all" + RoleRead = "system.role:read" + RoleAll = "system.role:all" + ClusterAll = "system.cluster:all" + ClusterRead = "system.cluster:read" CommandAll = "system.command:all" CommandRead = "system.command:read" - EntryAll = "gateway.entry:all" - EntryRead = "gateway.entry:read" - RouterRead = "gateway.router:read" - RouterAll = "gateway.router:all" + InstanceRead = "gateway.instance:read" + InstanceAll = "gateway.instance:all" + EntryAll = "gateway.entry:all" + EntryRead = "gateway.entry:read" + RouterRead = "gateway.router:read" + RouterAll = "gateway.router:all" + FlowRead = "gateway.flow:read" + FlowAll = "gateway.flow:all" + + IndexAll = "data.index:all" + IndexRead = "data.index:read" + ViewsAll = "data.views:all" + ViewsRead = "data.views:read" + DiscoverAll = "data.discover:all" + DiscoverRead = "data.discover:read" + + RuleRead = "alerting.rule:read" + RuleAll = "alerting.rule:all" + AlertRead = "alerting.alert:read" + AlertAll = "alerting.alert:all" + ChannelRead = "alerting.channel:read" + ChannelAll = "alerting.channel:all" + + ClusterOverviewRead = "cluster.overview:read" + ClusterOverviewAll = "cluster.overview:all" + ElasticsearchRead = "cluster.elasticsearch:read" + ElasticsearchAll = "cluster.elasticsearch:all" + ActivitiesRead = "cluster.activities:read" + ActivitiesAll = "cluster.activities:all" ) -var UserReadPermission = []string{"user:read"} -var UserAllPermission = []string{"user:read", "user:write"} +var ( + UserReadPermission = []string{"user:read"} + UserAllPermission = []string{"user:read", "user:write"} -var RoleReadPermission = []string{"role:read"} -var RoleAllPermission = []string{"role:read", "role:write"} + RoleReadPermission = []string{"role:read"} + RoleAllPermission = []string{"role:read", "role:write"} -var RuleReadPermission = []string{"rule:read"} -var RuleAllPermission = []string{"rule:read", "rule:write"} + ClusterReadPermission = []string{"cluster:read"} + ClusterAllPermission = []string{"cluster:read", "cluster:write"} -var InstanceReadPermission = []string{"instance:read"} -var InstanceAllPermission = []string{"instance:all"} + CommandReadPermission = []string{"command:read"} + CommandAllPermission = []string{"command:read", "command:write"} -var EntryReadPermission = []string{"entry:read"} -var EntryAllPermission = []string{"entry:all"} + InstanceReadPermission = []string{"instance:read"} + InstanceAllPermission = []string{"instance:read", "instance:write"} -var RouterReadPermission = []string{"router:read"} -var RouterAllPermission = []string{"router:all"} + EntryReadPermission = []string{"entry:read"} + EntryAllPermission = []string{"entry:read", "entry:write"} + + RouterReadPermission = []string{"router:read"} + RouterAllPermission = []string{"router:read", "entry:write"} + + FlowReadPermission = []string{"flow:read"} + FlowAllPermission = []string{"flow:read", "flow:write"} + + IndexAllPermission = []string{"index:read"} + IndexReadPermission = []string{"index:read", "index:write"} + ViewsAllPermission = []string{"views:read"} + ViewsReadPermission = []string{"views:read", "views:write"} + DiscoverReadPermission = []string{"discover:read"} + DiscoverAllPermission = []string{"discover:read", "discover:write"} + + RuleReadPermission = []string{"rule:read"} + RuleAllPermission = []string{"rule:read", "rule:write"} + AlertReadPermission = []string{"alert:read"} + AlertAllPermission = []string{"alert:read", "alert:write"} + ChannelReadPermssion = []string{"channel:read"} + ChannnelAllPermission = []string{"channel:read", "channel:write"} + + ClusterOverviewReadPermission = []string{"clusterOverview:read"} + ClusterOverviewAllPermission = []string{"clusterOverview:read", "clusterOverview:write"} + + ElasticsearchReadPermission = []string{"elasticsearch:read"} + ElasticsearchAllPermission = []string{"elasticsearch:read", "elasticsearch:write"} + + ActivitiesReadPermission = []string{"activities:read"} + ActivitiesAllPermission = []string{"activities:read", "activities:write"} +) var AdminPrivilege = []string{ - UserAll, RoleAll, RuleAll, EntryAll, - InstanceAll, ClusterAll, CommandAll, RouterAll, - FlowRead, FlowAll, IndexAll, ViewsAll, - DiscoverAll, + UserAll, RoleAll, ClusterAll, CommandAll, + InstanceAll, EntryAll, RouterAll, FlowAll, + IndexAll, ViewsAll, DiscoverAll, + RuleAll, AlertAll, ChannelAll, + ClusterOverviewAll, ElasticsearchAll, ActivitiesAll, } var BuildRoles = make(map[string]map[string]interface{}, 0) @@ -74,18 +118,44 @@ func init() { "created": time.Now(), } PermissionMap = map[string][]string{ - UserRead: UserReadPermission, - UserAll: UserAllPermission, - RoleRead: RoleReadPermission, - RoleAll: RoleAllPermission, - RuleRead: RuleReadPermission, - RuleAll: RuleAllPermission, + UserRead: UserReadPermission, + UserAll: UserAllPermission, + RoleRead: RoleReadPermission, + RoleAll: RoleAllPermission, + ClusterRead: ClusterReadPermission, + ClusterAll: ClusterAllPermission, + CommandRead: CommandReadPermission, + CommandAll: CommandAllPermission, + InstanceRead: InstanceReadPermission, InstanceAll: InstanceAllPermission, EntryRead: EntryReadPermission, EntryAll: EntryAllPermission, RouterRead: RouterReadPermission, RouterAll: RouterAllPermission, + FlowRead: FlowReadPermission, + FlowAll: FlowAllPermission, + + IndexAll: IndexAllPermission, + IndexRead: IndexReadPermission, + ViewsAll: ViewsAllPermission, + ViewsRead: ViewsReadPermission, + DiscoverRead: DiscoverReadPermission, + DiscoverAll: DiscoverAllPermission, + + RuleRead: RuleReadPermission, + RuleAll: RuleAllPermission, + AlertRead: AlertReadPermission, + AlertAll: AlertAllPermission, + ChannelRead: ChannelReadPermssion, + ChannelAll: ChannnelAllPermission, + + ClusterOverviewRead: ClusterOverviewReadPermission, + ClusterOverviewAll: ClusterOverviewAllPermission, + ElasticsearchAll: ElasticsearchAllPermission, + ElasticsearchRead: ElasticsearchReadPermission, + ActivitiesAll: ActivitiesAllPermission, + ActivitiesRead: ActivitiesReadPermission, } } From 51497469e40161df2747f4daee1d7301b197123f Mon Sep 17 00:00:00 2001 From: liugq Date: Fri, 6 May 2022 16:01:42 +0800 Subject: [PATCH 68/75] change model data struct --- internal/biz/account.go | 19 ++-- internal/biz/enum/const.go | 12 +- internal/biz/permission.go | 40 ++----- internal/biz/role.go | 208 ++++------------------------------ internal/biz/user.go | 22 ++-- internal/biz/validate.go | 16 +-- internal/dto/role.go | 2 +- model/rbac/role.go | 69 +++++------ model/rbac/user.go | 29 +++-- plugin/api/account/account.go | 8 +- plugin/api/rbac/api.go | 16 ++- plugin/api/rbac/permission.go | 9 +- plugin/api/rbac/role.go | 29 ++--- plugin/api/rbac/user.go | 2 +- 14 files changed, 145 insertions(+), 336 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index 47d62fc8..6513179f 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -11,7 +11,6 @@ import ( "infini.sh/framework/core/global" "infini.sh/framework/core/orm" "infini.sh/framework/core/util" - "time" ) @@ -41,7 +40,7 @@ const Secret = "console" func authenticateUser(username string, password string) (user Account, err error) { - err, result := orm.GetBy("username", username, rbac.User{}) + err, result := orm.GetBy("name", username, rbac.User{}) if err != nil { err = ErrNotFound return @@ -75,7 +74,7 @@ func authenticateAdmin(username string, password string) (user Account, err erro user.ID = username user.Username = username user.Roles = []rbac.UserRole{{ - Id: "admin", Name: "admin", + ID: "admin", Name: "admin", }} return user, nil } @@ -85,7 +84,7 @@ func authorize(user Account) (m map[string]interface{}, err error) { for _, v := range user.Roles { role := RoleMap[v.Name] roles = append(roles, v.Name) - privilege = append(privilege, role.Platform...) + privilege = append(privilege, role.Privilege.Platform...) } token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims{ User: &User{ @@ -143,8 +142,8 @@ func Login(username string, password string) (m map[string]interface{}, err erro "password": password, }, User: util.MapStr{ - "userid": user.ID, - "username": user.Username, + "id": user.ID, + "name": user.Username, }, }, nil, nil)) return @@ -181,8 +180,8 @@ func UpdatePassword(localUser *User, req dto.UpdatePassword) (err error) { "new_password": req.NewPassword, }, User: util.MapStr{ - "userid": user.ID, - "username": user.Username, + "id": user.ID, + "name": user.Name, }, }, nil, nil)) return @@ -212,8 +211,8 @@ func UpdateProfile(localUser *User, req dto.UpdateProfile) (err error) { "phone": req.Phone, }, User: util.MapStr{ - "userid": user.ID, - "username": user.Username, + "id": user.ID, + "name": user.Name, }, }, nil, nil)) return diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 249bfc4e..3992f463 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -27,8 +27,8 @@ const ( IndexAll = "data.index:all" IndexRead = "data.index:read" - ViewsAll = "data.views:all" - ViewsRead = "data.views:read" + ViewsAll = "data.view:all" + ViewsRead = "data.view:read" DiscoverAll = "data.discover:all" DiscoverRead = "data.discover:read" @@ -83,8 +83,8 @@ var ( RuleAllPermission = []string{"rule:read", "rule:write"} AlertReadPermission = []string{"alert:read"} AlertAllPermission = []string{"alert:read", "alert:write"} - ChannelReadPermssion = []string{"channel:read"} - ChannnelAllPermission = []string{"channel:read", "channel:write"} + ChannelReadPermission = []string{"channel:read"} + ChannelAllPermission = []string{"channel:read", "channel:write"} ClusterOverviewReadPermission = []string{"clusterOverview:read"} ClusterOverviewAllPermission = []string{"clusterOverview:read", "clusterOverview:write"} @@ -147,8 +147,8 @@ func init() { RuleAll: RuleAllPermission, AlertRead: AlertReadPermission, AlertAll: AlertAllPermission, - ChannelRead: ChannelReadPermssion, - ChannelAll: ChannnelAllPermission, + ChannelRead: ChannelReadPermission, + ChannelAll: ChannelAllPermission, ClusterOverviewRead: ClusterOverviewReadPermission, ClusterOverviewAll: ClusterOverviewAllPermission, diff --git a/internal/biz/permission.go b/internal/biz/permission.go index b4199c64..5a5234a0 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -1,11 +1,14 @@ package biz -import "infini.sh/console/internal/core" +import ( + "infini.sh/console/internal/core" + "infini.sh/console/model/rbac" +) var ClusterApis = make(map[string][]string) var IndexApis = make([]string, 50) -var RoleMap = make(map[string]Role) +var RoleMap = make(map[string]rbac.Role) type Token struct { JwtStr string `json:"jwt_str"` @@ -17,19 +20,7 @@ var TokenMap = make(map[string]Token) var EsApiRoutes = core.NewRouter() -type Role struct { - Name string `json:"name"` - Platform []string `json:"platform,omitempty"` - Cluster []struct { - Id string `json:"id"` - Name string `json:"name"` - } `json:"cluster,omitempty"` - ClusterPrivilege []string `json:"cluster_privilege,omitempty"` - Index []struct { - Name []string `json:"name"` - Privilege []string `json:"privilege"` - } `json:"index,omitempty"` -} + type RolePermission struct { Platform []string `json:"platform,omitempty"` Cluster []string `json:"cluster"` @@ -37,30 +28,17 @@ type RolePermission struct { IndexPrivilege map[string][]string `json:"index_privilege"` } -type ConsolePermisson struct { - Platform []Platform `json:"platform"` -} -type Platform struct { - Id string `json:"id"` - Privilege map[string]string `json:"privilege,omitempty"` - Children []Platform `json:"children,omitempty"` -} -func (role ConsoleRole) ListPermission() interface{} { - - p := ConsolePermisson{} - return p -} -func (role ElasticsearchRole) ListPermission() interface{} { - list := ElasticsearchPermisson{ +func ListElasticsearchPermission() interface{} { + list := ElasticsearchPermission{ ClusterPrivileges: ClusterApis, IndexPrivileges: IndexApis, } return list } -type ElasticsearchPermisson struct { +type ElasticsearchPermission struct { IndexPrivileges []string `json:"index_privileges"` ClusterPrivileges map[string][]string `json:"cluster_privileges"` } diff --git a/internal/biz/role.go b/internal/biz/role.go index dc17d724..b5d0de28 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -16,68 +16,25 @@ import ( type RoleType = string const ( - Console RoleType = "console" + Platform RoleType = "platform" Elastisearch RoleType = "elasticsearch" ) -type IRole interface { - ListPermission() interface{} - Create(localUser *User) (id string, err error) - Update(localUser *User, model rbac.Role) (err error) -} -type ConsoleRole struct { - Name string `json:"name"` - Description string `json:"description"` - RoleType string `json:"type" ` - Platform []string `json:"platform,omitempty"` -} - -type ElasticsearchRole struct { - Name string `json:"name"` - Description string `json:"description" ` - RoleType string `json:"type" ` - Cluster []struct { - Id string `json:"id"` - Name string `json:"name"` - } `json:"cluster,omitempty"` - ClusterPrivilege []string `json:"cluster_privilege,omitempty"` - Index []struct { - Name []string `json:"name"` - Privilege []string `json:"privilege"` - } `json:"index,omitempty"` -} - -func NewRole(typ string) (r IRole, err error) { - switch typ { - case Console: - r = &ConsoleRole{ - RoleType: typ, - } - - case Elastisearch: - r = &ElasticsearchRole{ - RoleType: typ, - } - default: - err = fmt.Errorf("role type %s not support", typ) +func UpdateRole(localUser *User, role *rbac.Role) (err error) { + model, err := GetRole(role.ID) + if err != nil { + return err } - return -} -func (role ConsoleRole) Update(localUser *User, model rbac.Role) (err error) { - + role.Type = model.Type + role.Created = model.Created changeLog, _ := util.DiffTwoObject(model, role) - model.Description = role.Description - model.Platform = role.Platform - model.Updated = time.Now() - err = orm.Save(model) + role.Updated = time.Now() + err = orm.Save(role) if err != nil { return } - RoleMap[model.Name] = Role{ - Name: model.Name, - Platform: model.Platform, - } + RoleMap[model.Name] = model err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", @@ -87,7 +44,7 @@ func (role ConsoleRole) Update(localUser *User, model rbac.Role) (err error) { Labels: util.MapStr{ "id": model.ID, "description": model.Description, - "platform": model.Platform, + "privilege": role.Privilege, "updated": model.Updated, }, User: util.MapStr{ @@ -98,44 +55,8 @@ func (role ConsoleRole) Update(localUser *User, model rbac.Role) (err error) { return } -func (role ElasticsearchRole) Update(localUser *User, model rbac.Role) (err error) { - changeLog, _ := util.DiffTwoObject(model, role) - model.Description = role.Description - model.Cluster = role.Cluster - model.Index = role.Index - model.ClusterPrivilege = role.ClusterPrivilege - model.Updated = time.Now() - err = orm.Save(model) - if err != nil { - return - } - RoleMap[model.Name] = Role{ - Name: model.Name, - Cluster: model.Cluster, - ClusterPrivilege: model.ClusterPrivilege, - Index: model.Index, - } - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "role", - Type: "update", - Labels: util.MapStr{ - "id": model.ID, - "description": model.Description, - "platform": model.Platform, - "updated": model.Updated, - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, nil, changeLog)) - - return -} -func (role ConsoleRole) Create(localUser *User) (id string, err error) { +func CreateRole(localUser *User, role *rbac.Role) (id string, err error) { if role.Name == "" { err = errors.New("role name is require") return @@ -156,24 +77,15 @@ func (role ConsoleRole) Create(localUser *User) (id string, err error) { return } - newRole := rbac.Role{ - Name: role.Name, - Description: role.Description, - RoleType: role.RoleType, - Platform: role.Platform, - } - newRole.ID = util.GetUUID() - newRole.Created = time.Now() - newRole.Updated = time.Now() - err = orm.Save(&newRole) + role.ID = util.GetUUID() + role.Created = time.Now() + role.Updated = time.Now() + err = orm.Save(role) if err != nil { return } - id = newRole.ID - RoleMap[role.Name] = Role{ - Name: newRole.Name, - Platform: newRole.Platform, - } + id = role.ID + RoleMap[role.Name] = *role err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", @@ -183,10 +95,8 @@ func (role ConsoleRole) Create(localUser *User) (id string, err error) { "id": id, "name": role.Name, "description": role.Description, - "platform": role.Platform, - "type": role.RoleType, - "created": newRole.Created.Format("2006-01-02 15:04:05"), - "updated": newRole.Updated.Format("2006-01-02 15:04:05"), + "privilege": role.Privilege, + "type": role.Type, }, User: util.MapStr{ "userid": localUser.UserId, @@ -200,76 +110,6 @@ func (role ConsoleRole) Create(localUser *User) (id string, err error) { return } -func (role ElasticsearchRole) Create(localUser *User) (id string, err error) { - if role.Name == "" { - err = errors.New("role name is require") - return - } - if _, ok := enum.BuildRoles[role.Name]; ok { - err = fmt.Errorf("role name %s already exists", role.Name) - return - } - q := orm.Query{Size: 1} - q.Conds = orm.And(orm.Eq("name", role.Name)) - - err, result := orm.Search(rbac.Role{}, &q) - if err != nil { - return - } - if result.Total > 0 { - err = fmt.Errorf("role name %s already exists", role.Name) - return - } - - newRole := rbac.Role{ - Name: role.Name, - Description: role.Description, - RoleType: role.RoleType, - } - newRole.Cluster = role.Cluster - newRole.Index = role.Index - newRole.ClusterPrivilege = role.ClusterPrivilege - newRole.ID = util.GetUUID() - newRole.Created = time.Now() - newRole.Updated = time.Now() - err = orm.Save(&newRole) - if err != nil { - return - } - id = newRole.ID - RoleMap[newRole.Name] = Role{ - Name: newRole.Name, - Cluster: newRole.Cluster, - ClusterPrivilege: newRole.ClusterPrivilege, - Index: newRole.Index, - } - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "role", - Type: "create", - Labels: util.MapStr{ - "id": id, - "name": newRole.Name, - "description": newRole.Description, - "cluster": newRole.Cluster, - "index": newRole.Index, - "cluster_privilege": newRole.ClusterPrivilege, - "type": newRole.RoleType, - "created": newRole.Created.Format("2006-01-02 15:04:05"), - "updated": newRole.Updated.Format("2006-01-02 15:04:05"), - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, nil, nil)) - - if err != nil { - log.Error(err) - } - return -} func DeleteRole(localUser *User, id string) (err error) { role := rbac.Role{} role.ID = id @@ -302,11 +142,7 @@ func DeleteRole(localUser *User, id string) (err error) { "id": id, "name": role.Name, "description": role.Description, - "platform": role.Platform, - "cluster": role.Cluster, - "index": role.Index, - "cluster_privilege": role.ClusterPrivilege, - "type": role.RoleType, + "type": role.Type, "created": role.Created.Format("2006-01-02 15:04:05"), "updated": role.Updated.Format("2006-01-02 15:04:05"), }, nil)) @@ -342,7 +178,7 @@ func SearchRole(keyword string, from, size int) (roles orm.Result, err error) { return } func IsAllowRoleType(roleType string) (err error) { - if roleType != Console && roleType != Elastisearch { + if roleType != Platform && roleType != Elastisearch { err = fmt.Errorf("invalid role type %s ", roleType) return } diff --git a/internal/biz/user.go b/internal/biz/user.go index 5777ad56..34a0e20c 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -43,11 +43,11 @@ func DeleteUser(localUser *User, id string) (err error) { }, }, util.MapStr{ "id": id, - "username": user.Username, + "name": user.Name, "email": user.Email, "phone": user.Phone, "password": user.Password, - "name": user.Name, + "nickname": user.NickName, "tags": user.Tags, "roles": user.Roles, "created": user.Created, @@ -57,7 +57,7 @@ func DeleteUser(localUser *User, id string) (err error) { } func CreateUser(localUser *User, req dto.CreateUser) (id string, password string, err error) { q := orm.Query{Size: 1000} - q.Conds = orm.And(orm.Eq("username", req.Username)) + q.Conds = orm.And(orm.Eq("name", req.Name)) err, result := orm.Search(rbac.User{}, &q) if err != nil { @@ -71,7 +71,7 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, password string roles := make([]rbac.UserRole, 0) for _, v := range req.Roles { roles = append(roles, rbac.UserRole{ - Id: v.Id, + ID: v.Id, Name: v.Name, }) } @@ -82,7 +82,7 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, password string } user := rbac.User{ Name: req.Name, - Username: req.Username, + NickName: req.NickName, Password: string(hash), Email: req.Email, Phone: req.Phone, @@ -106,11 +106,11 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, password string Type: "create", Labels: util.MapStr{ "id": id, - "username": user.Username, + "name": user.Name, "email": user.Email, "phone": user.Phone, "password": user.Password, - "name": user.Name, + "nick_name": user.NickName, "tags": user.Tags, "roles": user.Roles, "created": user.Created, @@ -133,7 +133,7 @@ func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { roles := make([]rbac.UserRole, 0) for _, v := range req.Roles { roles = append(roles, rbac.UserRole{ - Id: v.Id, + ID: v.Id, Name: v.Name, }) } @@ -183,7 +183,7 @@ func UpdateUserRole(localUser *User, id string, req dto.UpdateUserRole) (err err roles := make([]rbac.UserRole, 0) for _, v := range req.Roles { roles = append(roles, rbac.UserRole{ - Id: v.Id, + ID: v.Id, Name: v.Name, }) } @@ -257,7 +257,9 @@ func UpdateUserPassword(localUser *User, id string, password string) (err error) if err != nil { return } - delete(TokenMap, localUser.UserId) + if localUser.UserId == id { + delete(TokenMap, localUser.UserId) + } err = orm.Save(GenerateEvent(event.ActivityMetadata{ Category: "platform", Group: "rbac", diff --git a/internal/biz/validate.go b/internal/biz/validate.go index ebd1bf3b..923738b7 100644 --- a/internal/biz/validate.go +++ b/internal/biz/validate.go @@ -114,22 +114,22 @@ func CombineUserRoles(roleNames []string) RolePermission { m := make(map[string][]string) for _, val := range roleNames { role := RoleMap[val] - for _, v := range role.Cluster { - newRole.Cluster = append(newRole.Cluster, v.Id) + for _, v := range role.Privilege.Elasticsearch.Cluster.Resources { + newRole.Cluster = append(newRole.Cluster, v.ID) } - for _, v := range role.ClusterPrivilege { + for _, v := range role.Privilege.Elasticsearch.Cluster.Permissions { newRole.ClusterPrivilege = append(newRole.ClusterPrivilege, v) } - for _, v := range role.Platform { + for _, v := range role.Privilege.Platform { newRole.Platform = append(newRole.Platform, v) } - for _, v := range role.Index { + for _, v := range role.Privilege.Elasticsearch.Index { for _, name := range v.Name { if _, ok := m[name]; ok { - m[name] = append(m[name], v.Privilege...) + m[name] = append(m[name], v.Permissions...) } else { - m[name] = v.Privilege + m[name] = v.Permissions } } @@ -225,7 +225,7 @@ func ValidatePermission(claims *UserClaims, permissions []string) (err error) { userPermissions := make([]string, 0) for _, role := range user.Roles { if _, ok := RoleMap[role]; ok { - for _, v := range RoleMap[role].Platform { + for _, v := range RoleMap[role].Privilege.Platform { userPermissions = append(userPermissions, v) //all include read diff --git a/internal/dto/role.go b/internal/dto/role.go index e0ca51f0..f56a7c48 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -16,7 +16,7 @@ type ElasticsearchPermission struct { IndexPrivilege []string `json:"index_privilege" ` } type CreateUser struct { - Username string `json:"username"` + NickName string `json:"nick_name"` Name string `json:"name"` Email string `json:"email"` diff --git a/model/rbac/role.go b/model/rbac/role.go index ae17b596..6e1e6fb4 100644 --- a/model/rbac/role.go +++ b/model/rbac/role.go @@ -1,51 +1,40 @@ package rbac import ( - "infini.sh/framework/core/orm" + "time" ) type Role struct { - orm.ORMObjectBase - Name string `json:"name" elastic_mapping:"name:{type:keyword}"` - Description string `json:"description" elastic_mapping:"description:{type:text}"` - RoleType string `json:"type" elastic_mapping:"type:{type:keyword}"` - Platform []string `json:"platform,omitempty" ` - BuiltIn bool `json:"builtin" elastic_mapping:"builtin:{type:boolean}"` //是否内置 - - Cluster []struct { - Id string `json:"id"` - Name string `json:"name"` - } `json:"cluster,omitempty"` - ClusterPrivilege []string `json:"cluster_privilege,omitempty"` - Index []struct { - Name []string `json:"name"` - Privilege []string `json:"privilege"` - } `json:"index,omitempty"` -} -type ConsolePermission struct { - Api []string `json:"api"` - Menu []Menu `json:"menu"` + ID string `json:"id,omitempty" elastic_meta:"_id" elastic_mapping:"id: { type: keyword }"` + Created time.Time `json:"created,omitempty" elastic_mapping:"created: { type: date }"` + Updated time.Time `json:"updated,omitempty" elastic_mapping:"updated: { type: date }"` + Name string `json:"name" elastic_mapping:"name: { type: keyword }"` + Type string `json:"type" elastic_mapping:"type: { type: keyword }"` + Description string `json:"description" elastic_mapping:"description: { type: text }"` + Builtin bool `json:"builtin" elastic_mapping:"builtin: { type: boolean }"` + Privilege RolePrivilege `json:"privilege" elastic_mapping:"privilege: { type: object }"` } -type Menu struct { - Id string `json:"id"` - Name string `json:"name"` - Privilege string `json:"privilege"` +type RolePrivilege struct { + Platform []string `json:"platform,omitempty" elastic_mapping:"platform: { type: keyword }"` + Elasticsearch ElasticsearchPrivilege `json:"elasticsearch,omitempty" elastic_mapping:"elasticsearch: { type: object }"` } -type ElasticRole struct { - orm.ORMObjectBase - Name string `json:"name" elastic_mapping:"name:{type:keyword}"` - Description string `json:"description" elastic_mapping:"description:{type:text}"` - RoleType string `json:"type" elastic_mapping:"type:{type:keyword}"` - BuiltIn bool `json:"builtin" elastic_mapping:"builtin:{type:boolean}"` //是否内置 - Cluster []struct { - Id string `json:"id"` - Name string `json:"name"` - } `json:"cluster,omitempty"` - ClusterPrivilege []map[string][]string `json:"cluster_privilege,omitempty"` - Index []struct { - Name []string `json:"name"` - Privilege []string `json:"privilege"` - } `json:"index,omitempty"` +type ElasticsearchPrivilege struct { + Cluster ClusterPrivilege `json:"cluster,omitempty" elastic_mapping:"cluster: { type: object }"` + Index []IndexPrivilege `json:"index,omitempty" elastic_mapping:"index: { type: object }"` } + +type InnerCluster struct { + ID string `json:"id" elastic_mapping:"id: { type: keyword }"` + Name string `json:"name" elastic_mapping:"name: { type: keyword }"` +} +type ClusterPrivilege struct { + Resources []InnerCluster `json:"resources,omitempty" elastic_mapping:"resources: { type: object }"` + Permissions []string `json:"permissions,omitempty" elastic_mapping:"permissions: { type: keyword }"` +} + +type IndexPrivilege struct { + Name []string `json:"name,omitempty" elastic_mapping:"name: { type: keyword }"` + Permissions []string `json:"permissions,omitempty" elastic_mapping:"permissions: { type: keyword }"` +} \ No newline at end of file diff --git a/model/rbac/user.go b/model/rbac/user.go index 1cd131b3..c5f626a4 100644 --- a/model/rbac/user.go +++ b/model/rbac/user.go @@ -1,18 +1,23 @@ package rbac -import "infini.sh/framework/core/orm" +import ( + "time" +) type User struct { - orm.ORMObjectBase - Username string `json:"username" elastic_mapping:"username:{type:keyword}"` - Password string `json:"password" elastic_mapping:"password:{type:text}"` - Name string `json:"name" elastic_mapping:"name:{type:keyword}"` - Phone string `json:"phone" elastic_mapping:"phone:{type:keyword}"` - Email string `json:"email" elastic_mapping:"email:{type:keyword}"` - Roles []UserRole `json:"roles"` - Tags []string `json:"tags,omitempty" elastic_mapping:"tags:{type:text}"` + ID string `json:"id,omitempty" elastic_meta:"_id" elastic_mapping:"id: { type: keyword }"` + Created time.Time `json:"created,omitempty" elastic_mapping:"created: { type: date }"` + Updated time.Time `json:"updated,omitempty" elastic_mapping:"updated: { type: date }"` + Name string `json:"name" elastic_mapping:"name: { type: keyword }"` + NickName string `json:"nick_name" elastic_mapping:"nick_name: { type: keyword }"` + Password string `json:"password" elastic_mapping:"password: { type: keyword }"` + Email string `json:"email" elastic_mapping:"email: { type: keyword }"` + Phone string `json:"phone" elastic_mapping:"phone: { type: keyword }"` + Tags []string `json:"tags" elastic_mapping:"mobile: { type: keyword }"` + Roles []UserRole `json:"roles" elastic_mapping:"roles: { type: object }"` } + type UserRole struct { - Id string `json:"id" elastic_mapping:"id:{type:keyword}"` - Name string `json:"name" elastic_mapping:"name:{type:keyword}" ` -} + ID string `json:"id" elastic_mapping:"id: { type: keyword }"` + Name string `json:"name" elastic_mapping:"name: { type: keyword }"` +} \ No newline at end of file diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index 638ddcc9..e82c627d 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -114,9 +114,9 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P u := util.MapStr{ "user_id": "admin", - "username": "admin", + "name": "admin", "email": "admin@infini.ltd", - "name": "admin", + "nick_name": "admin", "phone": "13011111111", } h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) @@ -128,9 +128,9 @@ func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.P } u := util.MapStr{ "user_id": user.ID, - "username": user.Username, + "name": user.Name, "email": user.Email, - "name": user.Name, + "nick_name": user.NickName, "phone": user.Phone, } h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index 591dcb3a..dccd061b 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -6,12 +6,13 @@ import ( "infini.sh/console/internal/biz" "infini.sh/console/internal/biz/enum" m "infini.sh/console/internal/middleware" + "infini.sh/console/model/rbac" "infini.sh/framework/core/api" "infini.sh/framework/core/elastic" "infini.sh/framework/core/util" "os" "path" - log "src/github.com/cihub/seelog" + log "github.com/cihub/seelog" ) type Rbac struct { @@ -70,10 +71,12 @@ func loadJsonConfig() { } func loadRolePermission() { - biz.RoleMap = make(map[string]biz.Role) + biz.RoleMap = make(map[string]rbac.Role) - biz.RoleMap["admin"] = biz.Role{ - Platform: enum.AdminPrivilege, + biz.RoleMap["admin"] = rbac.Role{ + Privilege: rbac.RolePrivilege{ + Platform: enum.AdminPrivilege, + }, } res, err := biz.SearchRole("", 0, 1000) @@ -85,9 +88,12 @@ func loadRolePermission() { util.FromJSONBytes(res.Raw, &response) for _, v := range response.Hits.Hits { - var role biz.Role + var role rbac.Role + delete(v.Source, "created") + delete(v.Source, "updated") err = mapstructure.Decode(v.Source, &role) if err != nil { + log.Error(err) return } biz.RoleMap[role.Name] = role diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index a77038a6..fc31eb02 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -9,15 +9,16 @@ import ( func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { typ := ps.MustGetParameter("type") - - role, err := biz.NewRole(typ) - + err := biz.IsAllowRoleType(typ) if err != nil { _ = log.Error(err.Error()) h.ErrorInternalServer(w, err.Error()) return } - permissions := role.ListPermission() + var permissions interface{} + if typ == biz.Elastisearch { + permissions = biz.ListElasticsearchPermission() + } h.WriteOKJSON(w, permissions) return } diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index 403f8f3b..ffa6097b 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -5,6 +5,7 @@ import ( "infini.sh/console/internal/biz" "infini.sh/console/internal/biz/enum" "infini.sh/console/internal/core" + "infini.sh/console/model/rbac" httprouter "infini.sh/framework/core/api/router" "infini.sh/framework/core/elastic" "infini.sh/framework/core/util" @@ -20,20 +21,22 @@ func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P h.ErrorInternalServer(w, err.Error()) return } - irole, err := biz.NewRole(roleType) + err = biz.IsAllowRoleType(roleType) if err != nil { h.ErrorInternalServer(w, err.Error()) return } - - err = h.DecodeJSON(r, &irole) + role := &rbac.Role{ + Type: roleType, + } + err = h.DecodeJSON(r, role) if err != nil { h.Error400(w, err.Error()) return } var id string - id, err = irole.Create(localUser) + id, err = biz.CreateRole(localUser, role) if err != nil { _ = log.Error(err.Error()) @@ -128,24 +131,14 @@ func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.P h.ErrorInternalServer(w, err.Error()) return } - model, err := biz.GetRole(id) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - irole, err := biz.NewRole(model.RoleType) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - - err = h.DecodeJSON(r, &irole) + role := &rbac.Role{} + err = h.DecodeJSON(r, role) if err != nil { h.Error400(w, err.Error()) return } - - err = irole.Update(localUser, model) + role.ID = id + err = biz.UpdateRole(localUser, role) if err != nil { _ = log.Error(err.Error()) diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go index 9423b729..b940db12 100644 --- a/plugin/api/rbac/user.go +++ b/plugin/api/rbac/user.go @@ -29,7 +29,7 @@ func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.P h.Error400(w, err.Error()) return } - if req.Username == "" || req.Phone == "" || req.Email == "" { + if req.Name == "" { h.Error400(w, "username and phone and email is require") return From abe934cef3d65e686b26f3998b46b30187f2944c Mon Sep 17 00:00:00 2001 From: liugq Date: Fri, 6 May 2022 18:04:01 +0800 Subject: [PATCH 69/75] update platform permission enum --- internal/biz/enum/const.go | 109 ++++++++++++++++--------- internal/biz/permission.go | 1 - internal/biz/validate.go | 21 ++--- internal/biz/validate_test.go | 149 ---------------------------------- 4 files changed, 75 insertions(+), 205 deletions(-) diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go index 3992f463..5a313392 100644 --- a/internal/biz/enum/const.go +++ b/internal/biz/enum/const.go @@ -41,59 +41,90 @@ const ( ClusterOverviewRead = "cluster.overview:read" ClusterOverviewAll = "cluster.overview:all" - ElasticsearchRead = "cluster.elasticsearch:read" - ElasticsearchAll = "cluster.elasticsearch:all" + MonitoringRead = "cluster.monitoring:read" + MonitoringAll = "cluster.monitoring:all" ActivitiesRead = "cluster.activities:read" ActivitiesAll = "cluster.activities:all" ) +const ( + PermissionUserRead string = "user:read" + PermissionUserWrite = "user:write" + PermissionRoleRead = "role:read" + PermissionRoleWrite = "role:write" + PermissionCommandRead = "command:read" + PermissionCommandWrite = "command:write" + PermissionElasticsearchClusterRead = "es.cluster:read" + PermissionElasticsearchClusterWrite = "es.cluster:write" // es cluster + PermissionElasticsearchIndexRead = "es.index:read" + PermissionElasticsearchIndexWrite = "es.index:write" // es index metadata + PermissionElasticsearchNodeRead = "es.node:read" //es node metadata + PermissionActivityRead = "activity:read" + PermissionActivityWrite = "activity:write" + PermissionAlertRuleRead = "alert.rule:read" + PermissionAlertRuleWrite = "alert.rule:write" + PermissionAlertHistoryRead = "alert.history:read" + PermissionAlertHistoryWrite = "alert.history:write" + PermissionAlertChannelRead = "alert.channel:read" + PermissionAlertChannelWrite = "alert.channel:write" + PermissionViewRead = "view:read" + PermissionViewWrite = "view:write" + PermissionGatewayInstanceRead = "gateway.instance:read" + PermissionGatewayInstanceWrite = "gateway.instance:write" + PermissionGatewayEntryRead = "gateway.entry:read" + PermissionGatewayEntryWrite = "gateway.entry:write" + PermissionGatewayRouterRead = "gateway.router:read" + PermissionGatewayRouterWrite = "gateway.router:write" + PermissionGatewayFlowRead = "gateway.flow:read" + PermissionGatewayFlowWrite = "gateway.flow:write" + PermissionElasticsearchMetricRead = "es.metric:read" +) + var ( - UserReadPermission = []string{"user:read"} - UserAllPermission = []string{"user:read", "user:write"} + UserReadPermission = []string{PermissionUserRead} + UserAllPermission = []string{PermissionUserRead, PermissionUserWrite,PermissionRoleRead} - RoleReadPermission = []string{"role:read"} - RoleAllPermission = []string{"role:read", "role:write"} + RoleReadPermission = []string{PermissionRoleRead} + RoleAllPermission = []string{PermissionRoleRead, PermissionRoleWrite} - ClusterReadPermission = []string{"cluster:read"} - ClusterAllPermission = []string{"cluster:read", "cluster:write"} + ClusterReadPermission = []string{PermissionElasticsearchClusterRead} + ClusterAllPermission = []string{PermissionElasticsearchClusterRead, PermissionElasticsearchClusterWrite} - CommandReadPermission = []string{"command:read"} - CommandAllPermission = []string{"command:read", "command:write"} + CommandReadPermission = []string{PermissionCommandRead} + CommandAllPermission = []string{PermissionCommandRead, PermissionCommandWrite} - InstanceReadPermission = []string{"instance:read"} - InstanceAllPermission = []string{"instance:read", "instance:write"} + InstanceReadPermission = []string{PermissionGatewayInstanceRead} + InstanceAllPermission = []string{PermissionGatewayInstanceRead,PermissionGatewayInstanceWrite} - EntryReadPermission = []string{"entry:read"} - EntryAllPermission = []string{"entry:read", "entry:write"} + EntryReadPermission = []string{PermissionGatewayEntryRead} + EntryAllPermission = []string{PermissionGatewayEntryRead, PermissionGatewayEntryWrite} - RouterReadPermission = []string{"router:read"} - RouterAllPermission = []string{"router:read", "entry:write"} + RouterReadPermission = []string{PermissionGatewayRouterRead} + RouterAllPermission = []string{PermissionGatewayRouterRead, PermissionGatewayRouterWrite} - FlowReadPermission = []string{"flow:read"} - FlowAllPermission = []string{"flow:read", "flow:write"} + FlowReadPermission = []string{PermissionGatewayFlowRead} + FlowAllPermission = []string{PermissionGatewayFlowRead, PermissionGatewayFlowWrite} IndexAllPermission = []string{"index:read"} IndexReadPermission = []string{"index:read", "index:write"} - ViewsAllPermission = []string{"views:read"} - ViewsReadPermission = []string{"views:read", "views:write"} - DiscoverReadPermission = []string{"discover:read"} - DiscoverAllPermission = []string{"discover:read", "discover:write"} + ViewsAllPermission = []string{PermissionViewRead} + ViewsReadPermission = []string{PermissionViewRead, PermissionViewWrite} + DiscoverReadPermission = []string{PermissionViewRead} + DiscoverAllPermission = []string{PermissionViewRead} - RuleReadPermission = []string{"rule:read"} - RuleAllPermission = []string{"rule:read", "rule:write"} - AlertReadPermission = []string{"alert:read"} - AlertAllPermission = []string{"alert:read", "alert:write"} - ChannelReadPermission = []string{"channel:read"} - ChannelAllPermission = []string{"channel:read", "channel:write"} + RuleReadPermission = []string{PermissionAlertRuleRead} + RuleAllPermission = []string{PermissionAlertRuleRead, PermissionAlertRuleWrite} + AlertReadPermission = []string{PermissionAlertHistoryRead} + AlertAllPermission = []string{PermissionAlertHistoryRead, PermissionAlertHistoryWrite} + ChannelReadPermission = []string{PermissionAlertChannelRead} + ChannelAllPermission = []string{PermissionAlertChannelRead, PermissionAlertChannelWrite} - ClusterOverviewReadPermission = []string{"clusterOverview:read"} - ClusterOverviewAllPermission = []string{"clusterOverview:read", "clusterOverview:write"} + ClusterOverviewReadPermission = []string{PermissionElasticsearchClusterRead, PermissionElasticsearchIndexRead, PermissionElasticsearchNodeRead, PermissionElasticsearchMetricRead} + ClusterOverviewAllPermission = ClusterOverviewReadPermission + MonitoringReadPermission = ClusterOverviewAllPermission - ElasticsearchReadPermission = []string{"elasticsearch:read"} - ElasticsearchAllPermission = []string{"elasticsearch:read", "elasticsearch:write"} - - ActivitiesReadPermission = []string{"activities:read"} - ActivitiesAllPermission = []string{"activities:read", "activities:write"} + ActivitiesReadPermission = []string{PermissionActivityRead} + ActivitiesAllPermission = []string{PermissionActivityRead, PermissionActivityWrite} ) var AdminPrivilege = []string{ @@ -101,7 +132,7 @@ var AdminPrivilege = []string{ InstanceAll, EntryAll, RouterAll, FlowAll, IndexAll, ViewsAll, DiscoverAll, RuleAll, AlertAll, ChannelAll, - ClusterOverviewAll, ElasticsearchAll, ActivitiesAll, + ClusterOverviewAll, MonitoringAll, ActivitiesAll, } var BuildRoles = make(map[string]map[string]interface{}, 0) @@ -111,7 +142,7 @@ func init() { BuildRoles["admin"] = map[string]interface{}{ "id": "admin", "name": "管理员", - "type": "console", + "type": "platform", "platform": AdminPrivilege, "builtin": true, "description": "is admin", @@ -152,8 +183,8 @@ func init() { ClusterOverviewRead: ClusterOverviewReadPermission, ClusterOverviewAll: ClusterOverviewAllPermission, - ElasticsearchAll: ElasticsearchAllPermission, - ElasticsearchRead: ElasticsearchReadPermission, + MonitoringAll: MonitoringReadPermission, + MonitoringRead: MonitoringReadPermission, ActivitiesAll: ActivitiesAllPermission, ActivitiesRead: ActivitiesReadPermission, } diff --git a/internal/biz/permission.go b/internal/biz/permission.go index 5a5234a0..f9ba38a5 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -29,7 +29,6 @@ type RolePermission struct { IndexPrivilege map[string][]string `json:"index_privilege"` } - func ListElasticsearchPermission() interface{} { list := ElasticsearchPermission{ ClusterPrivileges: ClusterApis, diff --git a/internal/biz/validate.go b/internal/biz/validate.go index 923738b7..7ecf1509 100644 --- a/internal/biz/validate.go +++ b/internal/biz/validate.go @@ -191,7 +191,7 @@ func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { err = errors.New("user id is empty") return } - fmt.Println("user token", clams.UserId, TokenMap[clams.UserId]) + //fmt.Println("user token", clams.UserId, TokenMap[clams.UserId]) tokenVal, ok := TokenMap[clams.UserId] if !ok { err = errors.New("token is invalid") @@ -227,12 +227,6 @@ func ValidatePermission(claims *UserClaims, permissions []string) (err error) { if _, ok := RoleMap[role]; ok { for _, v := range RoleMap[role].Privilege.Platform { userPermissions = append(userPermissions, v) - - //all include read - if strings.Contains(v, "all") { - key := v[:len(v)-3] + "read" - userPermissions = append(userPermissions, key) - } } } } @@ -244,17 +238,12 @@ func ValidatePermission(claims *UserClaims, permissions []string) (err error) { } - var count int for _, v := range permissions { - if _, ok := userPermissionMap[v]; ok { - count++ - continue + if _, ok := userPermissionMap[v]; !ok { + err = errors.New("permission denied") + return } } - if count == len(permissions) { - return nil - } - err = errors.New("permission denied") - return + return nil } diff --git a/internal/biz/validate_test.go b/internal/biz/validate_test.go index a1b82c1c..345e12f4 100644 --- a/internal/biz/validate_test.go +++ b/internal/biz/validate_test.go @@ -145,152 +145,3 @@ func TestStringInArray(t *testing.T) { assert.Equal(t, true, util.StringInArray(array, "c")) assert.Equal(t, false, util.StringInArray(array, "h")) } -func TestFilterCluster(t *testing.T) { - RoleMap["test"] = Role{ - Cluster: []struct { - Id string `json:"id"` - Name string `json:"name"` - }{ - { - Id: "c97rd2les10hml00pgh0", - Name: "docker-cluster", - }, - }, - ClusterPrivilege: []string{"cat.*"}, - Index: []struct { - Name []string `json:"name"` - Privilege []string `json:"privilege"` - }{ - { - Name: []string{".infini_rbac-role"}, - Privilege: []string{"indices.get_mapping"}, - }, - { - Name: []string{".infini_rbac-user", ".infini_rbac-role"}, - Privilege: []string{"cat.*"}, - }, - }, - } - type args struct { - roles []string - cluster []string - } - tests := []struct { - name string - args args - want []string - }{ - { - name: "empty", - args: args{ - roles: []string{"test"}, - cluster: []string{ - "cluser1", "cluster2", - }, - }, - want: []string{}, - }, - { - name: "one", - args: args{ - roles: []string{"test"}, - cluster: []string{ - "cluser1", "cluster2", "c97rd2les10hml00pgh0", - }, - }, - want: []string{"c97rd2les10hml00pgh0"}, - }, - { - name: "only", - args: args{ - roles: []string{"test"}, - cluster: []string{ - "c97rd2les10hml00pgh0", - }, - }, - want: []string{"c97rd2les10hml00pgh0"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := FilterCluster(tt.args.roles, tt.args.cluster) - assert.Equal(t, got, tt.want) - }) - } - -} -func TestFilterIndex(t *testing.T) { - RoleMap["test"] = Role{ - Cluster: []struct { - Id string `json:"id"` - Name string `json:"name"` - }{ - { - Id: "c97rd2les10hml00pgh0", - Name: "docker-cluster", - }, - }, - ClusterPrivilege: []string{"cat.*"}, - Index: []struct { - Name []string `json:"name"` - Privilege []string `json:"privilege"` - }{ - { - Name: []string{".infini_rbac-role"}, - Privilege: []string{"indices.get_mapping"}, - }, - { - Name: []string{".infini_rbac-user", ".infini_rbac-role"}, - Privilege: []string{"cat.*"}, - }, - }, - } - - type args struct { - roles []string - index []string - } - tests := []struct { - name string - args args - want []string - }{ - { - name: "empty", - args: args{ - roles: []string{"test"}, - index: []string{ - "index1", "index2", - }, - }, - want: []string{}, - }, - { - name: "one", - args: args{ - roles: []string{"test"}, - index: []string{ - "index1", "index2", ".infini_rbac-user", - }, - }, - want: []string{".infini_rbac-user"}, - }, - { - name: "only", - args: args{ - roles: []string{"test"}, - index: []string{ - ".infini_rbac-user", - }, - }, - want: []string{".infini_rbac-user"}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := FilterIndex(tt.args.roles, tt.args.index) - assert.Equal(t, got, tt.want) - }) - } - -} From e5d119885edd72a9a8ebab6449540970a428aa23 Mon Sep 17 00:00:00 2001 From: liugq Date: Sat, 7 May 2022 14:46:08 +0800 Subject: [PATCH 70/75] update validate --- internal/biz/permission.go | 3 -- internal/biz/validate.go | 102 +++++++++++++++++++++-------------- internal/core/router.go | 94 -------------------------------- internal/core/router_test.go | 79 --------------------------- internal/core/trie.go | 83 ---------------------------- internal/dto/role.go | 15 ------ internal/middleware/es.go | 4 +- 7 files changed, 65 insertions(+), 315 deletions(-) delete mode 100644 internal/core/router.go delete mode 100644 internal/core/router_test.go delete mode 100644 internal/core/trie.go diff --git a/internal/biz/permission.go b/internal/biz/permission.go index f9ba38a5..cfd64286 100644 --- a/internal/biz/permission.go +++ b/internal/biz/permission.go @@ -1,7 +1,6 @@ package biz import ( - "infini.sh/console/internal/core" "infini.sh/console/model/rbac" ) @@ -18,8 +17,6 @@ type Token struct { var TokenMap = make(map[string]Token) -var EsApiRoutes = core.NewRouter() - type RolePermission struct { Platform []string `json:"platform,omitempty"` diff --git a/internal/biz/validate.go b/internal/biz/validate.go index 7ecf1509..d67943f1 100644 --- a/internal/biz/validate.go +++ b/internal/biz/validate.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "infini.sh/console/internal/biz/enum" + "infini.sh/console/model/rbac" httprouter "infini.sh/framework/core/api/router" "infini.sh/framework/core/util" "src/github.com/golang-jwt/jwt" @@ -44,6 +45,11 @@ func NewClusterRequest(ps httprouter.Params, privilege []string) ClusterRequest } } +func ValidateElasticsearch(req rbac.ElasticsearchPrivilege, roleNames []string) (err error) { + + return nil +} + func ValidateIndex(req IndexRequest, userRole RolePermission) (err error) { userClusterMap := make(map[string]struct{}) @@ -60,7 +66,7 @@ func ValidateIndex(req IndexRequest, userRole RolePermission) (err error) { for _, val := range req.Privilege { position := strings.Index(val, ".") if position == -1 { - err = errors.New("invalid privilege parmeter") + err = errors.New("invalid privilege parameter") return err } prefix := val[:position] @@ -71,42 +77,43 @@ func ValidateIndex(req IndexRequest, userRole RolePermission) (err error) { return err } if util.StringInArray(privilege, prefix+".*") { - return nil + continue } if util.StringInArray(privilege, val) { - return nil + continue } - + return fmt.Errorf("no index api permission: %s", val) } } - return errors.New("no index api permission") + return nil } -func ValidateCluster(req ClusterRequest, userRole RolePermission) (err error) { - userClusterMap := make(map[string]struct{}) - for _, v := range userRole.Cluster { - userClusterMap[v] = struct{}{} - } +func ValidateCluster(req ClusterRequest, roleNames []string) (err error) { + userClusterMap := GetRoleClusterMap(roleNames) for _, v := range req.Cluster { - if _, ok := userClusterMap[v]; !ok { - err = errors.New("no cluster permission") + userClusterPermissions, ok := userClusterMap[v] + if !ok && userClusterMap["*"] == nil{ + err = fmt.Errorf("no cluster[%s] permission", v) return } - } - - // if include api.* for example: cat.* , return nil - for _, privilege := range req.Privilege { - prefix := privilege[:strings.Index(privilege, ".")] - - if util.StringInArray(userRole.ClusterPrivilege, prefix+".*") { - return nil + if util.StringInArray(userClusterPermissions, "*") { + continue } - if util.StringInArray(userRole.ClusterPrivilege, privilege) { - return nil + // if include api.* for example: cat.* , return nil + for _, privilege := range req.Privilege { + prefix := privilege[:strings.Index(privilege, ".")] + + if util.StringInArray(userClusterPermissions, prefix+".*") { + continue + } + if util.StringInArray(userClusterPermissions, privilege) { + continue + } + return fmt.Errorf("no cluster api permission: %s", privilege) } } + return nil - return errors.New("no cluster api permission") } func CombineUserRoles(roleNames []string) RolePermission { @@ -139,26 +146,43 @@ func CombineUserRoles(roleNames []string) RolePermission { newRole.IndexPrivilege = m return newRole } -func FilterCluster(roles []string, cluster []string) []string { - newRole := CombineUserRoles(roles) - userClusterMap := make(map[string]struct{}, 0) - for _, v := range newRole.Cluster { - userClusterMap[v] = struct{}{} - } - realCluster := make([]string, 0) - for _, v := range cluster { - if _, ok := userClusterMap[v]; ok { - realCluster = append(realCluster, v) +func GetRoleClusterMap(roles []string) map[string][]string { + userClusterMap := make(map[string][]string, 0) + for _, roleName := range roles { + role, ok := RoleMap[roleName] + if ok { + for _, ic := range role.Privilege.Elasticsearch.Cluster.Resources { + userClusterMap[ic.ID] = append(userClusterMap[ic.ID], role.Privilege.Elasticsearch.Cluster.Permissions...) + } } } + return userClusterMap +} +func GetRoleCluster(roles []string) []string { + userClusterMap := GetRoleClusterMap(roles) + realCluster := make([]string, 0, len(userClusterMap)) + for k, _ := range userClusterMap { + realCluster = append(realCluster, k) + } return realCluster } -func FilterIndex(roles []string, index []string) []string { - realIndex := make([]string, 0) - newRole := CombineUserRoles(roles) - for _, v := range index { - if _, ok := newRole.IndexPrivilege[v]; ok { - realIndex = append(realIndex, v) +func GetRoleIndex(roles, clusterIDs []string) map[string][]string { + userClusterMap := make(map[string]struct{}, len(clusterIDs)) + for _, clusterID := range clusterIDs { + userClusterMap[clusterID] = struct{}{} + } + realIndex := map[string][]string{} + for _, roleName := range roles { + role, ok := RoleMap[roleName] + if ok { + for _, ic := range role.Privilege.Elasticsearch.Cluster.Resources { + if _, ok = userClusterMap[ic.ID]; !ok { + continue + } + for _, ip := range role.Privilege.Elasticsearch.Index { + realIndex[ic.ID] = append(realIndex[ic.ID], ip.Name...) + } + } } } return realIndex diff --git a/internal/core/router.go b/internal/core/router.go deleted file mode 100644 index faeced25..00000000 --- a/internal/core/router.go +++ /dev/null @@ -1,94 +0,0 @@ -package core - -import ( - "errors" - "strings" -) - -type Router struct { - roots map[string]*node - handlers map[string]string -} - -func NewRouter() *Router { - return &Router{ - roots: make(map[string]*node), - handlers: make(map[string]string), - } -} - -// Only one * is allowed -func parsePattern(pattern string) []string { - vs := strings.Split(pattern, "/") - - parts := make([]string, 0) - for _, item := range vs { - if item != "" { - parts = append(parts, item) - if item[0] == '*' { - break - } - } - } - return parts -} - -func (r *Router) AddRoute(method string, pattern string, handler string) { - parts := parsePattern(pattern) - - key := method + "-" + pattern - _, ok := r.roots[method] - if !ok { - r.roots[method] = &node{} - } - r.roots[method].insert(pattern, parts, 0) - r.handlers[key] = handler -} - -func (r *Router) GetRoute(method string, path string) (*node, map[string]string) { - searchParts := parsePattern(path) - params := make(map[string]string) - root, ok := r.roots[method] - - if !ok { - return nil, nil - } - - n := root.search(searchParts, 0) - - if n != nil { - parts := parsePattern(n.pattern) - for index, part := range parts { - if part[0] == ':' { - params[part[1:]] = searchParts[index] - } - //if part[0] == '*' && len(part) > 1 { - // params[part[1:]] = strings.Join(searchParts[index:], "/") - // break - //} - } - return n, params - } - - return nil, nil -} - -func (r *Router) getRoutes(method string) []*node { - root, ok := r.roots[method] - if !ok { - return nil - } - nodes := make([]*node, 0) - root.travel(&nodes) - return nodes -} - -func (r *Router) Handle(method string, path string) (handle string, err error) { - n, _ := r.GetRoute(method, path) - if n == nil { - err = errors.New("router not match") - return - - } - return r.handlers[method+"-"+n.pattern], nil -} diff --git a/internal/core/router_test.go b/internal/core/router_test.go deleted file mode 100644 index ea49bbf2..00000000 --- a/internal/core/router_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package core - -import ( - "fmt" - "reflect" - "testing" -) - -func newTestRouter() *Router { - r := NewRouter() - //GET "GET/_mapping/:index": "indices.get_mapping", - r.AddRoute("GET", "/:index/_mappings", "indices.get_mapping") - r.AddRoute("GET", "/hello/:name", "gethello") - r.AddRoute("GET", "/hello/b/c", "hellobc") - r.AddRoute("GET", "/hi/:name", "getHi") - r.AddRoute("GET", "/role/xushuhui", "getRole") - - return r -} - -func TestParsePattern(t *testing.T) { - ok := reflect.DeepEqual(parsePattern("/p/:name"), []string{"p", ":name"}) - ok = ok && reflect.DeepEqual(parsePattern("/p/*"), []string{"p", "*"}) - ok = ok && reflect.DeepEqual(parsePattern("/p/*name/*"), []string{"p", "*name"}) - if !ok { - t.Fatal("test parsePattern failed") - } -} - -func TestGetRoute(t *testing.T) { - //r := newTestRouter() - //path := "/elasticsearch/c6dgjtgvi076f32oibj0/index/test/_mappings" - //paths := strings.Split(path, "/") - //newPath := "/" + strings.Join(paths[4:], "/") - //t.Log(newPath) - - //if n == nil { - // t.Fatal("nil shouldn't be returned") - //} - - //if n.pattern != "/hello/:name" { - // t.Fatal("should match /hello/:name") - //} - // - //if ps["name"] != "geektutu" { - // t.Fatal("name should be equal to 'geektutu'") - //} - - //fmt.Printf("matched path: %s, params['name']: %s\n", n.pattern, ps["name"]) - -} - -func TestGetRoute2(t *testing.T) { - r := newTestRouter() - n1, ps1 := r.GetRoute("GET", "/assets/file1.txt") - ok1 := n1.pattern == "/assets/*filepath" && ps1["filepath"] == "file1.txt" - if !ok1 { - t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be file1.txt") - } - - n2, ps2 := r.GetRoute("GET", "/assets/css/test.css") - ok2 := n2.pattern == "/assets/*filepath" && ps2["filepath"] == "css/test.css" - if !ok2 { - t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be css/test.css") - } - -} - -func TestGetRoutes(t *testing.T) { - r := newTestRouter() - nodes := r.getRoutes("GET") - for i, n := range nodes { - fmt.Println(i+1, n) - } - - if len(nodes) != 5 { - t.Fatal("the number of routes shoule be 4") - } -} diff --git a/internal/core/trie.go b/internal/core/trie.go deleted file mode 100644 index 2fcb5b5e..00000000 --- a/internal/core/trie.go +++ /dev/null @@ -1,83 +0,0 @@ -package core - -import ( - "fmt" - "strings" -) - -type node struct { - pattern string // 待匹配路由,例如 /p/:lang - part string // 路由中的一部分,例如 :lang - children []*node // 子节点,例如 [doc, tutorial, intro] - isWild bool // 是否精确匹配,part 含有 : 或 * 时为true -} - -func (n *node) String() string { - return fmt.Sprintf("node{pattern=%s, part=%s, isWild=%t}", n.pattern, n.part, n.isWild) -} - -func (n *node) insert(pattern string, parts []string, height int) { - if len(parts) == height { - n.pattern = pattern - return - } - - part := parts[height] - child := n.matchChild(part) - if child == nil { - child = &node{part: part, isWild: part[0] == ':' || part[0] == '*'} - n.children = append(n.children, child) - } - child.insert(pattern, parts, height+1) -} - -func (n *node) search(parts []string, height int) *node { - if len(parts) == height || strings.HasPrefix(n.part, "*") { - if n.pattern == "" { - return nil - } - return n - } - - part := parts[height] - children := n.matchChildren(part) - - for _, child := range children { - result := child.search(parts, height+1) - if result != nil { - return result - } - } - - return nil -} - -func (n *node) travel(list *[]*node) { - if n.pattern != "" { - *list = append(*list, n) - } - for _, child := range n.children { - child.travel(list) - } -} - -// 第一个匹配成功的节点,用于插入 -func (n *node) matchChild(part string) *node { - for _, child := range n.children { - if child.part == part || child.isWild { - return child - } - } - return nil -} - -// 所有匹配成功的节点,用于查找 -func (n *node) matchChildren(part string) []*node { - nodes := make([]*node, 0) - for _, child := range n.children { - if child.part == part || child.isWild { - nodes = append(nodes, child) - } - } - return nodes -} diff --git a/internal/dto/role.go b/internal/dto/role.go index f56a7c48..806dba23 100644 --- a/internal/dto/role.go +++ b/internal/dto/role.go @@ -1,20 +1,5 @@ package dto -type UpdateRole struct { - Description string `json:"description" ` - Platform []string `json:"platform"` - Cluster []string `json:"cluster" ` - Index []string `json:"index" ` - ClusterPrivilege []string `json:"cluster_privilege" ` - IndexPrivilege []string `json:"index_privilege" ` -} - -type ElasticsearchPermission struct { - Cluster []string `json:"cluster" ` - Index []string `json:"index" ` - ClusterPrivilege []string `json:"cluster_privilege" ` - IndexPrivilege []string `json:"index_privilege" ` -} type CreateUser struct { NickName string `json:"nick_name"` diff --git a/internal/middleware/es.go b/internal/middleware/es.go index 32e4ca94..c8aa78db 100644 --- a/internal/middleware/es.go +++ b/internal/middleware/es.go @@ -34,10 +34,10 @@ func ClusterRequired(h httprouter.Handle, route ...string) httprouter.Handle { w = handleError(w, http.StatusUnauthorized, err) return } - newRole := biz.CombineUserRoles(claims.Roles) + //newRole := biz.CombineUserRoles(claims.Roles) clusterReq := biz.NewClusterRequest(ps, route) - err = biz.ValidateCluster(clusterReq, newRole) + err = biz.ValidateCluster(clusterReq, claims.Roles) if err != nil { w = handleError(w, http.StatusForbidden, err) return From 412b5ae9a8804bff07e591e24a2358c5bb2f20b3 Mon Sep 17 00:00:00 2001 From: liugq Date: Mon, 9 May 2022 15:26:16 +0800 Subject: [PATCH 71/75] move rbac to framework --- internal/biz/account.go | 42 +++++++--------- internal/biz/context.go | 4 +- internal/biz/role.go | 36 +++----------- internal/biz/user.go | 10 ++-- internal/biz/validate.go | 2 +- main.go | 8 ++- plugin/api/account/account.go | 17 +++---- plugin/api/index_management/index.go | 74 +--------------------------- plugin/api/init.go | 1 - plugin/api/rbac/api.go | 31 ++++++------ plugin/api/rbac/permission.go | 2 +- plugin/api/rbac/role.go | 17 ++++--- 12 files changed, 68 insertions(+), 176 deletions(-) diff --git a/internal/biz/account.go b/internal/biz/account.go index 6513179f..23d9b4b4 100644 --- a/internal/biz/account.go +++ b/internal/biz/account.go @@ -16,29 +16,17 @@ import ( type UserClaims struct { *jwt.RegisteredClaims - *User + *ShortUser } -type User struct { +type ShortUser struct { Username string `json:"username"` UserId string `json:"user_id"` Roles []string `json:"roles"` } -type Account struct { - ID string `json:"id,omitempty" ` - Created string `json:"created,omitempty" ` - Updated string `json:"updated,omitempty" ` - Username string `json:"username" elastic_mapping:"username:{type:keyword}"` - Password string `json:"password" elastic_mapping:"password:{type:text}"` - Name string `json:"name" elastic_mapping:"name:{type:keyword}"` - Phone string `json:"phone" elastic_mapping:"phone:{type:keyword}"` - Email string `json:"email" elastic_mapping:"email:{type:keyword}"` - Tags []string `json:"tags" elastic_mapping:"tags:{type:text}"` - Roles []rbac.UserRole `json:"roles"` -} const Secret = "console" -func authenticateUser(username string, password string) (user Account, err error) { +func authenticateUser(username string, password string) (user rbac.User, err error) { err, result := orm.GetBy("name", username, rbac.User{}) if err != nil { @@ -49,6 +37,10 @@ func authenticateUser(username string, password string) (user Account, err error err = errors.New("user not found") return } + if row, ok := result.Result[0].(map[string]interface{}); ok { + delete(row, "created") + delete(row, "updated") + } err = mapstructure.Decode(result.Result[0], &user) if err != nil { @@ -62,7 +54,7 @@ func authenticateUser(username string, password string) (user Account, err error return } -func authenticateAdmin(username string, password string) (user Account, err error) { +func authenticateAdmin(username string, password string) (user rbac.User, err error) { u, _ := global.Env().GetConfig("bootstrap.username", "admin") p, _ := global.Env().GetConfig("bootstrap.password", "admin") @@ -72,13 +64,13 @@ func authenticateAdmin(username string, password string) (user Account, err erro return } user.ID = username - user.Username = username + user.Name = username user.Roles = []rbac.UserRole{{ ID: "admin", Name: "admin", }} return user, nil } -func authorize(user Account) (m map[string]interface{}, err error) { +func authorize(user rbac.User) (m map[string]interface{}, err error) { var roles, privilege []string for _, v := range user.Roles { @@ -87,8 +79,8 @@ func authorize(user Account) (m map[string]interface{}, err error) { privilege = append(privilege, role.Privilege.Platform...) } token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims{ - User: &User{ - Username: user.Username, + ShortUser: &ShortUser{ + Username: user.Name, UserId: user.ID, Roles: roles, }, @@ -104,7 +96,7 @@ func authorize(user Account) (m map[string]interface{}, err error) { m = util.MapStr{ "access_token": tokenString, - "username": user.Username, + "username": user.Name, "id": user.ID, "expire_in": 86400, "roles": roles, @@ -113,7 +105,7 @@ func authorize(user Account) (m map[string]interface{}, err error) { return } func Login(username string, password string) (m map[string]interface{}, err error) { - var user Account + var user rbac.User if username == "admin" { user, err = authenticateAdmin(username, password) if err != nil { @@ -143,12 +135,12 @@ func Login(username string, password string) (m map[string]interface{}, err erro }, User: util.MapStr{ "id": user.ID, - "name": user.Username, + "name": user.Name, }, }, nil, nil)) return } -func UpdatePassword(localUser *User, req dto.UpdatePassword) (err error) { +func UpdatePassword(localUser *ShortUser, req dto.UpdatePassword) (err error) { user := rbac.User{} user.ID = localUser.UserId _, err = orm.Get(&user) @@ -186,7 +178,7 @@ func UpdatePassword(localUser *User, req dto.UpdatePassword) (err error) { }, nil, nil)) return } -func UpdateProfile(localUser *User, req dto.UpdateProfile) (err error) { +func UpdateProfile(localUser *ShortUser, req dto.UpdateProfile) (err error) { user := rbac.User{} user.ID = localUser.UserId _, err = orm.Get(&user) diff --git a/internal/biz/context.go b/internal/biz/context.go index 2d4a8e49..cc152225 100644 --- a/internal/biz/context.go +++ b/internal/biz/context.go @@ -10,7 +10,7 @@ const ctxUserKey = "user" func NewUserContext(ctx context.Context, clam *UserClaims) context.Context { return context.WithValue(ctx, ctxUserKey, clam) } -func FromUserContext(ctx context.Context) (*User, error) { +func FromUserContext(ctx context.Context) (*ShortUser, error) { ctxUser := ctx.Value(ctxUserKey) if ctxUser == nil { return nil, errors.New("user not found") @@ -19,5 +19,5 @@ func FromUserContext(ctx context.Context) (*User, error) { if !ok { return nil, errors.New("invalid context user") } - return reqUser.User, nil + return reqUser.ShortUser, nil } diff --git a/internal/biz/role.go b/internal/biz/role.go index b5d0de28..ec9807df 100644 --- a/internal/biz/role.go +++ b/internal/biz/role.go @@ -16,47 +16,23 @@ import ( type RoleType = string const ( - Platform RoleType = "platform" - Elastisearch RoleType = "elasticsearch" + Platform RoleType = "platform" + Elasticsearch RoleType = "elasticsearch" ) -func UpdateRole(localUser *User, role *rbac.Role) (err error) { +func UpdateRole(role *rbac.Role) (err error) { model, err := GetRole(role.ID) if err != nil { return err } role.Type = model.Type role.Created = model.Created - changeLog, _ := util.DiffTwoObject(model, role) role.Updated = time.Now() err = orm.Save(role) - if err != nil { - return - } - - RoleMap[model.Name] = model - - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "role", - Type: "update", - Labels: util.MapStr{ - "id": model.ID, - "description": model.Description, - "privilege": role.Privilege, - "updated": model.Updated, - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, nil, changeLog)) - return } -func CreateRole(localUser *User, role *rbac.Role) (id string, err error) { +func CreateRole(localUser *ShortUser, role *rbac.Role) (id string, err error) { if role.Name == "" { err = errors.New("role name is require") return @@ -110,7 +86,7 @@ func CreateRole(localUser *User, role *rbac.Role) (id string, err error) { return } -func DeleteRole(localUser *User, id string) (err error) { +func DeleteRole(localUser *ShortUser, id string) (err error) { role := rbac.Role{} role.ID = id roleName := role.Name @@ -178,7 +154,7 @@ func SearchRole(keyword string, from, size int) (roles orm.Result, err error) { return } func IsAllowRoleType(roleType string) (err error) { - if roleType != Platform && roleType != Elastisearch { + if roleType != Platform && roleType != Elasticsearch { err = fmt.Errorf("invalid role type %s ", roleType) return } diff --git a/internal/biz/user.go b/internal/biz/user.go index 34a0e20c..667da8ac 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -15,7 +15,7 @@ import ( var ErrNotFound = fmt.Errorf("not found") -func DeleteUser(localUser *User, id string) (err error) { +func DeleteUser(localUser *ShortUser, id string) (err error) { user := rbac.User{} user.ID = id @@ -55,7 +55,7 @@ func DeleteUser(localUser *User, id string) (err error) { }, nil)) return } -func CreateUser(localUser *User, req dto.CreateUser) (id string, password string, err error) { +func CreateUser(localUser *ShortUser, req dto.CreateUser) (id string, password string, err error) { q := orm.Query{Size: 1000} q.Conds = orm.And(orm.Eq("name", req.Name)) @@ -123,7 +123,7 @@ func CreateUser(localUser *User, req dto.CreateUser) (id string, password string }, nil, nil)) return } -func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { +func UpdateUser(localUser *ShortUser, id string, req dto.UpdateUser) (err error) { user := rbac.User{} user.ID = id _, err = orm.Get(&user) @@ -171,7 +171,7 @@ func UpdateUser(localUser *User, id string, req dto.UpdateUser) (err error) { }, nil, changeLog)) return } -func UpdateUserRole(localUser *User, id string, req dto.UpdateUserRole) (err error) { +func UpdateUserRole(localUser *ShortUser, id string, req dto.UpdateUserRole) (err error) { user := rbac.User{} user.ID = id _, err = orm.Get(&user) @@ -239,7 +239,7 @@ func SearchUser(keyword string, from, size int) (users orm.Result, err error) { return } -func UpdateUserPassword(localUser *User, id string, password string) (err error) { +func UpdateUserPassword(localUser *ShortUser, id string, password string) (err error) { user := rbac.User{} user.ID = id _, err = orm.Get(&user) diff --git a/internal/biz/validate.go b/internal/biz/validate.go index d67943f1..86e8f0ff 100644 --- a/internal/biz/validate.go +++ b/internal/biz/validate.go @@ -234,7 +234,7 @@ func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { } func ValidatePermission(claims *UserClaims, permissions []string) (err error) { - user := claims.User + user := claims.ShortUser if user.UserId == "" { err = errors.New("user id is empty") diff --git a/main.go b/main.go index ce11dd6f..7a773a18 100644 --- a/main.go +++ b/main.go @@ -7,9 +7,7 @@ import ( "infini.sh/console/model" "infini.sh/console/model/alerting" "infini.sh/console/model/gateway" - "infini.sh/console/model/rbac" _ "infini.sh/console/plugin" - rbacApi "infini.sh/console/plugin/api/rbac" alerting2 "infini.sh/console/service/alerting" "infini.sh/framework" "infini.sh/framework/core/elastic" @@ -24,6 +22,7 @@ import ( "infini.sh/framework/modules/pipeline" queue2 "infini.sh/framework/modules/queue/disk_queue" "infini.sh/framework/modules/redis" + "infini.sh/framework/modules/security" "infini.sh/framework/modules/stats" "infini.sh/framework/modules/task" "infini.sh/framework/modules/ui" @@ -77,6 +76,7 @@ func main() { module.RegisterSystemModule(&task.TaskModule{}) module.RegisterUserPlugin(&metrics.MetricsModule{}) + module.RegisterUserPlugin(&security.SecurityModule{}) api.RegisterAPI("") appConfig = &config.AppConfig{ @@ -129,8 +129,6 @@ func main() { orm.RegisterSchemaWithIndexName(gateway.Instance{}, "gateway-instance") orm.RegisterSchemaWithIndexName(alerting.Rule{}, "alert-rule") orm.RegisterSchemaWithIndexName(alerting.Alert{}, "alert-history") - orm.RegisterSchemaWithIndexName(rbac.Role{}, "rbac-role") - orm.RegisterSchemaWithIndexName(rbac.User{}, "rbac-user") api.RegisterSchema() go func() { @@ -139,7 +137,7 @@ func main() { log.Errorf("init alerting task error: %v", err) } }() - go rbacApi.Init() + //go rbacApi.Init() }, nil) { app.Run() diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go index e82c627d..35c258f7 100644 --- a/plugin/api/account/account.go +++ b/plugin/api/account/account.go @@ -4,7 +4,6 @@ import ( "infini.sh/console/internal/biz" "infini.sh/console/internal/core" "infini.sh/console/internal/dto" - m "infini.sh/console/internal/middleware" "infini.sh/framework/core/api" "infini.sh/framework/core/api/router" "infini.sh/framework/core/util" @@ -16,14 +15,14 @@ type Account struct { } func init() { - account := Account{} - api.HandleAPIMethod(api.POST, "/account/login", account.Login) - - api.HandleAPIMethod(api.GET, "/account/current_user", account.CurrentUser) - - api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout) - api.HandleAPIMethod(api.GET, "/account/profile", m.LoginRequired(account.Profile)) - api.HandleAPIMethod(api.PUT, "/account/password", m.LoginRequired(account.UpdatePassword)) + //account := Account{} + //api.HandleAPIMethod(api.POST, "/account/login", account.Login) + // + //api.HandleAPIMethod(api.GET, "/account/current_user", account.CurrentUser) + // + //api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout) + //api.HandleAPIMethod(api.GET, "/account/profile", m.LoginRequired(account.Profile)) + //api.HandleAPIMethod(api.PUT, "/account/password", m.LoginRequired(account.UpdatePassword)) } const userInSession = "user_session:" diff --git a/plugin/api/index_management/index.go b/plugin/api/index_management/index.go index 6c659afd..99ee9422 100644 --- a/plugin/api/index_management/index.go +++ b/plugin/api/index_management/index.go @@ -1,8 +1,6 @@ package index_management import ( - "fmt" - "infini.sh/framework/core/elastic" "net/http" "strconv" "strings" @@ -117,74 +115,4 @@ func (handler APIHandler) UpdateDictItemAction(w http.ResponseWriter, req *http. resp["payload"] = dict handler.WriteJSON(w, resp, http.StatusOK) -} -func (h APIHandler) ListIndex(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - clusterIds := h.GetParameterOrDefault(req, "ids", "") - keyword := h.GetParameterOrDefault(req, "keyword", "") - ids := strings.Split(clusterIds, ",") - for i := range ids { - if i < len(ids)-1 { - ids[i] = `"` + ids[i] + `",` - } else { - ids[i] = `"` + ids[i] + `"` - } - - } - if len(ids) == 0 { - h.Error400(w, "id is required") - return - } - var dsl = `{ - "_source": ["metadata.index_name"], - "collapse": { - "field": "metadata.index_name" - }, - "size": 100, - "query": { - "bool": { - "must": [ - { - "terms": { - "metadata.cluster_id": %s - } - }%s - ], - "must_not": [ - { - "term": { - "metadata.labels.state": { - "value": "delete" - } - } - } - ] - } - } - }` - - str := &strings.Builder{} - - if keyword != "" { - str.WriteString(fmt.Sprintf(`,{"wildcard":{"metadata.index_name":{"value":"*%s*"}}}`, keyword)) - } - dsl = fmt.Sprintf(dsl, ids, str) - - esClient := elastic.GetClient(h.Config.Elasticsearch) - resp, err := esClient.SearchWithRawQueryDSL(".infini_index", []byte(dsl)) - if err != nil { - - return - } - list := resp.Hits.Hits - var indexNames []string - for _, v := range list { - m := v.Source["metadata"].(map[string]interface{}) - indexNames = append(indexNames, m["index_name"].(string)) - - } - m := make(map[string]interface{}) - m["indexnames"] = indexNames - h.WriteOKJSON(w, m) - - return -} +} \ No newline at end of file diff --git a/plugin/api/init.go b/plugin/api/init.go index 0d66b36b..766b40e4 100644 --- a/plugin/api/init.go +++ b/plugin/api/init.go @@ -46,7 +46,6 @@ func Init(cfg *config.AppConfig) { api.HandleAPIMethod(api.PUT, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleSaveCommonCommandAction) api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleQueryCommonCommandAction) api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleDeleteCommonCommandAction) - api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "elasticsearch/indices"), handler.ListIndex) //task.RegisterScheduleTask(task.ScheduleTask{ // Description: "sync reindex task result", // Task: func() { diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go index dccd061b..4a2e19d6 100644 --- a/plugin/api/rbac/api.go +++ b/plugin/api/rbac/api.go @@ -5,7 +5,6 @@ import ( "github.com/mitchellh/mapstructure" "infini.sh/console/internal/biz" "infini.sh/console/internal/biz/enum" - m "infini.sh/console/internal/middleware" "infini.sh/console/model/rbac" "infini.sh/framework/core/api" "infini.sh/framework/core/elastic" @@ -21,21 +20,21 @@ type Rbac struct { func init() { - r := Rbac{} - api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) - api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAllPermission...)) - api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleReadPermission...)) - api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAllPermission...)) - api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.RoleAllPermission...)) - api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.RoleReadPermission...)) - - api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.UserAllPermission...)) - api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.UserReadPermission...)) - api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.UserAllPermission...)) - api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAllPermission...)) - api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAllPermission...)) - api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserReadPermission...)) - api.HandleAPIMethod(api.PUT, "/user/:id/password", m.PermissionRequired(r.UpdateUserPassword, enum.UserAllPermission...)) + //r := Rbac{} + //api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) + //api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAllPermission...)) + //api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleReadPermission...)) + //api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAllPermission...)) + //api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.RoleAllPermission...)) + //api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.RoleReadPermission...)) + // + //api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.UserAllPermission...)) + //api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.UserReadPermission...)) + //api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.UserAllPermission...)) + //api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAllPermission...)) + //api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAllPermission...)) + //api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserReadPermission...)) + //api.HandleAPIMethod(api.PUT, "/user/:id/password", m.PermissionRequired(r.UpdateUserPassword, enum.UserAllPermission...)) } func loadJsonConfig() { diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go index fc31eb02..69f2d00f 100644 --- a/plugin/api/rbac/permission.go +++ b/plugin/api/rbac/permission.go @@ -16,7 +16,7 @@ func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprout return } var permissions interface{} - if typ == biz.Elastisearch { + if typ == biz.Elasticsearch { permissions = biz.ListElasticsearchPermission() } h.WriteOKJSON(w, permissions) diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go index ffa6097b..eca29b20 100644 --- a/plugin/api/rbac/role.go +++ b/plugin/api/rbac/role.go @@ -125,20 +125,21 @@ func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.P func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { id := ps.MustGetParameter("id") - localUser, err := biz.FromUserContext(r.Context()) - if err != nil { - log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } + //localUser, err := biz.FromUserContext(r.Context()) + //if err != nil { + // log.Error(err.Error()) + // h.ErrorInternalServer(w, err.Error()) + // return + //} role := &rbac.Role{} - err = h.DecodeJSON(r, role) + err := h.DecodeJSON(r, role) if err != nil { h.Error400(w, err.Error()) return } role.ID = id - err = biz.UpdateRole(localUser, role) + err = biz.UpdateRole(role) + biz.RoleMap[role.Name] = *role if err != nil { _ = log.Error(err.Error()) From fcd52923c2d397d2939f8d8b0726e044afcaa63a Mon Sep 17 00:00:00 2001 From: liugq Date: Mon, 9 May 2022 20:45:39 +0800 Subject: [PATCH 72/75] remove rbac from console --- internal/biz/account.go | 211 ------------------------- internal/biz/context.go | 23 --- internal/biz/enum/const.go | 192 ----------------------- internal/biz/event.go | 18 --- internal/biz/permission.go | 40 ----- internal/biz/role.go | 162 -------------------- internal/biz/user.go | 279 ---------------------------------- internal/biz/validate.go | 273 --------------------------------- internal/biz/validate_test.go | 147 ------------------ internal/core/response.go | 45 ------ internal/dto/role.go | 28 ---- internal/dto/user.go | 15 -- internal/middleware/es.go | 47 ------ internal/middleware/user.go | 52 ------- model/rbac/role.go | 40 ----- model/rbac/user.go | 23 --- plugin/api/init.go | 2 +- plugin/api/rbac/api.go | 105 ------------- plugin/api/rbac/permission.go | 24 --- plugin/api/rbac/role.go | 151 ------------------ plugin/api/rbac/user.go | 192 ----------------------- 21 files changed, 1 insertion(+), 2068 deletions(-) delete mode 100644 internal/biz/account.go delete mode 100644 internal/biz/context.go delete mode 100644 internal/biz/enum/const.go delete mode 100644 internal/biz/event.go delete mode 100644 internal/biz/permission.go delete mode 100644 internal/biz/role.go delete mode 100644 internal/biz/user.go delete mode 100644 internal/biz/validate.go delete mode 100644 internal/biz/validate_test.go delete mode 100644 internal/core/response.go delete mode 100644 internal/dto/role.go delete mode 100644 internal/dto/user.go delete mode 100644 internal/middleware/es.go delete mode 100644 internal/middleware/user.go delete mode 100644 model/rbac/role.go delete mode 100644 model/rbac/user.go delete mode 100644 plugin/api/rbac/api.go delete mode 100644 plugin/api/rbac/permission.go delete mode 100644 plugin/api/rbac/role.go delete mode 100644 plugin/api/rbac/user.go diff --git a/internal/biz/account.go b/internal/biz/account.go deleted file mode 100644 index 23d9b4b4..00000000 --- a/internal/biz/account.go +++ /dev/null @@ -1,211 +0,0 @@ -package biz - -import ( - "errors" - "github.com/golang-jwt/jwt" - "github.com/mitchellh/mapstructure" - "golang.org/x/crypto/bcrypt" - "infini.sh/console/internal/dto" - "infini.sh/console/model/rbac" - "infini.sh/framework/core/event" - "infini.sh/framework/core/global" - "infini.sh/framework/core/orm" - "infini.sh/framework/core/util" - "time" -) - -type UserClaims struct { - *jwt.RegisteredClaims - *ShortUser -} -type ShortUser struct { - Username string `json:"username"` - UserId string `json:"user_id"` - Roles []string `json:"roles"` -} - -const Secret = "console" - -func authenticateUser(username string, password string) (user rbac.User, err error) { - - err, result := orm.GetBy("name", username, rbac.User{}) - if err != nil { - err = ErrNotFound - return - } - if result.Total == 0 { - err = errors.New("user not found") - return - } - if row, ok := result.Result[0].(map[string]interface{}); ok { - delete(row, "created") - delete(row, "updated") - } - - err = mapstructure.Decode(result.Result[0], &user) - if err != nil { - return - } - err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) - if err == bcrypt.ErrMismatchedHashAndPassword { - err = errors.New("password incorrect") - return - } - - return -} -func authenticateAdmin(username string, password string) (user rbac.User, err error) { - - u, _ := global.Env().GetConfig("bootstrap.username", "admin") - p, _ := global.Env().GetConfig("bootstrap.password", "admin") - - if u != username || p != password { - err = errors.New("invalid username or password") - return - } - user.ID = username - user.Name = username - user.Roles = []rbac.UserRole{{ - ID: "admin", Name: "admin", - }} - return user, nil -} -func authorize(user rbac.User) (m map[string]interface{}, err error) { - - var roles, privilege []string - for _, v := range user.Roles { - role := RoleMap[v.Name] - roles = append(roles, v.Name) - privilege = append(privilege, role.Privilege.Platform...) - } - token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaims{ - ShortUser: &ShortUser{ - Username: user.Name, - UserId: user.ID, - Roles: roles, - }, - RegisteredClaims: &jwt.RegisteredClaims{ - ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), - }, - }) - - tokenString, err := token.SignedString([]byte(Secret)) - if err != nil { - return - } - - m = util.MapStr{ - "access_token": tokenString, - "username": user.Name, - "id": user.ID, - "expire_in": 86400, - "roles": roles, - "privilege": privilege, - } - return -} -func Login(username string, password string) (m map[string]interface{}, err error) { - var user rbac.User - if username == "admin" { - user, err = authenticateAdmin(username, password) - if err != nil { - return nil, err - } - - } else { - user, err = authenticateUser(username, password) - if err != nil { - return nil, err - } - } - - m, err = authorize(user) - if err != nil { - return - } - TokenMap[user.ID] = Token{ExpireIn: time.Now().Unix() + 86400} - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "login", - Type: "create", - Labels: util.MapStr{ - "username": username, - "password": password, - }, - User: util.MapStr{ - "id": user.ID, - "name": user.Name, - }, - }, nil, nil)) - return -} -func UpdatePassword(localUser *ShortUser, req dto.UpdatePassword) (err error) { - user := rbac.User{} - user.ID = localUser.UserId - _, err = orm.Get(&user) - if err != nil { - - return - } - err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword)) - if err == bcrypt.ErrMismatchedHashAndPassword { - err = errors.New("old password is not correct") - return - } - hash, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost) - if err != nil { - return - } - user.Password = string(hash) - err = orm.Save(&user) - if err != nil { - return - } - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "user", - Type: "update", - Labels: util.MapStr{ - "old_password": req.OldPassword, - "new_password": req.NewPassword, - }, - User: util.MapStr{ - "id": user.ID, - "name": user.Name, - }, - }, nil, nil)) - return -} -func UpdateProfile(localUser *ShortUser, req dto.UpdateProfile) (err error) { - user := rbac.User{} - user.ID = localUser.UserId - _, err = orm.Get(&user) - if err != nil { - return - } - user.Name = req.Name - user.Email = req.Email - user.Phone = req.Phone - err = orm.Save(&user) - if err != nil { - return - } - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "user", - Type: "update", - Labels: util.MapStr{ - "name": req.Name, - "email": req.Email, - "phone": req.Phone, - }, - User: util.MapStr{ - "id": user.ID, - "name": user.Name, - }, - }, nil, nil)) - return -} diff --git a/internal/biz/context.go b/internal/biz/context.go deleted file mode 100644 index cc152225..00000000 --- a/internal/biz/context.go +++ /dev/null @@ -1,23 +0,0 @@ -package biz - -import ( - "context" - "errors" -) - -const ctxUserKey = "user" - -func NewUserContext(ctx context.Context, clam *UserClaims) context.Context { - return context.WithValue(ctx, ctxUserKey, clam) -} -func FromUserContext(ctx context.Context) (*ShortUser, error) { - ctxUser := ctx.Value(ctxUserKey) - if ctxUser == nil { - return nil, errors.New("user not found") - } - reqUser, ok := ctxUser.(*UserClaims) - if !ok { - return nil, errors.New("invalid context user") - } - return reqUser.ShortUser, nil -} diff --git a/internal/biz/enum/const.go b/internal/biz/enum/const.go deleted file mode 100644 index 5a313392..00000000 --- a/internal/biz/enum/const.go +++ /dev/null @@ -1,192 +0,0 @@ -package enum - -import ( - "time" -) - -var PermissionMap = make(map[string][]string) - -const ( - UserRead = "system.user:read" - UserAll = "system.user:all" - RoleRead = "system.role:read" - RoleAll = "system.role:all" - ClusterAll = "system.cluster:all" - ClusterRead = "system.cluster:read" - CommandAll = "system.command:all" - CommandRead = "system.command:read" - - InstanceRead = "gateway.instance:read" - InstanceAll = "gateway.instance:all" - EntryAll = "gateway.entry:all" - EntryRead = "gateway.entry:read" - RouterRead = "gateway.router:read" - RouterAll = "gateway.router:all" - FlowRead = "gateway.flow:read" - FlowAll = "gateway.flow:all" - - IndexAll = "data.index:all" - IndexRead = "data.index:read" - ViewsAll = "data.view:all" - ViewsRead = "data.view:read" - DiscoverAll = "data.discover:all" - DiscoverRead = "data.discover:read" - - RuleRead = "alerting.rule:read" - RuleAll = "alerting.rule:all" - AlertRead = "alerting.alert:read" - AlertAll = "alerting.alert:all" - ChannelRead = "alerting.channel:read" - ChannelAll = "alerting.channel:all" - - ClusterOverviewRead = "cluster.overview:read" - ClusterOverviewAll = "cluster.overview:all" - MonitoringRead = "cluster.monitoring:read" - MonitoringAll = "cluster.monitoring:all" - ActivitiesRead = "cluster.activities:read" - ActivitiesAll = "cluster.activities:all" -) - -const ( - PermissionUserRead string = "user:read" - PermissionUserWrite = "user:write" - PermissionRoleRead = "role:read" - PermissionRoleWrite = "role:write" - PermissionCommandRead = "command:read" - PermissionCommandWrite = "command:write" - PermissionElasticsearchClusterRead = "es.cluster:read" - PermissionElasticsearchClusterWrite = "es.cluster:write" // es cluster - PermissionElasticsearchIndexRead = "es.index:read" - PermissionElasticsearchIndexWrite = "es.index:write" // es index metadata - PermissionElasticsearchNodeRead = "es.node:read" //es node metadata - PermissionActivityRead = "activity:read" - PermissionActivityWrite = "activity:write" - PermissionAlertRuleRead = "alert.rule:read" - PermissionAlertRuleWrite = "alert.rule:write" - PermissionAlertHistoryRead = "alert.history:read" - PermissionAlertHistoryWrite = "alert.history:write" - PermissionAlertChannelRead = "alert.channel:read" - PermissionAlertChannelWrite = "alert.channel:write" - PermissionViewRead = "view:read" - PermissionViewWrite = "view:write" - PermissionGatewayInstanceRead = "gateway.instance:read" - PermissionGatewayInstanceWrite = "gateway.instance:write" - PermissionGatewayEntryRead = "gateway.entry:read" - PermissionGatewayEntryWrite = "gateway.entry:write" - PermissionGatewayRouterRead = "gateway.router:read" - PermissionGatewayRouterWrite = "gateway.router:write" - PermissionGatewayFlowRead = "gateway.flow:read" - PermissionGatewayFlowWrite = "gateway.flow:write" - PermissionElasticsearchMetricRead = "es.metric:read" -) - -var ( - UserReadPermission = []string{PermissionUserRead} - UserAllPermission = []string{PermissionUserRead, PermissionUserWrite,PermissionRoleRead} - - RoleReadPermission = []string{PermissionRoleRead} - RoleAllPermission = []string{PermissionRoleRead, PermissionRoleWrite} - - ClusterReadPermission = []string{PermissionElasticsearchClusterRead} - ClusterAllPermission = []string{PermissionElasticsearchClusterRead, PermissionElasticsearchClusterWrite} - - CommandReadPermission = []string{PermissionCommandRead} - CommandAllPermission = []string{PermissionCommandRead, PermissionCommandWrite} - - InstanceReadPermission = []string{PermissionGatewayInstanceRead} - InstanceAllPermission = []string{PermissionGatewayInstanceRead,PermissionGatewayInstanceWrite} - - EntryReadPermission = []string{PermissionGatewayEntryRead} - EntryAllPermission = []string{PermissionGatewayEntryRead, PermissionGatewayEntryWrite} - - RouterReadPermission = []string{PermissionGatewayRouterRead} - RouterAllPermission = []string{PermissionGatewayRouterRead, PermissionGatewayRouterWrite} - - FlowReadPermission = []string{PermissionGatewayFlowRead} - FlowAllPermission = []string{PermissionGatewayFlowRead, PermissionGatewayFlowWrite} - - IndexAllPermission = []string{"index:read"} - IndexReadPermission = []string{"index:read", "index:write"} - ViewsAllPermission = []string{PermissionViewRead} - ViewsReadPermission = []string{PermissionViewRead, PermissionViewWrite} - DiscoverReadPermission = []string{PermissionViewRead} - DiscoverAllPermission = []string{PermissionViewRead} - - RuleReadPermission = []string{PermissionAlertRuleRead} - RuleAllPermission = []string{PermissionAlertRuleRead, PermissionAlertRuleWrite} - AlertReadPermission = []string{PermissionAlertHistoryRead} - AlertAllPermission = []string{PermissionAlertHistoryRead, PermissionAlertHistoryWrite} - ChannelReadPermission = []string{PermissionAlertChannelRead} - ChannelAllPermission = []string{PermissionAlertChannelRead, PermissionAlertChannelWrite} - - ClusterOverviewReadPermission = []string{PermissionElasticsearchClusterRead, PermissionElasticsearchIndexRead, PermissionElasticsearchNodeRead, PermissionElasticsearchMetricRead} - ClusterOverviewAllPermission = ClusterOverviewReadPermission - MonitoringReadPermission = ClusterOverviewAllPermission - - ActivitiesReadPermission = []string{PermissionActivityRead} - ActivitiesAllPermission = []string{PermissionActivityRead, PermissionActivityWrite} -) - -var AdminPrivilege = []string{ - UserAll, RoleAll, ClusterAll, CommandAll, - InstanceAll, EntryAll, RouterAll, FlowAll, - IndexAll, ViewsAll, DiscoverAll, - RuleAll, AlertAll, ChannelAll, - ClusterOverviewAll, MonitoringAll, ActivitiesAll, -} - -var BuildRoles = make(map[string]map[string]interface{}, 0) - -func init() { - - BuildRoles["admin"] = map[string]interface{}{ - "id": "admin", - "name": "管理员", - "type": "platform", - "platform": AdminPrivilege, - "builtin": true, - "description": "is admin", - "created": time.Now(), - } - PermissionMap = map[string][]string{ - UserRead: UserReadPermission, - UserAll: UserAllPermission, - RoleRead: RoleReadPermission, - RoleAll: RoleAllPermission, - ClusterRead: ClusterReadPermission, - ClusterAll: ClusterAllPermission, - CommandRead: CommandReadPermission, - CommandAll: CommandAllPermission, - - InstanceRead: InstanceReadPermission, - InstanceAll: InstanceAllPermission, - EntryRead: EntryReadPermission, - EntryAll: EntryAllPermission, - RouterRead: RouterReadPermission, - RouterAll: RouterAllPermission, - FlowRead: FlowReadPermission, - FlowAll: FlowAllPermission, - - IndexAll: IndexAllPermission, - IndexRead: IndexReadPermission, - ViewsAll: ViewsAllPermission, - ViewsRead: ViewsReadPermission, - DiscoverRead: DiscoverReadPermission, - DiscoverAll: DiscoverAllPermission, - - RuleRead: RuleReadPermission, - RuleAll: RuleAllPermission, - AlertRead: AlertReadPermission, - AlertAll: AlertAllPermission, - ChannelRead: ChannelReadPermission, - ChannelAll: ChannelAllPermission, - - ClusterOverviewRead: ClusterOverviewReadPermission, - ClusterOverviewAll: ClusterOverviewAllPermission, - MonitoringAll: MonitoringReadPermission, - MonitoringRead: MonitoringReadPermission, - ActivitiesAll: ActivitiesAllPermission, - ActivitiesRead: ActivitiesReadPermission, - } - -} diff --git a/internal/biz/event.go b/internal/biz/event.go deleted file mode 100644 index 224b82a5..00000000 --- a/internal/biz/event.go +++ /dev/null @@ -1,18 +0,0 @@ -package biz - -import ( - "infini.sh/framework/core/event" - "infini.sh/framework/core/util" - "time" -) - -func GenerateEvent(metadata event.ActivityMetadata, fields util.MapStr, changeLog interface{}) *event.Activity { - return &event.Activity{ - ID: util.GetUUID(), - Timestamp: time.Now(), - Metadata: metadata, - Fields: fields, - Changelog: changeLog, - } - -} diff --git a/internal/biz/permission.go b/internal/biz/permission.go deleted file mode 100644 index cfd64286..00000000 --- a/internal/biz/permission.go +++ /dev/null @@ -1,40 +0,0 @@ -package biz - -import ( - "infini.sh/console/model/rbac" -) - -var ClusterApis = make(map[string][]string) -var IndexApis = make([]string, 50) - -var RoleMap = make(map[string]rbac.Role) - -type Token struct { - JwtStr string `json:"jwt_str"` - Value string `json:"value"` - ExpireIn int64 `json:"expire_in"` -} - -var TokenMap = make(map[string]Token) - - -type RolePermission struct { - Platform []string `json:"platform,omitempty"` - Cluster []string `json:"cluster"` - ClusterPrivilege []string `json:"cluster_privilege"` - - IndexPrivilege map[string][]string `json:"index_privilege"` -} - -func ListElasticsearchPermission() interface{} { - list := ElasticsearchPermission{ - ClusterPrivileges: ClusterApis, - IndexPrivileges: IndexApis, - } - return list -} - -type ElasticsearchPermission struct { - IndexPrivileges []string `json:"index_privileges"` - ClusterPrivileges map[string][]string `json:"cluster_privileges"` -} diff --git a/internal/biz/role.go b/internal/biz/role.go deleted file mode 100644 index ec9807df..00000000 --- a/internal/biz/role.go +++ /dev/null @@ -1,162 +0,0 @@ -package biz - -import ( - "errors" - "fmt" - "infini.sh/console/internal/biz/enum" - "infini.sh/console/model/rbac" - "infini.sh/framework/core/event" - "infini.sh/framework/core/orm" - "infini.sh/framework/core/util" - log "src/github.com/cihub/seelog" - "strings" - "time" -) - -type RoleType = string - -const ( - Platform RoleType = "platform" - Elasticsearch RoleType = "elasticsearch" -) - -func UpdateRole(role *rbac.Role) (err error) { - model, err := GetRole(role.ID) - if err != nil { - return err - } - role.Type = model.Type - role.Created = model.Created - role.Updated = time.Now() - err = orm.Save(role) - return -} - -func CreateRole(localUser *ShortUser, role *rbac.Role) (id string, err error) { - if role.Name == "" { - err = errors.New("role name is require") - return - } - if _, ok := enum.BuildRoles[role.Name]; ok { - err = fmt.Errorf("role name %s already exists", role.Name) - return - } - q := orm.Query{Size: 1} - q.Conds = orm.And(orm.Eq("name", role.Name)) - - err, result := orm.Search(rbac.Role{}, &q) - if err != nil { - return - } - if result.Total > 0 { - err = fmt.Errorf("role name %s already exists", role.Name) - return - } - - role.ID = util.GetUUID() - role.Created = time.Now() - role.Updated = time.Now() - err = orm.Save(role) - if err != nil { - return - } - id = role.ID - RoleMap[role.Name] = *role - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "role", - Type: "create", - Labels: util.MapStr{ - "id": id, - "name": role.Name, - "description": role.Description, - "privilege": role.Privilege, - "type": role.Type, - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, nil, nil)) - - if err != nil { - log.Error(err) - } - return - -} -func DeleteRole(localUser *ShortUser, id string) (err error) { - role := rbac.Role{} - role.ID = id - roleName := role.Name - _, err = orm.Get(&role) - if err != nil { - return - } - - err = orm.Delete(&role) - if err != nil { - return - } - - delete(RoleMap, roleName) - - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "role", - Type: "delete", - Labels: util.MapStr{ - "id": id, - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, util.MapStr{ - "id": id, - "name": role.Name, - "description": role.Description, - "type": role.Type, - "created": role.Created.Format("2006-01-02 15:04:05"), - "updated": role.Updated.Format("2006-01-02 15:04:05"), - }, nil)) - - return -} - -func GetRole(id string) (role rbac.Role, err error) { - - role.ID = id - _, err = orm.Get(&role) - if err != nil { - return - } - return -} - -func SearchRole(keyword string, from, size int) (roles orm.Result, err error) { - - query := orm.Query{} - - queryDSL := `{"query":{"bool":{"must":[%s]}}, "from": %d,"size": %d}` - mustBuilder := &strings.Builder{} - - if keyword != "" { - mustBuilder.WriteString(fmt.Sprintf(`{"query_string":{"default_field":"*","query": "%s"}}`, keyword)) - } - queryDSL = fmt.Sprintf(queryDSL, mustBuilder.String(), from, size) - query.RawQuery = []byte(queryDSL) - - err, roles = orm.Search(rbac.Role{}, &query) - - return -} -func IsAllowRoleType(roleType string) (err error) { - if roleType != Platform && roleType != Elasticsearch { - err = fmt.Errorf("invalid role type %s ", roleType) - return - } - return -} diff --git a/internal/biz/user.go b/internal/biz/user.go deleted file mode 100644 index 667da8ac..00000000 --- a/internal/biz/user.go +++ /dev/null @@ -1,279 +0,0 @@ -package biz - -import ( - "fmt" - "golang.org/x/crypto/bcrypt" - "infini.sh/console/internal/dto" - "infini.sh/console/model/rbac" - "infini.sh/framework/core/event" - - "infini.sh/framework/core/orm" - "infini.sh/framework/core/util" - "strings" - "time" -) - -var ErrNotFound = fmt.Errorf("not found") - -func DeleteUser(localUser *ShortUser, id string) (err error) { - - user := rbac.User{} - user.ID = id - _, err = orm.Get(&user) - if err != nil { - return - } - err = orm.Delete(user) - if err != nil { - return - } - - delete(TokenMap, id) - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "user", - Type: "delete", - Labels: util.MapStr{ - "id": id, - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, util.MapStr{ - "id": id, - "name": user.Name, - "email": user.Email, - "phone": user.Phone, - "password": user.Password, - "nickname": user.NickName, - "tags": user.Tags, - "roles": user.Roles, - "created": user.Created, - "updated": user.Updated, - }, nil)) - return -} -func CreateUser(localUser *ShortUser, req dto.CreateUser) (id string, password string, err error) { - q := orm.Query{Size: 1000} - q.Conds = orm.And(orm.Eq("name", req.Name)) - - err, result := orm.Search(rbac.User{}, &q) - if err != nil { - return - } - if result.Total > 0 { - err = fmt.Errorf("user name %s already exists", req.Name) - return - } - - roles := make([]rbac.UserRole, 0) - for _, v := range req.Roles { - roles = append(roles, rbac.UserRole{ - ID: v.Id, - Name: v.Name, - }) - } - randStr := util.GenerateRandomString(8) - hash, err := bcrypt.GenerateFromPassword([]byte(randStr), bcrypt.DefaultCost) - if err != nil { - return - } - user := rbac.User{ - Name: req.Name, - NickName: req.NickName, - Password: string(hash), - Email: req.Email, - Phone: req.Phone, - Roles: roles, - Tags: req.Tags, - } - user.ID = util.GetUUID() - user.Created = time.Now() - user.Updated = time.Now() - err = orm.Save(&user) - if err != nil { - - return - } - id = user.ID - password = randStr - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "user", - Type: "create", - Labels: util.MapStr{ - "id": id, - "name": user.Name, - "email": user.Email, - "phone": user.Phone, - "password": user.Password, - "nick_name": user.NickName, - "tags": user.Tags, - "roles": user.Roles, - "created": user.Created, - "updated": user.Updated, - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, nil, nil)) - return -} -func UpdateUser(localUser *ShortUser, id string, req dto.UpdateUser) (err error) { - user := rbac.User{} - user.ID = id - _, err = orm.Get(&user) - if err != nil { - return - } - roles := make([]rbac.UserRole, 0) - for _, v := range req.Roles { - roles = append(roles, rbac.UserRole{ - ID: v.Id, - Name: v.Name, - }) - } - changeLog, _ := util.DiffTwoObject(user, req) - user.Name = req.Name - user.Email = req.Email - user.Phone = req.Phone - user.Tags = req.Tags - user.Roles = roles - user.Updated = time.Now() - err = orm.Save(&user) - if err != nil { - return - } - delete(TokenMap, id) - - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "user", - Type: "update", - Labels: util.MapStr{ - "id": id, - "email": user.Email, - "phone": user.Phone, - "name": user.Name, - "tags": user.Tags, - "roles": roles, - "updated": user.Updated, - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, nil, changeLog)) - return -} -func UpdateUserRole(localUser *ShortUser, id string, req dto.UpdateUserRole) (err error) { - user := rbac.User{} - user.ID = id - _, err = orm.Get(&user) - if err != nil { - - return - } - changeLog, _ := util.DiffTwoObject(user, req) - roles := make([]rbac.UserRole, 0) - for _, v := range req.Roles { - roles = append(roles, rbac.UserRole{ - ID: v.Id, - Name: v.Name, - }) - } - user.Roles = roles - user.Updated = time.Now() - err = orm.Save(&user) - if err != nil { - return - } - delete(TokenMap, id) - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "user", - Type: "update", - Labels: util.MapStr{ - "id": id, - "roles": user.Roles, - "updated": user.Updated, - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, nil, changeLog)) - return - -} -func GetUser(id string) (user rbac.User, err error) { - - user.ID = id - _, err = orm.Get(&user) - if err != nil { - return - } - return - -} -func SearchUser(keyword string, from, size int) (users orm.Result, err error) { - query := orm.Query{} - - queryDSL := `{"query":{"bool":{"must":[%s]}}, "from": %d,"size": %d}` - mustBuilder := &strings.Builder{} - - if keyword != "" { - mustBuilder.WriteString(fmt.Sprintf(`{"query_string":{"default_field":"*","query": "%s"}}`, keyword)) - } - queryDSL = fmt.Sprintf(queryDSL, mustBuilder.String(), from, size) - query.RawQuery = []byte(queryDSL) - - err, users = orm.Search(rbac.User{}, &query) - - return - -} -func UpdateUserPassword(localUser *ShortUser, id string, password string) (err error) { - user := rbac.User{} - user.ID = id - _, err = orm.Get(&user) - if err != nil { - - return - } - hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - if err != nil { - return - } - user.Password = string(hash) - user.Updated = time.Now() - err = orm.Save(&user) - if err != nil { - return - } - if localUser.UserId == id { - delete(TokenMap, localUser.UserId) - } - err = orm.Save(GenerateEvent(event.ActivityMetadata{ - Category: "platform", - Group: "rbac", - Name: "user", - Type: "update", - Labels: util.MapStr{ - "id": id, - "password": password, - "updated": user.Updated, - }, - User: util.MapStr{ - "userid": localUser.UserId, - "username": localUser.Username, - }, - }, nil, nil)) - return -} diff --git a/internal/biz/validate.go b/internal/biz/validate.go deleted file mode 100644 index 86e8f0ff..00000000 --- a/internal/biz/validate.go +++ /dev/null @@ -1,273 +0,0 @@ -package biz - -import ( - "errors" - "fmt" - "infini.sh/console/internal/biz/enum" - "infini.sh/console/model/rbac" - httprouter "infini.sh/framework/core/api/router" - "infini.sh/framework/core/util" - "src/github.com/golang-jwt/jwt" - "strings" - "time" -) - -type EsRequest struct { - Doc string `json:"doc"` - Privilege string `json:"privilege"` - ClusterRequest - IndexRequest -} -type ClusterRequest struct { - Cluster []string `json:"cluster"` - Privilege []string `json:"privilege"` -} -type IndexRequest struct { - Cluster []string `json:"cluster"` - Index []string `json:"index"` - Privilege []string `json:"privilege"` -} - -func NewIndexRequest(ps httprouter.Params, privilege []string) IndexRequest { - index := ps.ByName("index") - clusterId := ps.ByName("id") - return IndexRequest{ - Cluster: []string{clusterId}, - Index: []string{index}, - Privilege: privilege, - } -} -func NewClusterRequest(ps httprouter.Params, privilege []string) ClusterRequest { - clusterId := ps.ByName("id") - return ClusterRequest{ - Cluster: []string{clusterId}, - Privilege: privilege, - } -} - -func ValidateElasticsearch(req rbac.ElasticsearchPrivilege, roleNames []string) (err error) { - - return nil -} - -func ValidateIndex(req IndexRequest, userRole RolePermission) (err error) { - - userClusterMap := make(map[string]struct{}) - for _, v := range userRole.Cluster { - userClusterMap[v] = struct{}{} - } - for _, v := range req.Cluster { - if _, ok := userClusterMap[v]; !ok { - err = errors.New("no cluster permission") - return - } - } - - for _, val := range req.Privilege { - position := strings.Index(val, ".") - if position == -1 { - err = errors.New("invalid privilege parameter") - return err - } - prefix := val[:position] - for _, v := range req.Index { - privilege, ok := userRole.IndexPrivilege[v] - if !ok { - err = errors.New("no index permission") - return err - } - if util.StringInArray(privilege, prefix+".*") { - continue - } - if util.StringInArray(privilege, val) { - continue - } - return fmt.Errorf("no index api permission: %s", val) - } - } - - return nil -} -func ValidateCluster(req ClusterRequest, roleNames []string) (err error) { - userClusterMap := GetRoleClusterMap(roleNames) - for _, v := range req.Cluster { - userClusterPermissions, ok := userClusterMap[v] - if !ok && userClusterMap["*"] == nil{ - err = fmt.Errorf("no cluster[%s] permission", v) - return - } - if util.StringInArray(userClusterPermissions, "*") { - continue - } - // if include api.* for example: cat.* , return nil - for _, privilege := range req.Privilege { - prefix := privilege[:strings.Index(privilege, ".")] - - if util.StringInArray(userClusterPermissions, prefix+".*") { - continue - } - if util.StringInArray(userClusterPermissions, privilege) { - continue - } - return fmt.Errorf("no cluster api permission: %s", privilege) - } - } - return nil - -} - -func CombineUserRoles(roleNames []string) RolePermission { - newRole := RolePermission{} - m := make(map[string][]string) - for _, val := range roleNames { - role := RoleMap[val] - for _, v := range role.Privilege.Elasticsearch.Cluster.Resources { - newRole.Cluster = append(newRole.Cluster, v.ID) - } - for _, v := range role.Privilege.Elasticsearch.Cluster.Permissions { - newRole.ClusterPrivilege = append(newRole.ClusterPrivilege, v) - } - for _, v := range role.Privilege.Platform { - newRole.Platform = append(newRole.Platform, v) - } - for _, v := range role.Privilege.Elasticsearch.Index { - - for _, name := range v.Name { - if _, ok := m[name]; ok { - m[name] = append(m[name], v.Permissions...) - } else { - m[name] = v.Permissions - } - - } - - } - } - newRole.IndexPrivilege = m - return newRole -} -func GetRoleClusterMap(roles []string) map[string][]string { - userClusterMap := make(map[string][]string, 0) - for _, roleName := range roles { - role, ok := RoleMap[roleName] - if ok { - for _, ic := range role.Privilege.Elasticsearch.Cluster.Resources { - userClusterMap[ic.ID] = append(userClusterMap[ic.ID], role.Privilege.Elasticsearch.Cluster.Permissions...) - } - } - } - return userClusterMap -} -func GetRoleCluster(roles []string) []string { - userClusterMap := GetRoleClusterMap(roles) - realCluster := make([]string, 0, len(userClusterMap)) - for k, _ := range userClusterMap { - realCluster = append(realCluster, k) - } - return realCluster -} -func GetRoleIndex(roles, clusterIDs []string) map[string][]string { - userClusterMap := make(map[string]struct{}, len(clusterIDs)) - for _, clusterID := range clusterIDs { - userClusterMap[clusterID] = struct{}{} - } - realIndex := map[string][]string{} - for _, roleName := range roles { - role, ok := RoleMap[roleName] - if ok { - for _, ic := range role.Privilege.Elasticsearch.Cluster.Resources { - if _, ok = userClusterMap[ic.ID]; !ok { - continue - } - for _, ip := range role.Privilege.Elasticsearch.Index { - realIndex[ic.ID] = append(realIndex[ic.ID], ip.Name...) - } - } - } - } - return realIndex -} -func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) { - - if authorizationHeader == "" { - err = errors.New("authorization header is empty") - return - } - fields := strings.Fields(authorizationHeader) - if fields[0] != "Bearer" || len(fields) != 2 { - err = errors.New("authorization header is invalid") - return - } - tokenString := fields[1] - - token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) { - if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { - return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) - } - return []byte(Secret), nil - }) - if err != nil { - return - } - clams, ok := token.Claims.(*UserClaims) - - if clams.UserId == "" { - err = errors.New("user id is empty") - return - } - //fmt.Println("user token", clams.UserId, TokenMap[clams.UserId]) - tokenVal, ok := TokenMap[clams.UserId] - if !ok { - err = errors.New("token is invalid") - return - } - if tokenVal.ExpireIn < time.Now().Unix() { - err = errors.New("token is expire in") - delete(TokenMap, clams.UserId) - return - } - if ok && token.Valid { - return clams, nil - } - return - -} -func ValidatePermission(claims *UserClaims, permissions []string) (err error) { - - user := claims.ShortUser - - if user.UserId == "" { - err = errors.New("user id is empty") - return - } - if user.Roles == nil { - err = errors.New("api permission is empty") - return - } - - // 权限校验 - userPermissions := make([]string, 0) - for _, role := range user.Roles { - if _, ok := RoleMap[role]; ok { - for _, v := range RoleMap[role].Privilege.Platform { - userPermissions = append(userPermissions, v) - } - } - } - userPermissionMap := make(map[string]struct{}) - for _, val := range userPermissions { - for _, v := range enum.PermissionMap[val] { - userPermissionMap[v] = struct{}{} - } - - } - - for _, v := range permissions { - if _, ok := userPermissionMap[v]; !ok { - err = errors.New("permission denied") - return - } - } - return nil - -} diff --git a/internal/biz/validate_test.go b/internal/biz/validate_test.go deleted file mode 100644 index 345e12f4..00000000 --- a/internal/biz/validate_test.go +++ /dev/null @@ -1,147 +0,0 @@ -package biz - -import ( - "github.com/stretchr/testify/assert" - "infini.sh/framework/core/util" - "testing" -) - -func Test_validateIndex(t *testing.T) { - type args struct { - req IndexRequest - userRole RolePermission - } - tests := []struct { - name string - args args - want string - }{ - {"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 { - t.Run(tt.name, func(t *testing.T) { - - got := ValidateIndex(tt.args.req, tt.args.userRole) - - assert.EqualError(t, got, tt.want) - }) - } -} -func Test_validateCluster(t *testing.T) { - type args struct { - req ClusterRequest - userRole RolePermission - } - tests := []struct { - name string - args args - want string - }{ - {"no cluster", - args{ - req: ClusterRequest{ - - Cluster: []string{"cluster1"}, - Privilege: []string{"indices.get_mapping"}, - }, - userRole: RolePermission{ - Cluster: []string{ - "cluster2", - }, - - ClusterPrivilege: []string{ - "cat.*", - }, - }, - }, "no cluster permission", - }, - {"no cluster", - args{ - req: ClusterRequest{ - Cluster: []string{"cluster1"}, - Privilege: []string{"indices.get_mapping"}, - }, - userRole: RolePermission{ - Cluster: []string{}, - ClusterPrivilege: []string{}, - }, - }, "no cluster permission", - }, - {"no cluster api", - args{ - req: ClusterRequest{ - - Cluster: []string{"cluster1"}, - Privilege: []string{"indices.get_mapping"}, - }, - userRole: RolePermission{ - Cluster: []string{ - "cluster1", - }, - - ClusterPrivilege: []string{ - "cat.*", - }, - }, - }, - "no cluster api permission", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := ValidateCluster(tt.args.req, tt.args.userRole) - assert.EqualError(t, got, tt.want) - }) - } -} -func TestStringInArray(t *testing.T) { - array := []string{"a", "b", "c", "d", "e"} - assert.Equal(t, true, util.StringInArray(array, "c")) - assert.Equal(t, false, util.StringInArray(array, "h")) -} diff --git a/internal/core/response.go b/internal/core/response.go deleted file mode 100644 index 0804e91c..00000000 --- a/internal/core/response.go +++ /dev/null @@ -1,45 +0,0 @@ -package core - -type Response struct { - Total int64 `json:"total,omitempty"` - Hit interface{} `json:"hit,omitempty"` - Id string `json:"_id,omitempty"` - Result string `json:"result,omitempty"` -} -type FoundResp struct { - Found bool `json:"found"` - Id string `json:"_id,omitempty"` - Source interface{} `json:"_source,omitempty"` -} - -func CreateResponse(id string) Response { - return Response{ - Id: id, - Result: "created", - } -} -func UpdateResponse(id string) Response { - return Response{ - Id: id, - Result: "updated", - } -} -func DeleteResponse(id string) Response { - return Response{ - Id: id, - Result: "deleted", - } -} -func NotFoundResponse(id string) FoundResp { - return FoundResp{ - Id: id, - Found: false, - } -} -func FoundResponse(id string, data interface{}) FoundResp { - return FoundResp{ - Id: id, - Found: true, - Source: data, - } -} diff --git a/internal/dto/role.go b/internal/dto/role.go deleted file mode 100644 index 806dba23..00000000 --- a/internal/dto/role.go +++ /dev/null @@ -1,28 +0,0 @@ -package dto - -type CreateUser struct { - NickName string `json:"nick_name"` - - Name string `json:"name"` - Email string `json:"email"` - Phone string `json:"phone"` - Roles []Role `json:"roles"` - Tags []string `json:"tags"` -} -type Role struct { - Id string `json:"id"` - Name string `json:"name"` -} -type UpdateUser struct { - Name string `json:"name"` - Email string `json:"email"` - Phone string `json:"phone"` - Tags []string `json:"tags"` - Roles []Role `json:"roles"` -} -type UpdateUserRole struct { - Roles []Role `json:"roles"` -} -type UpdateUserPassword struct { - Password string `json:"password"` -} diff --git a/internal/dto/user.go b/internal/dto/user.go deleted file mode 100644 index 68d7ed83..00000000 --- a/internal/dto/user.go +++ /dev/null @@ -1,15 +0,0 @@ -package dto - -type Login struct { - Username string `json:"username"` - Password string `json:"password"` -} -type UpdatePassword struct { - OldPassword string `json:"old_password"` - NewPassword string `json:"new_password"` -} -type UpdateProfile struct { - Name string `json:"name"` - Phone string `json:"phone"` - Email string `json:"email"` -} diff --git a/internal/middleware/es.go b/internal/middleware/es.go deleted file mode 100644 index c8aa78db..00000000 --- a/internal/middleware/es.go +++ /dev/null @@ -1,47 +0,0 @@ -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, claims.Roles) - if err != nil { - w = handleError(w, http.StatusForbidden, err) - return - } - h(w, r, ps) - } -} diff --git a/internal/middleware/user.go b/internal/middleware/user.go deleted file mode 100644 index 3f13b419..00000000 --- a/internal/middleware/user.go +++ /dev/null @@ -1,52 +0,0 @@ -package middleware - -import ( - "infini.sh/console/internal/biz" - httprouter "infini.sh/framework/core/api/router" - "infini.sh/framework/core/util" - "net/http" -) - -func LoginRequired(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 - } - r = r.WithContext(biz.NewUserContext(r.Context(), claims)) - h(w, r, ps) - } -} - -func PermissionRequired(h httprouter.Handle, permissions ...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 - } - err = biz.ValidatePermission(claims, permissions) - if err != nil { - w = handleError(w, http.StatusForbidden, err) - return - } - r = r.WithContext(biz.NewUserContext(r.Context(), claims)) - h(w, r, ps) - } -} -func handleError(w http.ResponseWriter, statusCode int, err error) http.ResponseWriter { - w.Header().Set("Content-type", util.ContentTypeJson) - w.WriteHeader(statusCode) - json := util.ToJson(util.MapStr{ - "error": util.MapStr{ - "status": statusCode, - "reason": err.Error(), - }, - }, true) - w.Write([]byte(json)) - - return w -} diff --git a/model/rbac/role.go b/model/rbac/role.go deleted file mode 100644 index 6e1e6fb4..00000000 --- a/model/rbac/role.go +++ /dev/null @@ -1,40 +0,0 @@ -package rbac - -import ( - "time" -) - -type Role struct { - ID string `json:"id,omitempty" elastic_meta:"_id" elastic_mapping:"id: { type: keyword }"` - Created time.Time `json:"created,omitempty" elastic_mapping:"created: { type: date }"` - Updated time.Time `json:"updated,omitempty" elastic_mapping:"updated: { type: date }"` - Name string `json:"name" elastic_mapping:"name: { type: keyword }"` - Type string `json:"type" elastic_mapping:"type: { type: keyword }"` - Description string `json:"description" elastic_mapping:"description: { type: text }"` - Builtin bool `json:"builtin" elastic_mapping:"builtin: { type: boolean }"` - Privilege RolePrivilege `json:"privilege" elastic_mapping:"privilege: { type: object }"` -} - -type RolePrivilege struct { - Platform []string `json:"platform,omitempty" elastic_mapping:"platform: { type: keyword }"` - Elasticsearch ElasticsearchPrivilege `json:"elasticsearch,omitempty" elastic_mapping:"elasticsearch: { type: object }"` -} - -type ElasticsearchPrivilege struct { - Cluster ClusterPrivilege `json:"cluster,omitempty" elastic_mapping:"cluster: { type: object }"` - Index []IndexPrivilege `json:"index,omitempty" elastic_mapping:"index: { type: object }"` -} - -type InnerCluster struct { - ID string `json:"id" elastic_mapping:"id: { type: keyword }"` - Name string `json:"name" elastic_mapping:"name: { type: keyword }"` -} -type ClusterPrivilege struct { - Resources []InnerCluster `json:"resources,omitempty" elastic_mapping:"resources: { type: object }"` - Permissions []string `json:"permissions,omitempty" elastic_mapping:"permissions: { type: keyword }"` -} - -type IndexPrivilege struct { - Name []string `json:"name,omitempty" elastic_mapping:"name: { type: keyword }"` - Permissions []string `json:"permissions,omitempty" elastic_mapping:"permissions: { type: keyword }"` -} \ No newline at end of file diff --git a/model/rbac/user.go b/model/rbac/user.go deleted file mode 100644 index c5f626a4..00000000 --- a/model/rbac/user.go +++ /dev/null @@ -1,23 +0,0 @@ -package rbac - -import ( - "time" -) - -type User struct { - ID string `json:"id,omitempty" elastic_meta:"_id" elastic_mapping:"id: { type: keyword }"` - Created time.Time `json:"created,omitempty" elastic_mapping:"created: { type: date }"` - Updated time.Time `json:"updated,omitempty" elastic_mapping:"updated: { type: date }"` - Name string `json:"name" elastic_mapping:"name: { type: keyword }"` - NickName string `json:"nick_name" elastic_mapping:"nick_name: { type: keyword }"` - Password string `json:"password" elastic_mapping:"password: { type: keyword }"` - Email string `json:"email" elastic_mapping:"email: { type: keyword }"` - Phone string `json:"phone" elastic_mapping:"phone: { type: keyword }"` - Tags []string `json:"tags" elastic_mapping:"mobile: { type: keyword }"` - Roles []UserRole `json:"roles" elastic_mapping:"roles: { type: object }"` -} - -type UserRole struct { - ID string `json:"id" elastic_mapping:"id: { type: keyword }"` - Name string `json:"name" elastic_mapping:"name: { type: keyword }"` -} \ No newline at end of file diff --git a/plugin/api/init.go b/plugin/api/init.go index 766b40e4..e7fa2f9a 100644 --- a/plugin/api/init.go +++ b/plugin/api/init.go @@ -2,7 +2,7 @@ package api import ( "infini.sh/console/config" - m "infini.sh/console/internal/middleware" + m "infini.sh/framework/core/security/rbac/middleware" "infini.sh/console/plugin/api/alerting" "infini.sh/console/plugin/api/index_management" "infini.sh/framework/core/api" diff --git a/plugin/api/rbac/api.go b/plugin/api/rbac/api.go deleted file mode 100644 index 4a2e19d6..00000000 --- a/plugin/api/rbac/api.go +++ /dev/null @@ -1,105 +0,0 @@ -package rbac - -import ( - "encoding/json" - "github.com/mitchellh/mapstructure" - "infini.sh/console/internal/biz" - "infini.sh/console/internal/biz/enum" - "infini.sh/console/model/rbac" - "infini.sh/framework/core/api" - "infini.sh/framework/core/elastic" - "infini.sh/framework/core/util" - "os" - "path" - log "github.com/cihub/seelog" -) - -type Rbac struct { - api.Handler -} - -func init() { - - //r := Rbac{} - //api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission) - //api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAllPermission...)) - //api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleReadPermission...)) - //api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAllPermission...)) - //api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.RoleAllPermission...)) - //api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.RoleReadPermission...)) - // - //api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.UserAllPermission...)) - //api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.UserReadPermission...)) - //api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.UserAllPermission...)) - //api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAllPermission...)) - //api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAllPermission...)) - //api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserReadPermission...)) - //api.HandleAPIMethod(api.PUT, "/user/:id/password", m.PermissionRequired(r.UpdateUserPassword, enum.UserAllPermission...)) -} - -func loadJsonConfig() { - pwd, _ := os.Getwd() - - bytes, err := util.FileGetContent(path.Join(pwd, "/config/permission.json")) - if err != nil { - panic("load json file err " + err.Error()) - - } - apis := make(map[string][]string) - err = json.Unmarshal(bytes, &apis) - if err != nil { - panic("json config unmarshal err " + err.Error()) - } - biz.IndexApis = apis["indices"] - delete(apis, "indices") - biz.ClusterApis = apis - - //bytes, err = util.FileGetContent(path.Join(pwd, "/config/map.json")) - //if err != nil { - // panic("load json file err " + err.Error()) - //} - //esapiMap := make(map[string]string) - //err = json.Unmarshal(bytes, &esapiMap) - //if err != nil { - // panic("json config unmarshal err " + err.Error()) - //} - //for k, v := range esapiMap { - // s := strings.Split(k, "-") - // biz.EsApiRoutes.AddRoute(s[0], s[1], v) - //} - -} -func loadRolePermission() { - biz.RoleMap = make(map[string]rbac.Role) - - biz.RoleMap["admin"] = rbac.Role{ - Privilege: rbac.RolePrivilege{ - Platform: enum.AdminPrivilege, - }, - } - - res, err := biz.SearchRole("", 0, 1000) - if err != nil { - log.Error(err) - return - } - response := elastic.SearchResponse{} - util.FromJSONBytes(res.Raw, &response) - - for _, v := range response.Hits.Hits { - var role rbac.Role - delete(v.Source, "created") - delete(v.Source, "updated") - err = mapstructure.Decode(v.Source, &role) - if err != nil { - log.Error(err) - return - } - biz.RoleMap[role.Name] = role - } - -} -func Init() { - loadJsonConfig() - loadRolePermission() -} diff --git a/plugin/api/rbac/permission.go b/plugin/api/rbac/permission.go deleted file mode 100644 index 69f2d00f..00000000 --- a/plugin/api/rbac/permission.go +++ /dev/null @@ -1,24 +0,0 @@ -package rbac - -import ( - log "github.com/cihub/seelog" - "infini.sh/console/internal/biz" - httprouter "infini.sh/framework/core/api/router" - "net/http" -) - -func (h Rbac) ListPermission(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - typ := ps.MustGetParameter("type") - err := biz.IsAllowRoleType(typ) - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - var permissions interface{} - if typ == biz.Elasticsearch { - permissions = biz.ListElasticsearchPermission() - } - h.WriteOKJSON(w, permissions) - return -} diff --git a/plugin/api/rbac/role.go b/plugin/api/rbac/role.go deleted file mode 100644 index eca29b20..00000000 --- a/plugin/api/rbac/role.go +++ /dev/null @@ -1,151 +0,0 @@ -package rbac - -import ( - log "github.com/cihub/seelog" - "infini.sh/console/internal/biz" - "infini.sh/console/internal/biz/enum" - "infini.sh/console/internal/core" - "infini.sh/console/model/rbac" - httprouter "infini.sh/framework/core/api/router" - "infini.sh/framework/core/elastic" - "infini.sh/framework/core/util" - "net/http" -) - -func (h Rbac) CreateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - roleType := ps.MustGetParameter("type") - - localUser, err := biz.FromUserContext(r.Context()) - if err != nil { - log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - err = biz.IsAllowRoleType(roleType) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - role := &rbac.Role{ - Type: roleType, - } - err = h.DecodeJSON(r, role) - if err != nil { - h.Error400(w, err.Error()) - return - } - - var id string - id, err = biz.CreateRole(localUser, role) - - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - _ = h.WriteOKJSON(w, core.CreateResponse(id)) - return - -} - -func (h Rbac) SearchRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - - var ( - keyword = h.GetParameterOrDefault(r, "keyword", "") - from = h.GetIntOrDefault(r, "from", 0) - size = h.GetIntOrDefault(r, "size", 20) - ) - - res, err := biz.SearchRole(keyword, from, size) - if err != nil { - log.Error(err) - h.ErrorInternalServer(w, err.Error()) - return - } - response := elastic.SearchResponse{} - util.FromJSONBytes(res.Raw, &response) - - hits := response.Hits.Hits - list := make([]elastic.IndexDocument, 0) - total := response.GetTotal() - var index string - for _, v := range hits { - index = v.Index - } - for k, v := range enum.BuildRoles { - list = append(list, elastic.IndexDocument{ - ID: k, - Index: index, - Type: "_doc", - Source: v, - }) - total++ - } - list = append(list, hits...) - response.Hits.Hits = list - response.Hits.Total = total - - h.WriteOKJSON(w, response) - return - -} - -func (h Rbac) GetRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - id := ps.MustGetParameter("id") - role, err := biz.GetRole(id) - - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - h.WriteOKJSON(w, core.Response{Hit: role}) - return -} - -func (h Rbac) DeleteRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - id := ps.MustGetParameter("id") - - localUser, err := biz.FromUserContext(r.Context()) - if err != nil { - log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - err = biz.DeleteRole(localUser, id) - - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - _ = h.WriteOKJSON(w, core.DeleteResponse(id)) - return -} - -func (h Rbac) UpdateRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - id := ps.MustGetParameter("id") - //localUser, err := biz.FromUserContext(r.Context()) - //if err != nil { - // log.Error(err.Error()) - // h.ErrorInternalServer(w, err.Error()) - // return - //} - role := &rbac.Role{} - err := h.DecodeJSON(r, role) - if err != nil { - h.Error400(w, err.Error()) - return - } - role.ID = id - err = biz.UpdateRole(role) - biz.RoleMap[role.Name] = *role - - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - _ = h.WriteOKJSON(w, core.UpdateResponse(id)) - return -} diff --git a/plugin/api/rbac/user.go b/plugin/api/rbac/user.go deleted file mode 100644 index b940db12..00000000 --- a/plugin/api/rbac/user.go +++ /dev/null @@ -1,192 +0,0 @@ -package rbac - -import ( - "errors" - "infini.sh/console/internal/biz" - "infini.sh/console/internal/core" - "infini.sh/console/internal/dto" - httprouter "infini.sh/framework/core/api/router" - "infini.sh/framework/core/util" - "infini.sh/framework/modules/elastic" - "net/http" - log "src/github.com/cihub/seelog" -) - -type CreateUserReq struct { - Username string `json:"username" ` - Password string `json:"password" ` - Name string `json:"name" ` - Phone string `json:"phone" ` - Email string `json:"email" ` - Tags []string `json:"tags"` -} - -func (h Rbac) CreateUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - - var req dto.CreateUser - err := h.DecodeJSON(r, &req) - if err != nil { - h.Error400(w, err.Error()) - return - } - if req.Name == "" { - - h.Error400(w, "username and phone and email is require") - return - } - localUser, err := biz.FromUserContext(r.Context()) - if err != nil { - log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - id, pass, err := biz.CreateUser(localUser, req) - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - _ = h.WriteOKJSON(w, util.MapStr{ - "_id": id, - "password": pass, - "result": "created", - }) - return - -} - -func (h Rbac) GetUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - id := ps.MustGetParameter("id") - user, err := biz.GetUser(id) - if errors.Is(err, elastic.ErrNotFound) { - h.WriteJSON(w, core.NotFoundResponse(id), http.StatusNotFound) - return - } - - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - h.WriteOKJSON(w, core.FoundResponse(id, user)) - return -} - -func (h Rbac) UpdateUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - id := ps.MustGetParameter("id") - var req dto.UpdateUser - err := h.DecodeJSON(r, &req) - if err != nil { - _ = log.Error(err.Error()) - h.Error400(w, err.Error()) - return - } - localUser, err := biz.FromUserContext(r.Context()) - if err != nil { - log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - err = biz.UpdateUser(localUser, id, req) - - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - _ = h.WriteOKJSON(w, core.UpdateResponse(id)) - return -} - -func (h Rbac) UpdateUserRole(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - id := ps.MustGetParameter("id") - var req dto.UpdateUserRole - err := h.DecodeJSON(r, &req) - if err != nil { - _ = log.Error(err.Error()) - h.Error400(w, err.Error()) - return - } - localUser, err := biz.FromUserContext(r.Context()) - if err != nil { - log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - err = biz.UpdateUserRole(localUser, id, req) - - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - _ = h.WriteOKJSON(w, core.UpdateResponse(id)) - return -} - -func (h Rbac) DeleteUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - id := ps.MustGetParameter("id") - localUser, err := biz.FromUserContext(r.Context()) - if err != nil { - log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - err = biz.DeleteUser(localUser, id) - if errors.Is(err, elastic.ErrNotFound) { - h.WriteJSON(w, core.NotFoundResponse(id), http.StatusNotFound) - return - } - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - _ = h.WriteOKJSON(w, core.DeleteResponse(id)) - return -} - -func (h Rbac) SearchUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - var ( - keyword = h.GetParameterOrDefault(r, "keyword", "") - from = h.GetIntOrDefault(r, "from", 0) - size = h.GetIntOrDefault(r, "size", 20) - ) - - res, err := biz.SearchUser(keyword, from, size) - if err != nil { - log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - - h.Write(w, res.Raw) - return - -} -func (h Rbac) UpdateUserPassword(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - id := ps.MustGetParameter("id") - var req dto.UpdateUserPassword - err := h.DecodeJSON(r, &req) - if err != nil { - _ = log.Error(err.Error()) - h.Error400(w, err.Error()) - return - } - localUser, err := biz.FromUserContext(r.Context()) - if err != nil { - log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - err = biz.UpdateUserPassword(localUser, id, req.Password) - if err != nil { - _ = log.Error(err.Error()) - h.ErrorInternalServer(w, err.Error()) - return - } - - _ = h.WriteOKJSON(w, core.UpdateResponse(id)) - return - -} From 075be76bcc79ff8f5b52566e69ca47e97e5658bb Mon Sep 17 00:00:00 2001 From: liugq Date: Mon, 9 May 2022 21:02:47 +0800 Subject: [PATCH 73/75] remove account api --- plugin/api/account/account.go | 175 ---------------------------------- 1 file changed, 175 deletions(-) delete mode 100644 plugin/api/account/account.go diff --git a/plugin/api/account/account.go b/plugin/api/account/account.go deleted file mode 100644 index 35c258f7..00000000 --- a/plugin/api/account/account.go +++ /dev/null @@ -1,175 +0,0 @@ -package account - -import ( - "infini.sh/console/internal/biz" - "infini.sh/console/internal/core" - "infini.sh/console/internal/dto" - "infini.sh/framework/core/api" - "infini.sh/framework/core/api/router" - "infini.sh/framework/core/util" - "net/http" -) - -type Account struct { - api.Handler -} - -func init() { - //account := Account{} - //api.HandleAPIMethod(api.POST, "/account/login", account.Login) - // - //api.HandleAPIMethod(api.GET, "/account/current_user", account.CurrentUser) - // - //api.HandleAPIMethod(api.DELETE, "/account/logout", account.Logout) - //api.HandleAPIMethod(api.GET, "/account/profile", m.LoginRequired(account.Profile)) - //api.HandleAPIMethod(api.PUT, "/account/password", m.LoginRequired(account.UpdatePassword)) -} - -const userInSession = "user_session:" - -func (h Account) Login(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - - var req dto.Login - err := h.DecodeJSON(r, &req) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - - data, err := biz.Login(req.Username, req.Password) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - data["status"] = "ok" - - //api.SetSession(w, r, userInSession+req.Username, req.Username) - h.WriteOKJSON(w, data) -} - -func (h Account) CurrentUser(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { - - exists, user := api.GetSession(w, req, userInSession) - if exists { - data := util.MapStr{ - "name": user, - "avatar": "", - "userid": "10001", - "email": "hello@infini.ltd", - "signature": "极限科技 - 专业的开源搜索与实时数据分析整体解决方案提供商。", - "title": "首席设计师", - "group": "INFINI Labs", - "tags": []util.MapStr{ - { - "key": "0", - "label": "很有想法的", - }}, - "notifyCount": 12, - "country": "China", - "geographic": util.MapStr{ - "province": util.MapStr{ - "label": "湖南省", - "key": "330000", - }, - "city": util.MapStr{ - "label": "长沙市", - "key": "330100", - }, - }, - "address": "岳麓区湘江金融中心", - "phone": "4001399200", - } - - h.WriteJSON(w, data, 200) - } else { - data := util.MapStr{ - "status": "error", - "type": "account", - "currentAuthority": "guest", - } - h.WriteJSON(w, data, 403) - } -} -func (h Account) Logout(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - reqUser, err := biz.FromUserContext(r.Context()) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - - delete(biz.TokenMap, reqUser.UserId) - h.WriteOKJSON(w, util.MapStr{ - "status": "ok", - }) -} -func (h Account) Profile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - reqUser, err := biz.FromUserContext(r.Context()) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - - if reqUser.UserId == "admin" { - - u := util.MapStr{ - "user_id": "admin", - "name": "admin", - "email": "admin@infini.ltd", - "nick_name": "admin", - "phone": "13011111111", - } - h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) - } else { - user, err := biz.GetUser(reqUser.UserId) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - u := util.MapStr{ - "user_id": user.ID, - "name": user.Name, - "email": user.Email, - "nick_name": user.NickName, - "phone": user.Phone, - } - h.WriteOKJSON(w, core.FoundResponse(reqUser.UserId, u)) - } - - return -} -func (h Account) UpdatePassword(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - reqUser, err := biz.FromUserContext(r.Context()) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - var req dto.UpdatePassword - err = h.DecodeJSON(r, &req) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - err = biz.UpdatePassword(reqUser, req) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - h.WriteOKJSON(w, core.UpdateResponse(reqUser.UserId)) - return -} -func (h Account) UpdateProfile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - reqUser, err := biz.FromUserContext(r.Context()) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - var req dto.UpdateProfile - err = h.DecodeJSON(r, &req) - err = biz.UpdateProfile(reqUser, req) - if err != nil { - h.ErrorInternalServer(w, err.Error()) - return - } - h.WriteOKJSON(w, core.UpdateResponse(reqUser.UserId)) - return -} From 16228bda79c30257c2ed9c04d1783435862d8ca2 Mon Sep 17 00:00:00 2001 From: medcl Date: Wed, 11 May 2022 16:10:15 +0800 Subject: [PATCH 74/75] refactoring security --- console.yml | 2 ++ main.go | 20 +------------------- plugin/api/init.go | 24 +++++++++++++----------- 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/console.yml b/console.yml index c0fe998d..fe56d1bc 100644 --- a/console.yml +++ b/console.yml @@ -12,6 +12,8 @@ elasticsearch: web: enabled: true embedding_api: true +# auth: +# enabled: true ui: enabled: true path: .public diff --git a/main.go b/main.go index 7a773a18..cb158c3d 100644 --- a/main.go +++ b/main.go @@ -22,7 +22,6 @@ import ( "infini.sh/framework/modules/pipeline" queue2 "infini.sh/framework/modules/queue/disk_queue" "infini.sh/framework/modules/redis" - "infini.sh/framework/modules/security" "infini.sh/framework/modules/stats" "infini.sh/framework/modules/task" "infini.sh/framework/modules/ui" @@ -76,7 +75,7 @@ func main() { module.RegisterSystemModule(&task.TaskModule{}) module.RegisterUserPlugin(&metrics.MetricsModule{}) - module.RegisterUserPlugin(&security.SecurityModule{}) + api.RegisterAPI("") appConfig = &config.AppConfig{ @@ -100,22 +99,6 @@ func main() { appUI = &UI{Config: appConfig} appUI.InitUI() - //uiConfig := ui.UIConfig{} - //env.ParseConfig("web", &uiConfig) - // - //if len(global.Env().SystemConfig.APIConfig.CrossDomain.AllowedOrigins)==0{ - // global.Env().SystemConfig.APIConfig.CrossDomain.AllowedOrigins= - // append(global.Env().SystemConfig.APIConfig.CrossDomain.AllowedOrigins,uiConfig.NetworkConfig.GetBindingAddr()) - //} - //apiConfig := global.Env().SystemConfig.APIConfig - //if len(apiConfig.CrossDomain.AllowedOrigins) == 0 { - // apiConfig.CrossDomain.AllowedOrigins = []string{ - // fmt.Sprintf("%s://%s", appConfig.GetSchema(), appConfig.Network.GetPublishAddr()), - // } - //} - - //start each module, with enabled provider - }, func() { module.Start() @@ -137,7 +120,6 @@ func main() { log.Errorf("init alerting task error: %v", err) } }() - //go rbacApi.Init() }, nil) { app.Run() diff --git a/plugin/api/init.go b/plugin/api/init.go index e7fa2f9a..fdb60167 100644 --- a/plugin/api/init.go +++ b/plugin/api/init.go @@ -2,7 +2,6 @@ package api import ( "infini.sh/console/config" - m "infini.sh/framework/core/security/rbac/middleware" "infini.sh/console/plugin/api/alerting" "infini.sh/console/plugin/api/index_management" "infini.sh/framework/core/api" @@ -25,27 +24,28 @@ func Init(cfg *config.AppConfig) { api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "dict/:id"), handler.DeleteDictItemAction) api.HandleAPIMethod(api.PUT, path.Join(pathPrefix, "dict/:id"), handler.UpdateDictItemAction) - api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index/_search"), m.IndexRequired(handler.HandleSearchDocumentAction, "doc.search")) - api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index"), m.IndexRequired(handler.HandleAddDocumentAction, "doc.create")) - api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "doc/:index/:docId"), m.IndexRequired(handler.HandleUpdateDocumentAction, "doc.update")) - api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "doc/:index/:docId"), m.IndexRequired(handler.HandleDeleteDocumentAction, "doc.delete")) + api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index/_search"), handler.IndexRequired(handler.HandleSearchDocumentAction, "doc.search")) + api.HandleAPIMethod(api.POST, path.Join(esPrefix, "doc/:index"), handler.IndexRequired(handler.HandleAddDocumentAction, "doc.create")) + api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "doc/:index/:docId"), handler.IndexRequired(handler.HandleUpdateDocumentAction, "doc.update")) + api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "doc/:index/:docId"), handler.IndexRequired(handler.HandleDeleteDocumentAction, "doc.delete")) api.HandleAPIMethod(api.GET, path.Join(esPrefix, "doc/_validate"), handler.ValidateDocIDAction) api.HandleAPIMethod(api.POST, path.Join(pathPrefix, "rebuild/*id"), handler.HandleReindexAction) api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "rebuild/_search"), handler.HandleGetRebuildListAction) api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "rebuild/:id"), handler.HandleDeleteRebuildAction) - api.HandleAPIMethod(api.GET, path.Join(esPrefix, "_cat/indices"), m.ClusterRequired(handler.HandleGetIndicesAction, "cat.indices")) - api.HandleAPIMethod(api.GET, path.Join(esPrefix, "index/:index/_mappings"), m.IndexRequired(handler.HandleGetMappingsAction, "indices.get_mapping")) - api.HandleAPIMethod(api.GET, path.Join(esPrefix, "index/:index/_settings"), m.IndexRequired(handler.HandleGetSettingsAction, "indices.get_settings")) - api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "index/:index/_settings"), m.IndexRequired(handler.HandleUpdateSettingsAction, "indices.put_mapping")) - api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "index/:index"), m.IndexRequired(handler.HandleDeleteIndexAction, "indices.delete")) - api.HandleAPIMethod(api.POST, path.Join(esPrefix, "index/:index"), m.IndexRequired(handler.HandleCreateIndexAction, "indices.create")) + api.HandleAPIMethod(api.GET, path.Join(esPrefix, "_cat/indices"), handler.ClusterRequired(handler.HandleGetIndicesAction, "cat.indices")) + api.HandleAPIMethod(api.GET, path.Join(esPrefix, "index/:index/_mappings"), handler.IndexRequired(handler.HandleGetMappingsAction, "indices.get_mapping")) + api.HandleAPIMethod(api.GET, path.Join(esPrefix, "index/:index/_settings"), handler.IndexRequired(handler.HandleGetSettingsAction, "indices.get_settings")) + api.HandleAPIMethod(api.PUT, path.Join(esPrefix, "index/:index/_settings"), handler.IndexRequired(handler.HandleUpdateSettingsAction, "indices.put_mapping")) + api.HandleAPIMethod(api.DELETE, path.Join(esPrefix, "index/:index"), handler.IndexRequired(handler.HandleDeleteIndexAction, "indices.delete")) + api.HandleAPIMethod(api.POST, path.Join(esPrefix, "index/:index"), handler.IndexRequired(handler.HandleCreateIndexAction, "indices.create")) api.HandleAPIMethod(api.POST, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleAddCommonCommandAction) api.HandleAPIMethod(api.PUT, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleSaveCommonCommandAction) api.HandleAPIMethod(api.GET, path.Join(pathPrefix, "elasticsearch/command"), handler.HandleQueryCommonCommandAction) api.HandleAPIMethod(api.DELETE, path.Join(pathPrefix, "elasticsearch/command/:cid"), handler.HandleDeleteCommonCommandAction) + //task.RegisterScheduleTask(task.ScheduleTask{ // Description: "sync reindex task result", // Task: func() { @@ -55,9 +55,11 @@ func Init(cfg *config.AppConfig) { // } // }, //}) + alertAPI := alerting.AlertAPI{ Config: cfg, } + alertAPI.Init() } From 56ff72b38d004a1a56a23b62d6e88952e67a379a Mon Sep 17 00:00:00 2001 From: medcl Date: Wed, 11 May 2022 16:19:41 +0800 Subject: [PATCH 75/75] update default config --- console.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console.yml b/console.yml index fe56d1bc..e85401df 100644 --- a/console.yml +++ b/console.yml @@ -12,8 +12,8 @@ elasticsearch: web: enabled: true embedding_api: true -# auth: -# enabled: true + auth: + enabled: true ui: enabled: true path: .public