tianxiaoliang commented on a change in pull request #736:
URL: 
https://github.com/apache/servicecomb-service-center/pull/736#discussion_r525977030



##########
File path: pkg/rbacframe/role.go
##########
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rbacframe
+
+type RoleResponse struct {
+       Roles []*Role `json:"data,omitempty"`
+}
+
+type Role struct {
+       ID          string        `json:"id,omitempty"`
+       Name        string        `json:"name,omitempty"`
+       Permissions []*Permission `json:"permissions,omitempty"`
+}
+
+type Permission struct {
+       Resources []string

Review comment:
       这里没有进行tag定义

##########
File path: pkg/rbacframe/role.go
##########
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rbacframe
+
+type RoleResponse struct {
+       Roles []*Role `json:"data,omitempty"`
+}
+
+type Role struct {
+       ID          string        `json:"id,omitempty"`
+       Name        string        `json:"name,omitempty"`
+       Permissions []*Permission `json:"permissions,omitempty"`

Review comment:
       简化为perms

##########
File path: datasource/etcd/role.go
##########
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package etcd
+
+import (
+       "context"
+       "encoding/json"
+       "fmt"
+       "github.com/apache/servicecomb-service-center/datasource"
+       "github.com/apache/servicecomb-service-center/datasource/etcd/client"
+       "github.com/apache/servicecomb-service-center/datasource/etcd/kv"
+       "github.com/apache/servicecomb-service-center/pkg/etcdsync"
+       "github.com/apache/servicecomb-service-center/pkg/log"
+       "github.com/apache/servicecomb-service-center/pkg/rbacframe"
+       "github.com/apache/servicecomb-service-center/pkg/util"
+       "github.com/apache/servicecomb-service-center/server/core"
+)
+
+func (ds *DataSource) CreateRole(ctx context.Context, r *rbacframe.Role) error 
{
+       lock, err := etcdsync.Lock("/role-creating/"+r.Name, -1, false)
+       if err != nil {
+               return fmt.Errorf("role %s is creating", r.Name)
+       }
+       defer func() {
+               err := lock.Unlock()
+               if err != nil {
+                       log.Errorf(err, "can not release role lock")
+               }
+       }()
+       key := core.GenerateRoleKey(r.Name)
+       exist, err := datasource.Instance().RoleExist(ctx, r.Name)
+       if err != nil {
+               log.Errorf(err, "can not save role info")
+               return err
+       }
+       if exist {
+               return datasource.ErrRoleDuplicated
+       }
+       r.ID = util.GenerateUUID()
+       value, err := json.Marshal(r)
+       if err != nil {
+               log.Errorf(err, "role info is invalid")
+               return err
+       }
+       err = client.PutBytes(ctx, key, value)
+       if err != nil {
+               log.Errorf(err, "can not save account info")
+               return err
+       }
+       log.Info("create new role: " + r.ID)
+       return nil
+}
+
+func (ds *DataSource) RoleExist(ctx context.Context, key string) (bool, error) 
{
+       resp, err := client.Instance().Do(ctx, client.GET,
+               client.WithStrKey(kv.GenerateETCDRoleKey(key)))
+       if err != nil {
+               return false, err
+       }
+       if resp.Count == 0 {
+               return false, nil
+       }
+       return true, nil
+}
+func (ds *DataSource) GetRole(ctx context.Context, key string) 
(*rbacframe.Role, error) {
+       resp, err := client.Instance().Do(ctx, client.GET,
+               client.WithStrKey(kv.GenerateETCDRoleKey(key)))
+       if err != nil {
+               return nil, err
+       }
+       if resp.Count != 1 {
+               return nil, client.ErrNotUnique
+       }
+       role := &rbacframe.Role{}
+       err = json.Unmarshal(resp.Kvs[0].Value, role)
+       if err != nil {
+               log.Errorf(err, "role info format invalid")
+               return nil, err
+       }
+       return role, nil
+}
+func (ds *DataSource) ListRole(ctx context.Context, key string) 
([]*rbacframe.Role, int64, error) {
+       resp, err := client.Instance().Do(ctx, client.GET,
+               client.WithStrKey(kv.GenerateETCDRoleKey(key)), 
client.WithPrefix())

Review comment:
       拿到role列表为何需要一个role的名字

##########
File path: datasource/role.go
##########
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package datasource
+
+import (
+       "context"
+       "errors"
+       "github.com/apache/servicecomb-service-center/pkg/rbacframe"
+)
+
+var (
+       ErrRoleDuplicated = errors.New("role is duplicated")
+       ErrRoleCanNotEdit = errors.New("role can not be edited")
+)
+
+// RoleManager contains the RBAC CRUD
+type RoleManager interface {
+       CreateRole(ctx context.Context, r *rbacframe.Role) error
+       RoleExist(ctx context.Context, key string) (bool, error)
+       GetRole(ctx context.Context, key string) (*rbacframe.Role, error)
+       ListRole(ctx context.Context, key string) ([]*rbacframe.Role, int64, 
error)

Review comment:
       list不需要name作为入参

##########
File path: docs/user-guides/rbac.md
##########
@@ -85,6 +85,74 @@ curl -X POST \
 }'
 ```
 ### Roles 
-currently, you can not custom and manage any role and role policy. there is 
only 2 build in roles. rbac feature is in early development stage.
+currently, two default roles are provided. rbac feature is in early 
development stage.
 - admin: able to do anything, including manage account, even change other 
account password
 - developer: able to call most of API except account management. except 
account management
+You can also create new role and allocate resources to new role.
+
+### API and resources
+All APIs of the system are divided according to their attributes. For example, 
resource account has the permission to create or update or delete user account 
when assign the corresponding permissions, resource service has all permission 
to create, get, add or delete microservices when permissions equal to "*". For 
more details to see 
[https://github.com/apache/servicecomb-service-center/blob/master/server/service/rbac/resource.go]()
+           
+ ```json
+{
+ "name": "tester",
+ "permissions": [
+         { 
+            "resources": ["service","instance"],
+            "verbs":    ["get", "create", "update"]
+         },
+         { 
+             "resources": ["rule"],
+             "verbs":     ["get"]
+         }
+    ]
+}
+```
+
+### create new role 
+you can add new role for user.
+```shell script
+curl -X POST \
+  http://127.0.0.1:30100/v4/account \
+  -H 'Accept: */*' \
+  -H 'Authorization: Bearer {your_token}' \
+  -H 'Content-Type: application/json' \
+  -d '{
+       "name":"dev_test",
+       "password":"{strong_password}",
+       "role":"tester"

Review comment:
       这个多role还没支持

##########
File path: pkg/rbacframe/resource_dao.go
##########
@@ -35,3 +35,12 @@ func GetResource(api string) string {
 func MapResource(api, resource string) {
        resourceMap[api] = resource
 }
+
+//AddResourceType join the resource to an array
+func AddResourceType(resourceType ...string) []string {

Review comment:
       没看到rt用在哪了

##########
File path: datasource/role.go
##########
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package datasource
+
+import (
+       "context"
+       "errors"
+       "github.com/apache/servicecomb-service-center/pkg/rbacframe"
+)
+
+var (
+       ErrRoleDuplicated = errors.New("role is duplicated")
+       ErrRoleCanNotEdit = errors.New("role can not be edited")
+)
+
+// RoleManager contains the RBAC CRUD
+type RoleManager interface {
+       CreateRole(ctx context.Context, r *rbacframe.Role) error
+       RoleExist(ctx context.Context, key string) (bool, error)

Review comment:
       input就别叫key了,改成name

##########
File path: server/service/rbac/decision.go
##########
@@ -19,26 +19,53 @@ package rbac
 
 import (
        "context"
+       "github.com/apache/servicecomb-service-center/datasource"
        "github.com/apache/servicecomb-service-center/pkg/log"
-       "github.com/apache/servicecomb-service-center/server/service/rbac/dao"
 )
 
 func Allow(ctx context.Context, role, project, resource, verbs string) (bool, 
error) {
-       r := dao.GetRole(ctx, role)
+       r, err := datasource.Instance().GetRole(ctx, role)
+       if err != nil {
+               log.Error("get role list errors", err)
+               return false, err
+       }
        if r == nil {
                log.Warn("empty role info")
                return false, nil
        }
+       //TODO check project
+
        ps := r.Permissions
        if len(ps) == 0 {
                log.Warn("role has no any permissions")
                return false, nil
        }
-       p, ok := ps[resource]
-       if !ok || p == nil {
-               log.Warn("role is not allowed to access resource")
-               return false, nil
+
+       for i := 0; i < len(ps); i++ {
+               pr := ps[i].Resources
+               contains := inStrSlice(pr, resource)
+               if contains {
+                       return allowVerbs(ps[i].Verbs, verbs), nil
+               }
+       }
+
+       log.Warn("role is not allowed to operate resource")
+       return false, nil
+}
+
+func inStrSlice(haystack []string, needle string) bool {

Review comment:
       inStrSlice方法名起的不够易懂,应该是ableToAccessResource

##########
File path: server/service/rbac/permission.go
##########
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rbac
+
+import "github.com/apache/servicecomb-service-center/pkg/rbacframe"
+
+// method to verbs
+var (
+       MethodToVerbs = map[string]string{
+               "GET":    "get",
+               "POST":   "create",
+               "UPDATE": "update",
+               "DELETE": "delete",
+       }
+)
+
+// AdminPerms allocate all resource permissions
+func AdminPerms() []*rbacframe.Permission {
+       resources := rbacframe.AddResourceType(ResourceAccount, ResourceRole, 
ResourceService, ResourceInstance,
+               ResourceDep, ResourceTag, ResourceRule, ResourceGovern, 
ResourceAdminister, ResourceSchema)
+       perm := []*rbacframe.Permission{
+               {
+                       Resources: resources,
+                       Verbs:     []string{"*"},
+               },
+       }
+       return perm
+}
+
+// DevPerms allocate all resource permissions except account and role resources
+func DevPerms() []*rbacframe.Permission {
+       resources := rbacframe.AddResourceType(ResourceService, 
ResourceInstance,

Review comment:
       我明白了AddResourceType是什么,你不如叫buildResourceList

##########
File path: server/service/rbac/decision.go
##########
@@ -19,26 +19,53 @@ package rbac
 
 import (
        "context"
+       "github.com/apache/servicecomb-service-center/datasource"
        "github.com/apache/servicecomb-service-center/pkg/log"
-       "github.com/apache/servicecomb-service-center/server/service/rbac/dao"
 )
 
 func Allow(ctx context.Context, role, project, resource, verbs string) (bool, 
error) {
-       r := dao.GetRole(ctx, role)
+       r, err := datasource.Instance().GetRole(ctx, role)
+       if err != nil {
+               log.Error("get role list errors", err)
+               return false, err
+       }
        if r == nil {
                log.Warn("empty role info")
                return false, nil
        }
+       //TODO check project
+
        ps := r.Permissions
        if len(ps) == 0 {
                log.Warn("role has no any permissions")
                return false, nil
        }
-       p, ok := ps[resource]
-       if !ok || p == nil {
-               log.Warn("role is not allowed to access resource")
-               return false, nil
+
+       for i := 0; i < len(ps); i++ {
+               pr := ps[i].Resources
+               contains := inStrSlice(pr, resource)
+               if contains {
+                       return allowVerbs(ps[i].Verbs, verbs), nil

Review comment:
       
allowVerbs不要最后返回这个方法的结果,虽然结果正确,但是代码不易读,应该是一个大方法判断resource和verbs,比如叫ableToOperateResource




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to