server/service/rbac/decision.go (116 lines of code) (raw):

/* * 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 ( "context" "fmt" "github.com/apache/servicecomb-service-center/datasource/rbac" "github.com/apache/servicecomb-service-center/pkg/log" "github.com/apache/servicecomb-service-center/server/plugin/auth" rbacmodel "github.com/go-chassis/cari/rbac" ) // Allow return: matched labels(empty if no label defined), error func Allow(ctx context.Context, _ string, roleList []string, targetResource *auth.ResourceScope) ([]map[string]string, error) { //TODO check project allPerms, err := getPermsByRoles(ctx, roleList) if err != nil { log.Error("get role list errors", err) return nil, err } if len(allPerms) == 0 { log.Warn("role list has no any permissions") return nil, rbacmodel.NewError(rbacmodel.ErrNoPermission, "role has no any permissions") } allow, labelList := GetLabel(allPerms, targetResource.Type, targetResource.Verb) if !allow { return nil, rbacmodel.NewError(rbacmodel.ErrNoPermission, fmt.Sprintf("role has no permissions[%s:%s]", targetResource.Type, targetResource.Verb)) } // allow, but no label found, means we can ignore the labels if len(labelList) == 0 { return nil, nil } // target resource needs no label, return without filter if len(targetResource.Labels) == 0 { return labelList, nil } // allow, and labels found, filter the labels filteredLabelList := FilterLabel(targetResource.Labels, labelList) // target resource label matches no label in permission, means not allow if len(filteredLabelList) == 0 { return nil, rbacmodel.NewError(rbacmodel.ErrNoPermission, fmt.Sprintf("role has no permissions[%s:%s] for labels %v", targetResource.Type, targetResource.Verb, targetResource.Labels)) } return filteredLabelList, nil } func FilterLabel(targetResourceLabel []map[string]string, permLabelList []map[string]string) []map[string]string { l := make([]map[string]string, 0) for _, resourceLabel := range targetResourceLabel { for _, label := range permLabelList { if LabelMatched(resourceLabel, label) { l = append(l, label) } } } return l } func LabelMatched(targetResourceLabel map[string]string, permLabel map[string]string) bool { for k, v := range permLabel { if vv := targetResourceLabel[k]; vv != v { return false } } return true } func getPermsByRoles(ctx context.Context, roleList []string) ([]*rbacmodel.Permission, error) { var allPerms = make([]*rbacmodel.Permission, 0) for _, name := range roleList { r, err := rbac.Instance().GetRole(ctx, name) if err == nil { allPerms = append(allPerms, r.Perms...) continue } if err == rbac.ErrRoleNotExist { log.Warn(fmt.Sprintf("role [%s] not exist", name)) continue } log.Error(fmt.Sprintf("get role [%s] failed", name), err) return nil, err } return allPerms, nil } // GetLabel checks if the perms have permission to operate the resource(ignore label), // if one perm have the permission, add it's label to the result. func GetLabel(perms []*rbacmodel.Permission, targetResource, verb string) (allow bool, labelList []map[string]string) { for _, perm := range perms { a, l := GetLabelFromSinglePerm(perm, targetResource, verb) if !a { continue } allow = true // allow and has no label, return fast if len(l) == 0 { return true, nil } labelList = append(labelList, l...) } return } // GetLabel checks if the perm have permission to operate the resource(ignore label), // if the perm have the permission, return it's label. func GetLabelFromSinglePerm(perm *rbacmodel.Permission, targetResource, verb string) (allow bool, labelList []map[string]string) { if !allowVerb(perm.Verbs, verb) { return false, nil } return getResourceLabel(perm.Resources, targetResource) } func allowVerb(haystack []string, needle string) bool { for _, e := range haystack { if e == "*" || e == needle { return true } } return false } func getResourceLabel(resources []*rbacmodel.Resource, needle string) (allow bool, labelList []map[string]string) { for _, resource := range resources { // filter the same resource if resource.Type != needle { continue } // has no label, return fast if len(resource.Labels) == 0 { return true, nil } labelList = append(labelList, resource.Labels) allow = true } return }