mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-21 14:19:49 +08:00
Merge pull request #17047 from swordqiu/hotfix/qj-role-policy-assignment-violation-check
fix: prevent policy violate when assigning policy to roles
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/util/httputils"
|
||||
"yunion.io/x/pkg/util/rbacscope"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
@@ -30,6 +31,10 @@ import (
|
||||
)
|
||||
|
||||
func ExportOptionsHandler(app *appsrv.Application, options interface{}) {
|
||||
ExportOptionsHandlerWithPrefix(app, "", options)
|
||||
}
|
||||
|
||||
func ExportOptionsHandlerWithPrefix(app *appsrv.Application, prefix string, options interface{}) {
|
||||
hf := func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
|
||||
result := policy.PolicyManager.Allow(rbacscope.ScopeSystem, userCred, consts.GetServiceType(), "app-options", "list")
|
||||
@@ -41,5 +46,6 @@ func ExportOptionsHandler(app *appsrv.Application, options interface{}) {
|
||||
}
|
||||
ahf := auth.Authenticate(hf)
|
||||
name := "get_app_options"
|
||||
app.AddHandler2("GET", "/app-options", ahf, nil, name, nil)
|
||||
pref := httputils.JoinPath(prefix, "app-options")
|
||||
app.AddHandler2("GET", pref, ahf, nil, name, nil)
|
||||
}
|
||||
|
||||
@@ -678,3 +678,21 @@ func (policy *SPolicy) GetI18N(ctx context.Context) *jsonutils.JSONDict {
|
||||
r.Set("description", jsonutils.NewString(act18))
|
||||
return r
|
||||
}
|
||||
|
||||
func (policy *SPolicy) ValidateUpdateCondition(ctx context.Context) error {
|
||||
err := policy.SEnabledIdentityBaseResource.ValidateUpdateCondition(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SEnabledIdentityBaseResource.ValidateUpdateCondition")
|
||||
}
|
||||
//if policy.IsSystem.IsTrue() {
|
||||
// return errors.Wrap(httperrors.ErrForbidden, "system policy")
|
||||
//}
|
||||
rps, err := RolePolicyManager.fetchByPolicyId(policy.Id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetchByPolicyId")
|
||||
}
|
||||
if len(rps) > 0 {
|
||||
return errors.Wrap(httperrors.ErrForbidden, "policy in use")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/keystone/options"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/tagutils"
|
||||
)
|
||||
@@ -529,14 +530,14 @@ func (manager *SProjectManager) ValidateCreateData(ctx context.Context, userCred
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (self *SProject) PostCreate(
|
||||
func (project *SProject) PostCreate(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
ownerId mcclient.IIdentityProvider,
|
||||
query jsonutils.JSONObject,
|
||||
data jsonutils.JSONObject,
|
||||
) {
|
||||
self.SIdentityBaseResource.PostCreate(ctx, userCred, ownerId, query, data)
|
||||
project.SIdentityBaseResource.PostCreate(ctx, userCred, ownerId, query, data)
|
||||
|
||||
quota := &SIdentityQuota{Project: 1}
|
||||
quota.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()})
|
||||
@@ -546,8 +547,7 @@ func (self *SProject) PostCreate(
|
||||
}
|
||||
}
|
||||
|
||||
func threeMemberSystemValidateJoinProject(userCred mcclient.TokenCredential, project *SProject, roleIds []string) error {
|
||||
_, assignPolicies, _ := RolePolicyManager.GetMatchPolicyGroup2(false, roleIds, project.Id, "", time.Time{}, false)
|
||||
func threeMemberSystemValidatePolicies(userCred mcclient.TokenCredential, projectId string, assignPolicies rbacutils.TPolicyGroup) error {
|
||||
assignScope := assignPolicies.HighestScope()
|
||||
var checkRoles []string
|
||||
if assignScope == rbacscope.ScopeSystem {
|
||||
@@ -563,7 +563,7 @@ func threeMemberSystemValidateJoinProject(userCred mcclient.TokenCredential, pro
|
||||
if err != nil {
|
||||
return httperrors.NewResourceNotFoundError2(RoleManager.Keyword(), roleName)
|
||||
}
|
||||
_, adminPolicies, _ := RolePolicyManager.GetMatchPolicyGroup2(false, []string{role.Id}, project.Id, "", time.Time{}, false)
|
||||
_, adminPolicies, _ := RolePolicyManager.GetMatchPolicyGroup2(false, []string{role.Id}, projectId, "", time.Time{}, false)
|
||||
if adminPolicies[assignScope].Contains(assignPolicies[assignScope]) {
|
||||
contains = append(contains, roleName)
|
||||
}
|
||||
@@ -574,15 +574,11 @@ func threeMemberSystemValidateJoinProject(userCred mcclient.TokenCredential, pro
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateJoinProject(userCred mcclient.TokenCredential, project *SProject, roleIds []string) error {
|
||||
if options.Options.NoPolicyViolationCheck {
|
||||
return nil
|
||||
func normalValidatePolicies(userCred mcclient.TokenCredential, assignPolicies rbacutils.TPolicyGroup) error {
|
||||
_, opsPolicies, err := RolePolicyManager.GetMatchPolicyGroup(userCred, time.Time{}, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "RolePolicyManager.GetMatchPolicyGroup")
|
||||
}
|
||||
if options.Options.ThreeAdminRoleSystem {
|
||||
return threeMemberSystemValidateJoinProject(userCred, project, roleIds)
|
||||
}
|
||||
_, opsPolicies, _ := RolePolicyManager.GetMatchPolicyGroup(userCred, time.Time{}, false)
|
||||
_, assignPolicies, _ := RolePolicyManager.GetMatchPolicyGroup2(false, roleIds, project.Id, "", time.Time{}, false)
|
||||
opsScope := opsPolicies.HighestScope()
|
||||
assignScope := assignPolicies.HighestScope()
|
||||
if assignScope.HigherThan(opsScope) {
|
||||
@@ -593,6 +589,25 @@ func validateJoinProject(userCred mcclient.TokenCredential, project *SProject, r
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateAssignPolicies(userCred mcclient.TokenCredential, projectId string, assignPolicies rbacutils.TPolicyGroup) error {
|
||||
if options.Options.NoPolicyViolationCheck {
|
||||
return nil
|
||||
}
|
||||
if options.Options.ThreeAdminRoleSystem {
|
||||
return threeMemberSystemValidatePolicies(userCred, projectId, assignPolicies)
|
||||
} else {
|
||||
return normalValidatePolicies(userCred, assignPolicies)
|
||||
}
|
||||
}
|
||||
|
||||
func validateJoinProject(userCred mcclient.TokenCredential, project *SProject, roleIds []string) error {
|
||||
_, assignPolicies, err := RolePolicyManager.GetMatchPolicyGroup2(false, roleIds, project.Id, "", time.Time{}, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "RolePolicyManager.GetMatchPolicyGroup2")
|
||||
}
|
||||
return validateAssignPolicies(userCred, project.Id, assignPolicies)
|
||||
}
|
||||
|
||||
func (project *SProject) AllowPerformJoin(ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
|
||||
@@ -565,7 +565,17 @@ func (manager *SRolePolicyManager) fetchByRoleId(roleId string) ([]SRolePolicy,
|
||||
q := manager.Query().Equals("role_id", roleId)
|
||||
rps := make([]SRolePolicy, 0)
|
||||
err := db.FetchModelObjects(manager, q, &rps)
|
||||
if err != nil && errors.Cause(err) == sql.ErrNoRows {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "FetchModelObjects")
|
||||
}
|
||||
return rps, nil
|
||||
}
|
||||
|
||||
func (manager *SRolePolicyManager) fetchByPolicyId(policyId string) ([]SRolePolicy, error) {
|
||||
q := manager.Query().Equals("policy_id", policyId)
|
||||
rps := make([]SRolePolicy, 0)
|
||||
err := db.FetchModelObjects(manager, q, &rps)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "FetchModelObjects")
|
||||
}
|
||||
return rps, nil
|
||||
|
||||
@@ -548,14 +548,19 @@ func (role *SRole) GetSharedDomains() []string {
|
||||
return db.SharableGetSharedProjects(role, db.SharedTargetDomain)
|
||||
}
|
||||
|
||||
func (role *SRole) AllowPerformSetPolicies(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RolePerformSetPoliciesInput) bool {
|
||||
return true
|
||||
func validateRolePolicies(userCred mcclient.TokenCredential, policyIds []string) error {
|
||||
_, assignPolicies, err := RolePolicyManager.GetPolicyGroupByIds(policyIds, false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "RolePolicyManager.GetPolicyGroupByIds %s", policyIds)
|
||||
}
|
||||
return validateAssignPolicies(userCred, "", assignPolicies)
|
||||
}
|
||||
|
||||
func (role *SRole) PerformSetPolicies(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RolePerformSetPoliciesInput) (jsonutils.JSONObject, error) {
|
||||
if len(input.Action) == 0 {
|
||||
input.Action = api.ROLE_SET_POLICY_ACTION_DEFAULT
|
||||
}
|
||||
inputPolicyIds := stringutils2.NewSortedStrings(nil)
|
||||
normalInputIds := stringutils2.NewSortedStrings(nil)
|
||||
normalInputs := make(map[string]sRolePerformAddPolicyInput, len(input.Policies))
|
||||
for i := range input.Policies {
|
||||
@@ -563,6 +568,7 @@ func (role *SRole) PerformSetPolicies(ctx context.Context, userCred mcclient.Tok
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "normalizeRoleAddPolicyInput at %d", i)
|
||||
}
|
||||
inputPolicyIds = stringutils2.Append(inputPolicyIds, normalInput.policyId)
|
||||
idstr := normalInput.getId()
|
||||
if _, ok := normalInputs[idstr]; !ok {
|
||||
normalInputs[idstr] = normalInput
|
||||
@@ -577,9 +583,11 @@ func (role *SRole) PerformSetPolicies(ctx context.Context, userCred mcclient.Tok
|
||||
return nil, errors.Wrap(err, "RolePolicyManager.fetchByRoleId")
|
||||
}
|
||||
|
||||
existPolicyIds := stringutils2.NewSortedStrings(nil)
|
||||
existRpIds := stringutils2.NewSortedStrings(nil)
|
||||
existRpMap := make(map[string]*SRolePolicy)
|
||||
for i := range existRpList {
|
||||
existPolicyIds = stringutils2.Append(existPolicyIds, existRpList[i].PolicyId)
|
||||
idstr := existRpList[i].GetId()
|
||||
if _, ok := existRpMap[idstr]; !ok {
|
||||
existRpMap[idstr] = &existRpList[i]
|
||||
@@ -589,6 +597,19 @@ func (role *SRole) PerformSetPolicies(ctx context.Context, userCred mcclient.Tok
|
||||
|
||||
addedIds, updatedIds, deletedIds := stringutils2.Split(normalInputIds, existRpIds)
|
||||
|
||||
// validate
|
||||
var newPolicyIds []string
|
||||
if input.Action == api.ROLE_SET_POLICY_ACTION_REPLACE {
|
||||
newPolicyIds = inputPolicyIds
|
||||
} else {
|
||||
newPolicyIds = stringutils2.Append(newPolicyIds, inputPolicyIds...)
|
||||
newPolicyIds = stringutils2.Append(newPolicyIds, existPolicyIds...)
|
||||
}
|
||||
err = validateRolePolicies(userCred, newPolicyIds)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "validateRolePolicies")
|
||||
}
|
||||
|
||||
if input.Action == api.ROLE_SET_POLICY_ACTION_REPLACE {
|
||||
for _, idstr := range deletedIds {
|
||||
toDel := existRpMap[idstr]
|
||||
@@ -618,10 +639,6 @@ func (role *SRole) PerformSetPolicies(ctx context.Context, userCred mcclient.Tok
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (role *SRole) AllowPerformAddPolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RolePerformAddPolicyInput) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type sRolePerformAddPolicyInput struct {
|
||||
prefixes []netutils.IPV4Prefix
|
||||
roleId string
|
||||
@@ -681,6 +698,22 @@ func (role *SRole) PerformAddPolicy(ctx context.Context, userCred mcclient.Token
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "normalizeRoleAddPolicyInput")
|
||||
}
|
||||
|
||||
// validate
|
||||
rps, err := RolePolicyManager.fetchByRoleId(role.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchByRoleId")
|
||||
}
|
||||
newPolicyIds := stringutils2.NewSortedStrings(nil)
|
||||
for i := range rps {
|
||||
newPolicyIds = stringutils2.Append(newPolicyIds, rps[i].PolicyId)
|
||||
}
|
||||
newPolicyIds = stringutils2.Append(newPolicyIds, normalInput.policyId)
|
||||
err = validateRolePolicies(userCred, newPolicyIds)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "validateRolePolicies")
|
||||
}
|
||||
|
||||
err = RolePolicyManager.newRecord(ctx, normalInput.roleId, normalInput.projectId, normalInput.policyId, tristate.True, normalInput.prefixes, normalInput.validSince, normalInput.validUntil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "newRecord")
|
||||
@@ -688,10 +721,6 @@ func (role *SRole) PerformAddPolicy(ctx context.Context, userCred mcclient.Token
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (role *SRole) AllowPerformRemovePolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RolePerformRemovePolicyInput) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (role *SRole) PerformRemovePolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RolePerformRemovePolicyInput) (jsonutils.JSONObject, error) {
|
||||
if len(input.ProjectId) > 0 {
|
||||
proj, err := ProjectManager.FetchByIdOrName(userCred, input.ProjectId)
|
||||
|
||||
@@ -44,7 +44,7 @@ func InitHandlers(app *appsrv.Application) {
|
||||
usages.AddUsageHandler(API_VERSION, app)
|
||||
taskman.AddTaskHandler(API_VERSION, app)
|
||||
|
||||
app_common.ExportOptionsHandler(app, &options.Options)
|
||||
app_common.ExportOptionsHandlerWithPrefix(app, API_VERSION, &options.Options)
|
||||
|
||||
tokens.AddHandler(app)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user