mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-21 14:19:49 +08:00
改进:model资源支持rbac认证,需要打开enable_rbac选项,默认关闭。非model资源还不支持
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
)
|
||||
|
||||
@@ -39,4 +40,12 @@ func InitAuth(options *Options, authComplete auth.AuthCompletedCallback) {
|
||||
auth.Init(a, false, true, options.SslCertfile, options.SslKeyfile) // , authComplete)
|
||||
|
||||
authComplete()
|
||||
|
||||
if options.GlobalVirtualResourceNamespace {
|
||||
db.EnableGlobalVirtualResourceNamespace()
|
||||
}
|
||||
|
||||
if options.EnableRbac {
|
||||
db.EnableGlobalRbac()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,7 +401,7 @@ func listItems(manager IModelManager, ctx context.Context, userCred mcclient.Tok
|
||||
return nil, err
|
||||
}
|
||||
totalCnt := int64(q.Count())
|
||||
log.Debugf("total count %d", totalCnt)
|
||||
// log.Debugf("total count %d", totalCnt)
|
||||
if totalCnt == 0 {
|
||||
emptyList := modules.ListResult{Data: []jsonutils.JSONObject{}}
|
||||
return &emptyList, nil
|
||||
@@ -457,9 +457,19 @@ func listItems(manager IModelManager, ctx context.Context, userCred mcclient.Tok
|
||||
|
||||
func (dispatcher *DBModelDispatcher) List(ctx context.Context, query jsonutils.JSONObject, ctxId string) (*modules.ListResult, error) {
|
||||
userCred := fetchUserCredential(ctx)
|
||||
if !dispatcher.modelManager.AllowListItems(ctx, userCred, query) {
|
||||
|
||||
var isAllow bool
|
||||
if globalsRbacEnabled {
|
||||
isAdmin := jsonutils.QueryBoolean(query, "admin", false)
|
||||
isAllow = PolicyManager.Allow(isAdmin, userCred, GetGlobalServiceType(),
|
||||
dispatcher.modelManager.KeywordPlural(), PolicyActionList)
|
||||
} else {
|
||||
isAllow = dispatcher.modelManager.AllowListItems(ctx, userCred, query)
|
||||
}
|
||||
if !isAllow {
|
||||
return nil, httperrors.NewForbiddenError("Not allow to list")
|
||||
}
|
||||
|
||||
items, err := listItems(dispatcher.modelManager, ctx, userCred, query, ctxId)
|
||||
if err != nil {
|
||||
log.Errorf("Fail to list items: %s", err)
|
||||
@@ -541,6 +551,37 @@ func (dispatcher *DBModelDispatcher) tryGetModelProperty(ctx context.Context, pr
|
||||
}
|
||||
}
|
||||
|
||||
func isRbacAllowed(manager IModelManager, model IModel, userCred mcclient.TokenCredential, action string, extra ...string) bool {
|
||||
var isAllow bool
|
||||
var isAdmin bool
|
||||
if model == nil {
|
||||
_, ok := manager.(IVirtualModelManager)
|
||||
if ok {
|
||||
isAdmin = false
|
||||
}
|
||||
} else {
|
||||
virtModel, ok := model.(IVirtualModel)
|
||||
if ok {
|
||||
if virtModel.IsOwner(userCred) {
|
||||
isAdmin = false
|
||||
} else {
|
||||
isAdmin = true
|
||||
}
|
||||
} else {
|
||||
isAdmin = true
|
||||
}
|
||||
}
|
||||
if !isAdmin {
|
||||
isAllow = PolicyManager.Allow(false, userCred, GetGlobalServiceType(),
|
||||
manager.KeywordPlural(), action, extra...)
|
||||
}
|
||||
if !isAllow {
|
||||
isAllow = PolicyManager.Allow(true, userCred, GetGlobalServiceType(),
|
||||
manager.KeywordPlural(), action, extra...)
|
||||
}
|
||||
return isAllow
|
||||
}
|
||||
|
||||
func (dispatcher *DBModelDispatcher) Get(ctx context.Context, idStr string, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
// log.Debugf("Get %s", idStr)
|
||||
userCred := fetchUserCredential(ctx)
|
||||
@@ -560,7 +601,13 @@ func (dispatcher *DBModelDispatcher) Get(ctx context.Context, idStr string, quer
|
||||
return nil, err
|
||||
}
|
||||
// log.Debugf("Get found %s", model)
|
||||
if !model.AllowGetDetails(ctx, userCred, query) {
|
||||
var isAllow bool
|
||||
if globalsRbacEnabled {
|
||||
isAllow = isRbacAllowed(dispatcher.modelManager, model, userCred, PolicyActionGet)
|
||||
} else {
|
||||
isAllow = model.AllowGetDetails(ctx, userCred, query)
|
||||
}
|
||||
if !isAllow {
|
||||
return nil, httperrors.NewForbiddenError("Not allow to get details")
|
||||
}
|
||||
return getItemDetails(dispatcher.modelManager, model, ctx, userCred, query)
|
||||
@@ -576,35 +623,44 @@ func (dispatcher *DBModelDispatcher) GetSpecific(ctx context.Context, idStr stri
|
||||
return nil, err
|
||||
}
|
||||
|
||||
specCamel := utils.Kebab2Camel(spec, "-")
|
||||
funcName := fmt.Sprintf("AllowGetDetails%s", specCamel)
|
||||
modelValue := reflect.ValueOf(model)
|
||||
funcValue := modelValue.MethodByName(funcName)
|
||||
if !funcValue.IsValid() || funcValue.IsNil() {
|
||||
return nil, httperrors.NewSpecNotFoundError(fmt.Sprintf("%s %s %s not found", dispatcher.Keyword(), idStr, spec))
|
||||
}
|
||||
|
||||
params := []reflect.Value{
|
||||
reflect.ValueOf(ctx),
|
||||
reflect.ValueOf(userCred),
|
||||
reflect.ValueOf(query),
|
||||
}
|
||||
|
||||
outs := funcValue.Call(params)
|
||||
if len(outs) != 1 {
|
||||
return nil, httperrors.NewInternalServerError("Invald %s return value", funcName)
|
||||
specCamel := utils.Kebab2Camel(spec, "-")
|
||||
modelValue := reflect.ValueOf(model)
|
||||
|
||||
var isAllow bool
|
||||
if globalsRbacEnabled {
|
||||
isAllow = isRbacAllowed(dispatcher.modelManager, model, userCred, PolicyActionGet, spec)
|
||||
} else {
|
||||
funcName := fmt.Sprintf("AllowGetDetails%s", specCamel)
|
||||
|
||||
funcValue := modelValue.MethodByName(funcName)
|
||||
if !funcValue.IsValid() || funcValue.IsNil() {
|
||||
return nil, httperrors.NewSpecNotFoundError(fmt.Sprintf("%s %s %s not found", dispatcher.Keyword(), idStr, spec))
|
||||
}
|
||||
|
||||
outs := funcValue.Call(params)
|
||||
if len(outs) != 1 {
|
||||
return nil, httperrors.NewInternalServerError("Invald %s return value", funcName)
|
||||
}
|
||||
isAllow = outs[0].Bool()
|
||||
}
|
||||
if !outs[0].Bool() {
|
||||
|
||||
if !isAllow {
|
||||
return nil, httperrors.NewForbiddenError(fmt.Sprintf("%s not allow to get spec %s", dispatcher.Keyword(), spec))
|
||||
}
|
||||
|
||||
funcName = fmt.Sprintf("GetDetails%s", specCamel)
|
||||
funcValue = modelValue.MethodByName(funcName)
|
||||
funcName := fmt.Sprintf("GetDetails%s", specCamel)
|
||||
funcValue := modelValue.MethodByName(funcName)
|
||||
if !funcValue.IsValid() || funcValue.IsNil() {
|
||||
return nil, httperrors.NewSpecNotFoundError(fmt.Sprintf("%s %s %s not found", dispatcher.Keyword(), idStr, spec))
|
||||
}
|
||||
|
||||
outs = funcValue.Call(params)
|
||||
outs := funcValue.Call(params)
|
||||
if len(outs) != 2 {
|
||||
return nil, httperrors.NewInternalServerError("Invald %s return value", funcName)
|
||||
}
|
||||
@@ -633,7 +689,13 @@ func fetchOwnerProjectId(ctx context.Context, userCred mcclient.TokenCredential,
|
||||
if len(projId) == 0 {
|
||||
return userCred.GetProjectId(), nil
|
||||
}
|
||||
if !userCred.IsSystemAdmin() {
|
||||
var isAllow bool
|
||||
if globalsRbacEnabled {
|
||||
isAllow = PolicyManager.Allow(true, userCred, GetGlobalServiceType(), PolicyDelegation, "")
|
||||
} else {
|
||||
isAllow = userCred.IsSystemAdmin()
|
||||
}
|
||||
if !isAllow {
|
||||
return "", httperrors.NewForbiddenError("Delegation not allowed")
|
||||
}
|
||||
t, _ := TenantCacheManager.FetchTenantByIdOrName(ctx, projId)
|
||||
@@ -748,7 +810,13 @@ func (dispatcher *DBModelDispatcher) Create(ctx context.Context, query jsonutils
|
||||
lockman.LockClass(ctx, dispatcher.modelManager, ownerProjId)
|
||||
defer lockman.ReleaseClass(ctx, dispatcher.modelManager, ownerProjId)
|
||||
|
||||
if !dispatcher.modelManager.AllowCreateItem(ctx, userCred, query, data) {
|
||||
var isAllow bool
|
||||
if globalsRbacEnabled {
|
||||
isAllow = isRbacAllowed(dispatcher.modelManager, nil, userCred, PolicyActionCreate)
|
||||
} else {
|
||||
isAllow = dispatcher.modelManager.AllowCreateItem(ctx, userCred, query, data)
|
||||
}
|
||||
if !isAllow {
|
||||
return nil, httperrors.NewForbiddenError("Not allow to create item")
|
||||
}
|
||||
|
||||
@@ -806,7 +874,13 @@ func (dispatcher *DBModelDispatcher) BatchCreate(ctx context.Context, query json
|
||||
lockman.LockClass(ctx, dispatcher.modelManager, ownerProjId)
|
||||
defer lockman.ReleaseClass(ctx, dispatcher.modelManager, ownerProjId)
|
||||
|
||||
if !dispatcher.modelManager.AllowCreateItem(ctx, userCred, query, data) {
|
||||
var isAllow bool
|
||||
if globalsRbacEnabled {
|
||||
isAllow = isRbacAllowed(dispatcher.modelManager, nil, userCred, PolicyActionCreate)
|
||||
} else {
|
||||
isAllow = dispatcher.modelManager.AllowCreateItem(ctx, userCred, query, data)
|
||||
}
|
||||
if !isAllow {
|
||||
return nil, httperrors.NewForbiddenError("Not allow to create item")
|
||||
}
|
||||
|
||||
@@ -858,16 +932,30 @@ func (dispatcher *DBModelDispatcher) PerformClassAction(ctx context.Context, act
|
||||
lockman.LockClass(ctx, dispatcher.modelManager, ownerProjId)
|
||||
defer lockman.ReleaseClass(ctx, dispatcher.modelManager, ownerProjId)
|
||||
|
||||
managerValue := reflect.ValueOf(dispatcher.modelManager)
|
||||
if action == "check-create-data" {
|
||||
manager := dispatcher.modelManager
|
||||
if body, err := data.(*jsonutils.JSONDict).Get(manager.Keyword()); err != nil {
|
||||
|
||||
body, err := data.(*jsonutils.JSONDict).Get(manager.Keyword())
|
||||
if err != nil {
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
} else {
|
||||
return manager.ValidateCreateData(ctx, userCred, ownerProjId, query, body.(*jsonutils.JSONDict))
|
||||
}
|
||||
data := body.(*jsonutils.JSONDict)
|
||||
|
||||
var isAllow bool
|
||||
if globalsRbacEnabled {
|
||||
isAllow = isRbacAllowed(manager, nil, userCred, PolicyActionPerform, action)
|
||||
} else {
|
||||
isAllow = manager.AllowPerformCheckCreateData(ctx, userCred, query, data)
|
||||
}
|
||||
if !isAllow {
|
||||
return nil, httperrors.NewForbiddenError("not allow to perform %s", action)
|
||||
}
|
||||
|
||||
return manager.ValidateCreateData(ctx, userCred, ownerProjId, query, data)
|
||||
}
|
||||
return objectPerformAction(dispatcher, managerValue, ctx, userCred, action, query, data)
|
||||
|
||||
managerValue := reflect.ValueOf(dispatcher.modelManager)
|
||||
return objectPerformAction(dispatcher, nil, managerValue, ctx, userCred, action, query, data)
|
||||
}
|
||||
|
||||
func (dispatcher *DBModelDispatcher) PerformAction(ctx context.Context, idStr string, action string, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
@@ -884,7 +972,7 @@ func (dispatcher *DBModelDispatcher) PerformAction(ctx context.Context, idStr st
|
||||
defer lockman.ReleaseObject(ctx, model)
|
||||
|
||||
modelValue := reflect.ValueOf(model)
|
||||
result, err := objectPerformAction(dispatcher, modelValue, ctx, userCred, action, query, data)
|
||||
result, err := objectPerformAction(dispatcher, model, modelValue, ctx, userCred, action, query, data)
|
||||
if err == nil && result == nil {
|
||||
return getItemDetails(dispatcher.modelManager, model, ctx, userCred, query)
|
||||
} else {
|
||||
@@ -892,23 +980,23 @@ func (dispatcher *DBModelDispatcher) PerformAction(ctx context.Context, idStr st
|
||||
}
|
||||
}
|
||||
|
||||
func objectPerformAction(dispatcher *DBModelDispatcher, modelValue reflect.Value, ctx context.Context, userCred mcclient.TokenCredential, action string, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
isGeneral := false
|
||||
|
||||
func objectPerformAction(dispatcher *DBModelDispatcher, model IModel, modelValue reflect.Value, ctx context.Context, userCred mcclient.TokenCredential, action string, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
const generalFuncName = "PerformAction"
|
||||
const generalAllowFuncName = "AllowPerformAction"
|
||||
// const generalAllowFuncName = "AllowPerformAction"
|
||||
|
||||
isGeneral := false
|
||||
funcName := fmt.Sprintf("Perform%s", utils.Kebab2Camel(action, "-"))
|
||||
allowFuncName := "Allow" + funcName
|
||||
funcValue := modelValue.MethodByName(allowFuncName)
|
||||
|
||||
funcValue := modelValue.MethodByName(funcName)
|
||||
if !funcValue.IsValid() || funcValue.IsNil() {
|
||||
funcValue = modelValue.MethodByName(generalAllowFuncName)
|
||||
funcValue = modelValue.MethodByName(generalFuncName)
|
||||
if !funcValue.IsValid() || funcValue.IsNil() {
|
||||
msg := fmt.Sprintf("%s allow perform action %s not found", dispatcher.Keyword(), action)
|
||||
msg := fmt.Sprintf("%s perform action %s not found", dispatcher.Keyword(), action)
|
||||
log.Errorf(msg)
|
||||
return nil, httperrors.NewActionNotFoundError(msg)
|
||||
} else {
|
||||
isGeneral = true
|
||||
funcName = generalFuncName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -931,25 +1019,30 @@ func objectPerformAction(dispatcher *DBModelDispatcher, modelValue reflect.Value
|
||||
}
|
||||
}
|
||||
|
||||
outs := funcValue.Call(params)
|
||||
if len(outs) != 1 {
|
||||
return nil, httperrors.NewInternalServerError("Invald %s return value", allowFuncName)
|
||||
var isAllow bool
|
||||
if globalsRbacEnabled {
|
||||
isAllow = isRbacAllowed(dispatcher.modelManager, model, userCred, PolicyActionPerform, action)
|
||||
} else {
|
||||
allowFuncName := "Allow" + funcName
|
||||
allowFuncValue := modelValue.MethodByName(allowFuncName)
|
||||
if !allowFuncValue.IsValid() || allowFuncValue.IsNil() {
|
||||
msg := fmt.Sprintf("%s allow perform action %s not found", dispatcher.Keyword(), action)
|
||||
log.Errorf(msg)
|
||||
return nil, httperrors.NewActionNotFoundError(msg)
|
||||
}
|
||||
|
||||
outs := funcValue.Call(params)
|
||||
if len(outs) != 1 {
|
||||
return nil, httperrors.NewInternalServerError("Invald %s return value", allowFuncName)
|
||||
}
|
||||
|
||||
isAllow = outs[0].Bool()
|
||||
}
|
||||
if !outs[0].Bool() {
|
||||
if !isAllow {
|
||||
return nil, httperrors.NewForbiddenError(fmt.Sprintf("%s not allow to perform action %s", dispatcher.Keyword(), action))
|
||||
}
|
||||
|
||||
if isGeneral {
|
||||
funcValue = modelValue.MethodByName(generalFuncName)
|
||||
} else {
|
||||
funcName = fmt.Sprintf("Perform%s", utils.Kebab2Camel(action, "-"))
|
||||
funcValue = modelValue.MethodByName(funcName)
|
||||
}
|
||||
if !funcValue.IsValid() || funcValue.IsNil() {
|
||||
return nil, httperrors.NewActionNotFoundError(fmt.Sprintf("%s perform action %s not found", dispatcher.Keyword(), action))
|
||||
}
|
||||
|
||||
outs = funcValue.Call(params)
|
||||
outs := funcValue.Call(params)
|
||||
if len(outs) != 2 {
|
||||
return nil, httperrors.NewInternalServerError("Invald %s return value", funcName)
|
||||
}
|
||||
@@ -1038,7 +1131,13 @@ func (dispatcher *DBModelDispatcher) Update(ctx context.Context, idStr string, q
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
|
||||
if !model.AllowUpdateItem(ctx, userCred) {
|
||||
var isAllow bool
|
||||
if globalsRbacEnabled {
|
||||
isAllow = isRbacAllowed(dispatcher.modelManager, model, userCred, PolicyActionUpdate)
|
||||
} else {
|
||||
isAllow = model.AllowUpdateItem(ctx, userCred)
|
||||
}
|
||||
if !isAllow {
|
||||
return nil, httperrors.NewForbiddenError(fmt.Sprintf("Not allow to update item"))
|
||||
}
|
||||
|
||||
@@ -1067,7 +1166,14 @@ func DeleteModel(ctx context.Context, userCred mcclient.TokenCredential, item IM
|
||||
|
||||
func deleteItem(manager IModelManager, model IModel, ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
log.Debugf("deleteItem %s", jsonutils.Marshal(model))
|
||||
if !model.AllowDeleteItem(ctx, userCred, query, data) {
|
||||
|
||||
var isAllow bool
|
||||
if globalsRbacEnabled {
|
||||
isAllow = isRbacAllowed(manager, model, userCred, PolicyActionDelete)
|
||||
} else {
|
||||
isAllow = model.AllowDeleteItem(ctx, userCred, query, data)
|
||||
}
|
||||
if !isAllow {
|
||||
log.Errorf("not allow to delete")
|
||||
return nil, httperrors.NewForbiddenError(fmt.Sprintf("%s(%s) not allow to delete", manager.KeywordPlural(), model.GetId()))
|
||||
}
|
||||
|
||||
@@ -2,8 +2,37 @@ package db
|
||||
|
||||
/// Global virtual resource namespace
|
||||
|
||||
var globalVirtualResourceNamespace = false
|
||||
var (
|
||||
globalVirtualResourceNamespace = false
|
||||
|
||||
globalRegion = ""
|
||||
|
||||
globalServiceType = ""
|
||||
|
||||
globalsRbacEnabled = false
|
||||
)
|
||||
|
||||
func EnableGlobalVirtualResourceNamespace() {
|
||||
globalVirtualResourceNamespace = true
|
||||
}
|
||||
|
||||
func SetGlobalRegion(region string) {
|
||||
globalRegion = region
|
||||
}
|
||||
|
||||
func GetGlobalRegion() string {
|
||||
return globalRegion
|
||||
}
|
||||
|
||||
func SetGlobalServiceType(srvType string) {
|
||||
globalServiceType = srvType
|
||||
}
|
||||
|
||||
func GetGlobalServiceType() string {
|
||||
return globalServiceType
|
||||
}
|
||||
|
||||
func EnableGlobalRbac() {
|
||||
globalsRbacEnabled = true
|
||||
PolicyManager.start()
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ type IModelManager interface {
|
||||
|
||||
// allow perform action
|
||||
AllowPerformAction(ctx context.Context, userCred mcclient.TokenCredential, action string, query jsonutils.JSONObject, data jsonutils.JSONObject) bool
|
||||
AllowPerformCheckCreateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool
|
||||
PerformAction(ctx context.Context, userCred mcclient.TokenCredential, action string, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error)
|
||||
|
||||
DoCreate(ctx context.Context, userCred mcclient.TokenCredential, kwargs jsonutils.JSONObject, data jsonutils.JSONObject, realManager IModelManager) (IModel, error)
|
||||
|
||||
@@ -150,6 +150,10 @@ func (manager *SModelBaseManager) PerformAction(ctx context.Context, userCred mc
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (manager *SModelBaseManager) AllowPerformCheckCreateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||||
return userCred.IsSystemAdmin()
|
||||
}
|
||||
|
||||
func (manager *SModelBaseManager) InitializeData() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"time"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
)
|
||||
|
||||
const (
|
||||
PolicyFailedRetryInterval = 15 * time.Second
|
||||
PolicyRefreshInterval = 15 * time.Minute
|
||||
|
||||
PolicyDelegation = "delegate"
|
||||
|
||||
PolicyActionList = "list"
|
||||
PolicyActionGet = "get"
|
||||
PolicyActionUpdate = "update"
|
||||
PolicyActionPatch = "patch"
|
||||
PolicyActionCreate = "create"
|
||||
PolicyActionDelete = "delete"
|
||||
PolicyActionPerform = "perform"
|
||||
)
|
||||
|
||||
var PolicyManager *SPolicyManager
|
||||
|
||||
func init() {
|
||||
PolicyManager = &SPolicyManager{}
|
||||
}
|
||||
|
||||
type SPolicyManager struct {
|
||||
policies map[string]rbacutils.SRbacPolicy
|
||||
adminPolicies map[string]rbacutils.SRbacPolicy
|
||||
lastSync time.Time
|
||||
}
|
||||
|
||||
func parseJsonPolicy(obj jsonutils.JSONObject) (string, rbacutils.SRbacPolicy, error) {
|
||||
policy := rbacutils.SRbacPolicy{}
|
||||
typeStr, err := obj.GetString("type")
|
||||
if err != nil {
|
||||
log.Errorf("get type error %s", err)
|
||||
return "", policy, err
|
||||
}
|
||||
|
||||
blobStr, err := obj.GetString("blob")
|
||||
if err != nil {
|
||||
log.Errorf("get blob error %s", err)
|
||||
return "", policy, err
|
||||
}
|
||||
blob, err := jsonutils.ParseString(blobStr)
|
||||
if err != nil {
|
||||
log.Errorf("parse blob json error %s", err)
|
||||
return "", policy, err
|
||||
}
|
||||
err = policy.Decode(blob)
|
||||
if err != nil {
|
||||
log.Errorf("policy decode error %s", err)
|
||||
return "", policy, err
|
||||
}
|
||||
|
||||
return typeStr, policy, nil
|
||||
}
|
||||
|
||||
func fetchPolicies() (map[string]rbacutils.SRbacPolicy, map[string]rbacutils.SRbacPolicy, error) {
|
||||
s := auth.GetAdminSession(GetGlobalRegion(), "v1")
|
||||
|
||||
policies := make(map[string]rbacutils.SRbacPolicy)
|
||||
adminPolicies := make(map[string]rbacutils.SRbacPolicy)
|
||||
|
||||
offset := 0
|
||||
for {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewInt(2048), "limit")
|
||||
params.Add(jsonutils.NewInt(int64(offset)), "offset")
|
||||
result, err := modules.Policies.List(s, params)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("fetch policy failed")
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(result.Data); i += 1 {
|
||||
typeStr, policy, err := parseJsonPolicy(result.Data[i])
|
||||
if err != nil {
|
||||
log.Errorf("error parse policty %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if policy.IsAdmin {
|
||||
adminPolicies[typeStr] = policy
|
||||
} else {
|
||||
policies[typeStr] = policy
|
||||
}
|
||||
}
|
||||
|
||||
offset += len(result.Data)
|
||||
if offset >= result.Total {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return policies, adminPolicies, nil
|
||||
}
|
||||
|
||||
func (manager *SPolicyManager) start() {
|
||||
log.Infof("PolicyManager start to fetch policies ...")
|
||||
manager.sync()
|
||||
}
|
||||
|
||||
func (manager *SPolicyManager) sync() {
|
||||
policies, adminPolicies, err := fetchPolicies()
|
||||
if err != nil {
|
||||
log.Errorf("sync policy fail %s", err)
|
||||
time.AfterFunc(PolicyFailedRetryInterval, manager.sync)
|
||||
return
|
||||
}
|
||||
manager.policies = policies
|
||||
manager.adminPolicies = adminPolicies
|
||||
manager.lastSync = time.Now()
|
||||
time.AfterFunc(PolicyRefreshInterval, manager.sync)
|
||||
}
|
||||
|
||||
func (manager *SPolicyManager) Allow(isAdmin bool, userCred mcclient.TokenCredential, service string, resource string, action string, extra ...string) bool {
|
||||
var policies map[string]rbacutils.SRbacPolicy
|
||||
if isAdmin {
|
||||
policies = manager.adminPolicies
|
||||
} else {
|
||||
policies = manager.policies
|
||||
}
|
||||
if policies == nil {
|
||||
log.Warningf("no policies fetched")
|
||||
return false
|
||||
}
|
||||
userCredJson := userCred.ToJson()
|
||||
log.Debugf("%s", userCredJson)
|
||||
for _, p := range policies {
|
||||
if p.Allow(userCredJson, service, resource, action, extra...) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -77,7 +77,7 @@ func (manager *STenantCacheManager) FetchTenantByName(ctx context.Context, idStr
|
||||
}
|
||||
|
||||
func (manager *STenantCacheManager) fetchTenantFromKeystone(ctx context.Context, idStr string) (*STenant, error) {
|
||||
s := auth.GetAdminSession("", "v1")
|
||||
s := auth.GetAdminSession(GetGlobalRegion(), "v1")
|
||||
tenant, err := modules.Projects.Get(s, idStr, nil)
|
||||
if err != nil {
|
||||
log.Errorf("fetch project fail %s", err)
|
||||
|
||||
@@ -40,6 +40,8 @@ type Options struct {
|
||||
SslCertfile string `help:"ssl certification file"`
|
||||
SslKeyfile string `help:"ssl certification key file"`
|
||||
|
||||
EnableRbac bool `help:"Switch on Role-based Access Control" default:"false"`
|
||||
|
||||
structarg.BaseOptions
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user