policies.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package models
  15. import (
  16. "context"
  17. "database/sql"
  18. "time"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/gotypes"
  23. "yunion.io/x/pkg/tristate"
  24. "yunion.io/x/pkg/util/netutils"
  25. "yunion.io/x/pkg/util/rbacscope"
  26. "yunion.io/x/pkg/utils"
  27. "yunion.io/x/sqlchemy"
  28. "yunion.io/x/onecloud/pkg/apis"
  29. api "yunion.io/x/onecloud/pkg/apis/identity"
  30. "yunion.io/x/onecloud/pkg/cloudcommon/consts"
  31. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  32. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  33. policyman "yunion.io/x/onecloud/pkg/cloudcommon/policy"
  34. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  35. "yunion.io/x/onecloud/pkg/httperrors"
  36. "yunion.io/x/onecloud/pkg/keystone/locale"
  37. "yunion.io/x/onecloud/pkg/keystone/options"
  38. "yunion.io/x/onecloud/pkg/mcclient"
  39. "yunion.io/x/onecloud/pkg/util/rbacutils"
  40. "yunion.io/x/onecloud/pkg/util/stringutils2"
  41. "yunion.io/x/onecloud/pkg/util/tagutils"
  42. )
  43. type SPolicyManager struct {
  44. SEnabledIdentityBaseResourceManager
  45. db.SSharableBaseResourceManager
  46. }
  47. var PolicyManager *SPolicyManager
  48. func init() {
  49. PolicyManager = &SPolicyManager{
  50. SEnabledIdentityBaseResourceManager: NewEnabledIdentityBaseResourceManager(
  51. SPolicy{},
  52. "policy",
  53. "policy",
  54. "policies",
  55. ),
  56. }
  57. PolicyManager.SetVirtualObject(PolicyManager)
  58. }
  59. /*
  60. +-------+--------------+------+-----+---------+-------+
  61. | Field | Type | Null | Key | Default | Extra |
  62. +-------+--------------+------+-----+---------+-------+
  63. | id | varchar(64) | NO | PRI | NULL | |
  64. | type | varchar(255) | NO | | NULL | |
  65. | blob | text | NO | | NULL | |
  66. | extra | text | YES | | NULL | |
  67. +-------+--------------+------+-----+---------+-------+
  68. */
  69. type SPolicy struct {
  70. SEnabledIdentityBaseResource
  71. db.SSharableBaseResource `"is_public->create":"domain_optional" "public_scope->create":"domain_optional"`
  72. // swagger:ignore
  73. // Deprecated
  74. Type string `width:"255" charset:"utf8" nullable:"false" list:"user" create:"domain_required" update:"domain"`
  75. // 权限定义
  76. Blob jsonutils.JSONObject `nullable:"false" list:"user" create:"domain_required" update:"domain"`
  77. // 权限范围
  78. Scope rbacscope.TRbacScope `nullable:"true" list:"user" create:"domain_required" update:"domain"`
  79. // 是否为系统权限
  80. IsSystem tristate.TriState `default:"false" list:"domain" update:"admin" create:"admin_optional"`
  81. // 匹配的项目标签
  82. ProjectTags tagutils.TTagSet `nullable:"true" list:"user" update:"domain" create:"domain_optional"`
  83. // 匹配的域标签
  84. DomainTags tagutils.TTagSet `nullable:"true" list:"user" update:"admin" create:"admin_optional"`
  85. // 匹配的资源标签
  86. ObjectTags tagutils.TTagSet `nullable:"true" list:"user" update:"domain" create:"domain_optional"`
  87. // 匹配的组织架构节点
  88. OrgNodeId []string `nullable:"true" list:"user" update:"domain" create:"domain_optional"`
  89. }
  90. func (manager *SPolicyManager) InitializeData() error {
  91. q := manager.Query()
  92. q = q.IsNullOrEmpty("name")
  93. policies := make([]SPolicy, 0)
  94. err := db.FetchModelObjects(manager, q, &policies)
  95. if err != nil {
  96. return err
  97. }
  98. for i := range policies {
  99. if !gotypes.IsNil(policies[i].Extra) {
  100. continue
  101. }
  102. db.Update(&policies[i], func() error {
  103. policies[i].Name = policies[i].Type
  104. policies[i].Description, _ = policies[i].Extra.GetString("description")
  105. return nil
  106. })
  107. }
  108. err = manager.initializeRolePolicyGroup()
  109. if err != nil {
  110. return err
  111. }
  112. return nil
  113. }
  114. func (manager *SPolicyManager) initializeRolePolicyGroup() error {
  115. ctx := context.Background()
  116. q := manager.Query()
  117. q = q.IsNullOrEmpty("scope")
  118. policies := make([]SPolicy, 0)
  119. err := db.FetchModelObjects(manager, q, &policies)
  120. if err != nil {
  121. return err
  122. }
  123. for i := range policies {
  124. var policy rbacutils.SRbacPolicy
  125. err := policy.Decode(policies[i].Blob)
  126. if err != nil {
  127. log.Errorf("Decode policy %s failed %s", policies[i].Name, err)
  128. continue
  129. }
  130. failed := false
  131. if len(policy.Roles) == 0 && len(policy.Projects) == 0 {
  132. // match any
  133. roles, err := policies[i].fetchMatchableRoles()
  134. if err != nil {
  135. log.Errorf("policy fetchMatchableRoles fail %s", err)
  136. failed = true
  137. } else {
  138. for _, r := range roles {
  139. err = RolePolicyManager.newRecord(ctx, r.Id, "", policies[i].Id, tristate.NewFromBool(policy.Auth), policy.Ips, time.Time{}, time.Time{})
  140. if err != nil {
  141. log.Errorf("insert role policy fail %s", err)
  142. failed = true
  143. }
  144. }
  145. }
  146. } else if len(policy.Roles) > 0 && len(policy.Projects) == 0 {
  147. for _, r := range policy.Roles {
  148. role, err := RoleManager.FetchRoleByName(r, policies[i].DomainId, "")
  149. if err != nil {
  150. log.Errorf("fetch role %s fail %s", r, err)
  151. continue
  152. }
  153. err = RolePolicyManager.newRecord(ctx, role.Id, "", policies[i].Id, tristate.True, policy.Ips, time.Time{}, time.Time{})
  154. if err != nil {
  155. log.Errorf("insert role policy fail %s", err)
  156. failed = true
  157. }
  158. }
  159. } else if len(policy.Roles) == 0 && len(policy.Projects) > 0 {
  160. for _, p := range policy.Projects {
  161. project, err := ProjectManager.FetchProjectByName(p, policies[i].DomainId, "")
  162. if err != nil {
  163. log.Errorf("fetch porject %s fail %s", p, err)
  164. continue
  165. }
  166. roles, err := policies[i].fetchMatchableRoles()
  167. if err != nil {
  168. log.Errorf("policy fetchMatchableRoles fail %s", err)
  169. failed = true
  170. } else {
  171. for _, r := range roles {
  172. err = RolePolicyManager.newRecord(ctx, r.Id, project.Id, policies[i].Id, tristate.True, policy.Ips, time.Time{}, time.Time{})
  173. if err != nil {
  174. log.Errorf("insert role policy fail %s", err)
  175. failed = true
  176. }
  177. }
  178. }
  179. }
  180. } else if len(policy.Roles) > 0 && len(policy.Projects) > 0 {
  181. for _, r := range policy.Roles {
  182. role, err := RoleManager.FetchRoleByName(r, policies[i].DomainId, "")
  183. if err != nil {
  184. log.Errorf("fetch role %s fail %s", r, err)
  185. continue
  186. }
  187. for _, p := range policy.Projects {
  188. project, err := ProjectManager.FetchProjectByName(p, policies[i].DomainId, "")
  189. if err != nil {
  190. log.Errorf("fetch project %s fail %s", p, err)
  191. continue
  192. }
  193. err = RolePolicyManager.newRecord(ctx, role.Id, project.Id, policies[i].Id, tristate.True, policy.Ips, time.Time{}, time.Time{})
  194. if err != nil {
  195. log.Errorf("insert role policy fail %s", err)
  196. failed = true
  197. }
  198. }
  199. }
  200. }
  201. if !failed {
  202. db.Update(&policies[i], func() error {
  203. policies[i].Scope = policy.Scope
  204. // do not rewrite blob, make backward compatible
  205. // policies[i].Blob = policy.Rules.Encode()
  206. return nil
  207. })
  208. }
  209. }
  210. return nil
  211. }
  212. func (manager *SPolicyManager) FetchEnabledPolicies() ([]SPolicy, error) {
  213. q := manager.Query().IsTrue("enabled")
  214. policies := make([]SPolicy, 0)
  215. err := db.FetchModelObjects(manager, q, &policies)
  216. if err != nil && err != sql.ErrNoRows {
  217. return nil, err
  218. }
  219. return policies, nil
  220. }
  221. func validatePolicyVioldatePrivilege(userCred mcclient.TokenCredential, policyScope rbacscope.TRbacScope, policy *rbacutils.SPolicy) error {
  222. if options.Options.NoPolicyViolationCheck || options.Options.ThreeAdminRoleSystem {
  223. return nil
  224. }
  225. if userCred.GetUserName() == api.SystemAdminUser && userCred.GetDomainId() == api.DEFAULT_DOMAIN_ID {
  226. return nil
  227. }
  228. _, policyGroup, err := RolePolicyManager.GetMatchPolicyGroup(userCred, time.Time{}, false)
  229. if err != nil {
  230. return errors.Wrap(err, "GetMatchPolicyGroup")
  231. }
  232. noViolate := false
  233. assignPolicySet := rbacutils.TPolicySet{*policy}
  234. for _, scope := range []rbacscope.TRbacScope{
  235. rbacscope.ScopeSystem,
  236. rbacscope.ScopeDomain,
  237. rbacscope.ScopeProject,
  238. } {
  239. isViolate := false
  240. policySet, ok := policyGroup[scope]
  241. if !ok || len(policySet) == 0 || !policySet.Contains(assignPolicySet) {
  242. isViolate = true
  243. }
  244. if !isViolate {
  245. noViolate = true
  246. }
  247. if scope == policyScope {
  248. break
  249. }
  250. }
  251. if !noViolate {
  252. return errors.Wrap(httperrors.ErrNotSufficientPrivilege, "policy violates operator's policy")
  253. }
  254. return nil
  255. }
  256. func (manager *SPolicyManager) ValidateCreateData(
  257. ctx context.Context,
  258. userCred mcclient.TokenCredential,
  259. ownerId mcclient.IIdentityProvider,
  260. query jsonutils.JSONObject,
  261. input api.PolicyCreateInput,
  262. ) (api.PolicyCreateInput, error) {
  263. var err error
  264. if len(input.Type) == 0 && len(input.Name) == 0 {
  265. return input, httperrors.NewInputParameterError("missing input field type")
  266. }
  267. if len(input.Name) == 0 {
  268. input.Name = input.Type
  269. }
  270. var domainTags, projectTags, objectTags tagutils.TTagSetList
  271. if len(input.OrgNodeId) > 0 {
  272. for i := range input.OrgNodeId {
  273. orgNodeObj, err := OrganizationNodeManager.FetchById(input.OrgNodeId[i])
  274. if err != nil {
  275. if errors.Cause(err) == sql.ErrNoRows {
  276. return input, httperrors.NewResourceNotFoundError2(OrganizationNodeManager.Keyword(), input.OrgNodeId[i])
  277. } else {
  278. return input, errors.Wrap(err, "OrganizationNodeManager.FetchById")
  279. }
  280. }
  281. orgNode := orgNodeObj.(*SOrganizationNode)
  282. input.OrgNodeId[i] = orgNode.Id
  283. org, err := orgNode.GetOrganization()
  284. if err != nil {
  285. return input, errors.Wrap(err, "orgNode.GetOrganization")
  286. }
  287. switch org.Type {
  288. case api.OrgTypeDomain:
  289. domainTags = domainTags.Append(orgNode.GetTagSet(org))
  290. case api.OrgTypeProject:
  291. projectTags = projectTags.Append(orgNode.GetTagSet(org))
  292. case api.OrgTypeObject:
  293. objectTags = objectTags.Append(orgNode.GetTagSet(org))
  294. }
  295. }
  296. }
  297. if len(input.DomainTags) > 0 {
  298. domainTags = domainTags.Append(input.DomainTags)
  299. }
  300. if len(input.ProjectTags) > 0 {
  301. projectTags = projectTags.Append(input.ProjectTags)
  302. }
  303. if len(input.ObjectTags) > 0 {
  304. objectTags = objectTags.Append(input.ObjectTags)
  305. }
  306. policy, err := rbacutils.DecodePolicyData(domainTags, projectTags, objectTags, input.Blob)
  307. if err != nil {
  308. return input, httperrors.NewInputParameterError("fail to decode policy data")
  309. }
  310. input.Scope = rbacscope.String2ScopeDefault(string(input.Scope), rbacscope.ScopeProject)
  311. err = validatePolicyVioldatePrivilege(userCred, input.Scope, policy)
  312. if err != nil {
  313. return input, errors.Wrap(err, "validatePolicyVioldatePrivilege")
  314. }
  315. err = db.ValidateCreateDomainId(ownerId.GetProjectDomainId())
  316. if err != nil {
  317. return input, errors.Wrap(err, "ValidateCreateDomainId")
  318. }
  319. input.EnabledIdentityBaseResourceCreateInput, err = manager.SEnabledIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledIdentityBaseResourceCreateInput)
  320. if err != nil {
  321. return input, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.ValidateCreateData")
  322. }
  323. input.SharableResourceBaseCreateInput, err = db.SharableManagerValidateCreateData(manager, ctx, userCred, ownerId, query, input.SharableResourceBaseCreateInput)
  324. if err != nil {
  325. return input, errors.Wrap(err, "SharableManagerValidateCreateData")
  326. }
  327. quota := &SIdentityQuota{
  328. SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
  329. Policy: 1,
  330. }
  331. err = quotas.CheckSetPendingQuota(ctx, userCred, quota)
  332. if err != nil {
  333. return input, errors.Wrap(err, "CheckSetPendingQuota")
  334. }
  335. requireScope := input.Scope
  336. if input.IsSystem != nil && *input.IsSystem {
  337. requireScope = rbacscope.ScopeSystem
  338. }
  339. allowScope, _ := policyman.PolicyManager.AllowScope(userCred, api.SERVICE_TYPE, manager.KeywordPlural(), policyman.PolicyActionCreate)
  340. if requireScope.HigherThan(allowScope) {
  341. return input, errors.Wrapf(httperrors.ErrNotSufficientPrivilege, "require %s allow %s", requireScope, allowScope)
  342. }
  343. return input, nil
  344. }
  345. func (policy *SPolicy) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.PolicyUpdateInput) (api.PolicyUpdateInput, error) {
  346. var requireScope rbacscope.TRbacScope
  347. if len(input.Scope) > 0 {
  348. input.Scope = rbacscope.String2ScopeDefault(string(input.Scope), rbacscope.ScopeProject)
  349. requireScope = input.Scope
  350. }
  351. if input.IsSystem != nil && *input.IsSystem {
  352. requireScope = rbacscope.ScopeSystem
  353. }
  354. if len(requireScope) > 0 {
  355. allowScope, _ := policyman.PolicyManager.AllowScope(userCred, api.SERVICE_TYPE, policy.KeywordPlural(), policyman.PolicyActionUpdate)
  356. if requireScope.HigherThan(allowScope) {
  357. return input, errors.Wrapf(httperrors.ErrNotSufficientPrivilege, "require %s allow %s", requireScope, allowScope)
  358. }
  359. }
  360. var tagChanged bool
  361. switch input.TagUpdatePolicy {
  362. case api.TAG_UPDATE_POLICY_REMOVE:
  363. var domainChanged, projectChanged, objectChanged bool
  364. input.DomainTags, domainChanged = policy.DomainTags.Remove(input.DomainTags...)
  365. input.ProjectTags, projectChanged = policy.ProjectTags.Remove(input.ProjectTags...)
  366. input.ObjectTags, objectChanged = policy.ObjectTags.Remove(input.ObjectTags...)
  367. if domainChanged || projectChanged || objectChanged {
  368. tagChanged = true
  369. }
  370. case api.TAG_UPDATE_POLICY_REPLACE:
  371. // do nothing
  372. tagChanged = true
  373. default:
  374. if len(input.DomainTags) > 0 || len(input.ProjectTags) > 0 || len(input.ObjectTags) > 0 {
  375. tagChanged = true
  376. }
  377. input.DomainTags = policy.DomainTags.Append(input.DomainTags...)
  378. input.ProjectTags = policy.ProjectTags.Append(input.ProjectTags...)
  379. input.ObjectTags = policy.ObjectTags.Append(input.ObjectTags...)
  380. }
  381. if len(input.OrgNodeId) > 0 {
  382. for i := range input.OrgNodeId {
  383. orgNode, err := OrganizationNodeManager.FetchById(input.OrgNodeId[i])
  384. if err != nil {
  385. if errors.Cause(err) == sql.ErrNoRows {
  386. return input, httperrors.NewResourceNotFoundError2(OrganizationNodeManager.Keyword(), input.OrgNodeId[i])
  387. } else {
  388. return input, errors.Wrap(err, "OrganizationNodeManager.FetchById")
  389. }
  390. }
  391. input.OrgNodeId[i] = orgNode.GetId()
  392. }
  393. }
  394. switch input.TagUpdatePolicy {
  395. case api.TAG_UPDATE_POLICY_REMOVE:
  396. if len(input.OrgNodeId) > 0 {
  397. nodeIds := make([]string, 0)
  398. for i := range policy.OrgNodeId {
  399. if !utils.IsInArray(policy.OrgNodeId[i], input.OrgNodeId) {
  400. nodeIds = append(nodeIds, policy.OrgNodeId[i])
  401. } else {
  402. tagChanged = true
  403. }
  404. }
  405. input.OrgNodeId = nodeIds
  406. }
  407. case api.TAG_UPDATE_POLICY_REPLACE:
  408. // do nothing
  409. tagChanged = true
  410. default:
  411. // add
  412. if len(input.OrgNodeId) > 0 {
  413. for i := range policy.OrgNodeId {
  414. if !utils.IsInArray(policy.OrgNodeId[i], input.OrgNodeId) {
  415. input.OrgNodeId = append(input.OrgNodeId, policy.OrgNodeId[i])
  416. tagChanged = true
  417. }
  418. }
  419. }
  420. }
  421. if input.Blob != nil || tagChanged {
  422. var domainTags, projectTags, objectTags tagutils.TTagSetList
  423. if len(input.DomainTags) > 0 {
  424. domainTags = domainTags.Append(input.DomainTags)
  425. }
  426. if len(input.ProjectTags) > 0 {
  427. projectTags = projectTags.Append(input.ProjectTags)
  428. }
  429. if len(input.ObjectTags) > 0 {
  430. objectTags = objectTags.Append(input.DomainTags)
  431. }
  432. for i := range input.OrgNodeId {
  433. orgNodeObj, err := OrganizationNodeManager.FetchById(input.OrgNodeId[i])
  434. if err != nil {
  435. return input, errors.Wrapf(err, "OrganizationNodeManager.FetchById %s", input.OrgNodeId[i])
  436. }
  437. orgNode := orgNodeObj.(*SOrganizationNode)
  438. org, err := orgNode.GetOrganization()
  439. if err != nil {
  440. return input, errors.Wrap(err, "GetOrganization")
  441. }
  442. switch org.Type {
  443. case api.OrgTypeDomain:
  444. domainTags = domainTags.Append(orgNode.GetTagSet(org))
  445. case api.OrgTypeProject:
  446. projectTags = projectTags.Append(orgNode.GetTagSet(org))
  447. case api.OrgTypeObject:
  448. objectTags = objectTags.Append(orgNode.GetTagSet(org))
  449. }
  450. }
  451. if input.Blob == nil {
  452. input.Blob = policy.Blob
  453. }
  454. p, err := rbacutils.DecodePolicyData(domainTags, projectTags, objectTags, input.Blob)
  455. if err != nil {
  456. return input, httperrors.NewInputParameterError("fail to decode policy data")
  457. }
  458. /* if p.IsSystemWidePolicy() && policyman.PolicyManager.Allow(rbacutils.ScopeSystem, userCred, consts.GetServiceType(), policy.GetModelManager().KeywordPlural(), policyman.PolicyActionUpdate) == rbacutils.Deny {
  459. return nil, httperrors.NewNotSufficientPrivilegeError("not allow to update system-wide policy")
  460. } */
  461. scope := input.Scope
  462. if len(scope) == 0 {
  463. scope = policy.Scope
  464. }
  465. err = validatePolicyVioldatePrivilege(userCred, scope, p)
  466. if err != nil {
  467. return input, errors.Wrap(err, "validatePolicyVioldatePrivilege")
  468. }
  469. }
  470. if len(input.Type) > 0 {
  471. input.Name = input.Type
  472. }
  473. var err error
  474. input.EnabledIdentityBaseUpdateInput, err = policy.SEnabledIdentityBaseResource.ValidateUpdateData(ctx, userCred, query, input.EnabledIdentityBaseUpdateInput)
  475. if err != nil {
  476. return input, errors.Wrap(err, "SEnabledIdentityBaseResource.ValidateUpdateData")
  477. }
  478. return input, nil
  479. }
  480. func (policy *SPolicy) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  481. policy.SEnabledIdentityBaseResource.PostCreate(ctx, userCred, ownerId, query, data)
  482. quota := &SIdentityQuota{
  483. SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
  484. Policy: 1,
  485. }
  486. err := quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
  487. if err != nil {
  488. log.Errorf("CancelPendingUsage fail %s", err)
  489. }
  490. // policyman.PolicyManager.SyncOnce()
  491. }
  492. func (policy *SPolicy) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  493. policy.SEnabledIdentityBaseResource.PostUpdate(ctx, userCred, query, data)
  494. // policyman.PolicyManager.SyncOnce()
  495. }
  496. func (policy *SPolicy) PostDelete(ctx context.Context, userCred mcclient.TokenCredential) {
  497. policy.SEnabledIdentityBaseResource.PostDelete(ctx, userCred)
  498. // policyman.PolicyManager.SyncOnce()
  499. }
  500. func (policy *SPolicy) IsSharable(reqUsrId mcclient.IIdentityProvider) bool {
  501. return db.SharableModelIsSharable(policy, reqUsrId)
  502. }
  503. func (policy *SPolicy) IsShared() bool {
  504. return db.SharableModelIsShared(policy)
  505. }
  506. // 共享Policy
  507. func (policy *SPolicy) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicDomainInput) (jsonutils.JSONObject, error) {
  508. err := db.SharablePerformPublic(policy, ctx, userCred, apis.PerformPublicProjectInput{PerformPublicDomainInput: input})
  509. if err != nil {
  510. return nil, errors.Wrap(err, "SharablePerformPublic")
  511. }
  512. // policyman.PolicyManager.SyncOnce()
  513. return nil, nil
  514. }
  515. // 设置policy为私有
  516. func (policy *SPolicy) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) (jsonutils.JSONObject, error) {
  517. err := db.SharablePerformPrivate(policy, ctx, userCred)
  518. if err != nil {
  519. return nil, errors.Wrap(err, "SharablePerformPrivate")
  520. }
  521. // policyman.PolicyManager.SyncOnce()
  522. return nil, nil
  523. }
  524. func (policy *SPolicy) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  525. db.SharableModelCustomizeCreate(policy, ctx, userCred, ownerId, query, data)
  526. return policy.SEnabledIdentityBaseResource.CustomizeCreate(ctx, userCred, ownerId, query, data)
  527. }
  528. func (policy *SPolicy) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  529. db.SharedResourceManager.CleanModelShares(ctx, userCred, policy)
  530. return policy.SEnabledIdentityBaseResource.RealDelete(ctx, userCred)
  531. }
  532. func (policy *SPolicy) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  533. // if policy.IsShared() {
  534. // return httperrors.NewInvalidStatusError("cannot delete shared policy")
  535. // }
  536. rps, err := RolePolicyManager.fetchByPolicyId(policy.Id)
  537. if err != nil {
  538. return errors.Wrap(err, "FetchByPolicyId")
  539. }
  540. if len(rps) > 0 {
  541. return httperrors.NewNotEmptyError("policy is in associated with %d roles", len(rps))
  542. }
  543. if policy.IsSystem.IsTrue() {
  544. return httperrors.NewForbiddenError("cannot delete system policy")
  545. }
  546. if policy.Enabled.IsTrue() {
  547. return httperrors.NewInvalidStatusError("cannot delete enabled policy")
  548. }
  549. return policy.SEnabledIdentityBaseResource.ValidateDeleteCondition(ctx, nil)
  550. }
  551. // 权限策略列表
  552. func (manager *SPolicyManager) ListItemFilter(
  553. ctx context.Context,
  554. q *sqlchemy.SQuery,
  555. userCred mcclient.TokenCredential,
  556. query api.PolicyListInput,
  557. ) (*sqlchemy.SQuery, error) {
  558. q, err := manager.SEnabledIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.EnabledIdentityBaseResourceListInput)
  559. if err != nil {
  560. return nil, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.ListItemFilter")
  561. }
  562. q, err = manager.SSharableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SharableResourceBaseListInput)
  563. if err != nil {
  564. return nil, errors.Wrap(err, "SSharableBaseResourceManager.ListItemFilter")
  565. }
  566. if len(query.RoleId) > 0 {
  567. _, err := validators.ValidateModel(ctx, userCred, RoleManager, &query.RoleId)
  568. if err != nil {
  569. return nil, err
  570. }
  571. sq := RolePolicyManager.Query("policy_id").Equals("role_id", query.RoleId).SubQuery()
  572. q = q.In("id", sq)
  573. }
  574. if len(query.Type) > 0 {
  575. q = q.In("type", query.Type)
  576. }
  577. if query.IsSystem != nil {
  578. if *query.IsSystem {
  579. q = q.IsTrue("is_system")
  580. } else {
  581. q = q.IsFalse("is_system")
  582. }
  583. }
  584. if len(query.Scope) == 0 {
  585. allowScope, _ := policyman.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policyman.PolicyActionList)
  586. query.Scope = string(allowScope)
  587. }
  588. switch query.Scope {
  589. case string(rbacscope.ScopeProject):
  590. q = q.Equals("scope", rbacscope.ScopeProject)
  591. case string(rbacscope.ScopeDomain):
  592. q = q.NotEquals("scope", rbacscope.ScopeSystem)
  593. }
  594. return q, nil
  595. }
  596. func (manager *SPolicyManager) OrderByExtraFields(
  597. ctx context.Context,
  598. q *sqlchemy.SQuery,
  599. userCred mcclient.TokenCredential,
  600. query api.PolicyListInput,
  601. ) (*sqlchemy.SQuery, error) {
  602. var err error
  603. q, err = manager.SEnabledIdentityBaseResourceManager.OrderByExtraFields(ctx, q, userCred, query.EnabledIdentityBaseResourceListInput)
  604. if err != nil {
  605. return nil, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.OrderByExtraFields")
  606. }
  607. return q, nil
  608. }
  609. func (manager *SPolicyManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  610. var err error
  611. q, err = manager.SEnabledIdentityBaseResourceManager.QueryDistinctExtraField(q, field)
  612. if err == nil {
  613. return q, nil
  614. }
  615. return q, httperrors.ErrNotFound
  616. }
  617. func (manager *SPolicyManager) FetchCustomizeColumns(
  618. ctx context.Context,
  619. userCred mcclient.TokenCredential,
  620. query jsonutils.JSONObject,
  621. objs []interface{},
  622. fields stringutils2.SSortedStrings,
  623. isList bool,
  624. ) []api.PolicyDetails {
  625. rows := make([]api.PolicyDetails, len(objs))
  626. identRows := manager.SEnabledIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  627. shareRows := manager.SSharableBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  628. for i := range rows {
  629. policy := objs[i].(*SPolicy)
  630. rows[i] = api.PolicyDetails{
  631. EnabledIdentityBaseResourceDetails: identRows[i],
  632. SharableResourceBaseInfo: shareRows[i],
  633. }
  634. {
  635. var err error
  636. rows[i].OrgNodes, err = OrganizationNodeManager.fetchOrgNodesInfo(ctx, userCred, policy.OrgNodeId, isList)
  637. if err != nil {
  638. log.Errorf("SPolicyManager.FetchCustomizeColumns fetchOrgNodesInfo fail %s", err)
  639. }
  640. }
  641. }
  642. return rows
  643. }
  644. func (policy *SPolicy) GetUsages() []db.IUsage {
  645. if policy.Deleted {
  646. return nil
  647. }
  648. usage := SIdentityQuota{Policy: 1}
  649. usage.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: policy.DomainId})
  650. return []db.IUsage{
  651. &usage,
  652. }
  653. }
  654. func (manager *SPolicyManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  655. q = db.SharableManagerFilterByOwner(ctx, manager, q, userCred, owner, scope)
  656. return q
  657. }
  658. func (policy *SPolicy) GetSharableTargetDomainIds() []string {
  659. return nil
  660. }
  661. func (policy *SPolicy) GetRequiredSharedDomainIds() []string {
  662. return []string{policy.DomainId}
  663. }
  664. func (policy *SPolicy) GetSharedDomains() []string {
  665. return db.SharableGetSharedProjects(policy, db.SharedTargetDomain)
  666. }
  667. func (policy *SPolicy) getPolicy() (*rbacutils.SPolicy, error) {
  668. var domainTags, projectTags, objectTags tagutils.TTagSetList
  669. if len(policy.DomainTags) > 0 {
  670. domainTags = domainTags.Append(policy.DomainTags)
  671. }
  672. if len(policy.ProjectTags) > 0 {
  673. projectTags = projectTags.Append(policy.ProjectTags)
  674. }
  675. if len(policy.ObjectTags) > 0 {
  676. objectTags = objectTags.Append(policy.ObjectTags)
  677. }
  678. var errs []error
  679. for i := range policy.OrgNodeId {
  680. orgNodeObj, err := OrganizationNodeManager.FetchById(policy.OrgNodeId[i])
  681. if err != nil {
  682. errs = append(errs, err)
  683. } else {
  684. orgNode := orgNodeObj.(*SOrganizationNode)
  685. org, err := orgNode.GetOrganization()
  686. if err != nil {
  687. errs = append(errs, err)
  688. } else {
  689. switch org.Type {
  690. case api.OrgTypeDomain:
  691. domainTags = domainTags.Append(orgNode.GetTagSet(org))
  692. case api.OrgTypeProject:
  693. projectTags = projectTags.Append(orgNode.GetTagSet(org))
  694. case api.OrgTypeObject:
  695. objectTags = objectTags.Append(orgNode.GetTagSet(org))
  696. }
  697. }
  698. }
  699. }
  700. pc, err := rbacutils.DecodePolicyData(domainTags, projectTags, objectTags, policy.Blob)
  701. if err != nil {
  702. return nil, errors.Wrap(err, "Decode")
  703. }
  704. return pc, nil
  705. }
  706. func (policy *SPolicy) GetChangeOwnerCandidateDomainIds() []string {
  707. return db.ISharableChangeOwnerCandidateDomainIds(policy)
  708. }
  709. func (policy *SPolicy) fetchMatchableRoles() ([]SRole, error) {
  710. q := RoleManager.Query()
  711. candDomains := policy.GetChangeOwnerCandidateDomainIds()
  712. if len(candDomains) > 0 {
  713. q = q.In("domain_id", candDomains)
  714. }
  715. roles := make([]SRole, 0)
  716. err := db.FetchModelObjects(RoleManager, q, &roles)
  717. if err != nil && errors.Cause(err) != sql.ErrNoRows {
  718. return nil, errors.Wrap(err, "FetchRoles")
  719. }
  720. return roles, nil
  721. }
  722. // 绑定角色
  723. func (policy *SPolicy) PerformBindRole(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.PolicyBindRoleInput) (jsonutils.JSONObject, error) {
  724. var projectId string
  725. prefList := make([]netutils.IPV4Prefix, 0)
  726. for _, ipStr := range input.Ips {
  727. pref, err := netutils.NewIPV4Prefix(ipStr)
  728. if err != nil {
  729. return nil, errors.Wrapf(httperrors.ErrInputParameter, "invalid prefix %s", ipStr)
  730. }
  731. prefList = append(prefList, pref)
  732. }
  733. if len(input.ProjectId) > 0 {
  734. proj, err := ProjectManager.FetchByIdOrName(ctx, userCred, input.ProjectId)
  735. if err != nil {
  736. if errors.Cause(err) == sql.ErrNoRows {
  737. return nil, errors.Wrapf(httperrors.ErrNotFound, "%s %s", ProjectManager.Keyword(), input.ProjectId)
  738. } else {
  739. return nil, errors.Wrap(err, "ProjectManager.FetchByIdOrName")
  740. }
  741. }
  742. projectId = proj.GetId()
  743. }
  744. if len(input.RoleId) == 0 {
  745. return nil, errors.Wrap(httperrors.ErrInputParameter, "missing role_id")
  746. }
  747. role, err := RoleManager.FetchByIdOrName(ctx, userCred, input.RoleId)
  748. if err != nil {
  749. if errors.Cause(err) == sql.ErrNoRows {
  750. return nil, errors.Wrapf(httperrors.ErrNotFound, "%s %s", RoleManager.Keyword(), input.RoleId)
  751. } else {
  752. return nil, errors.Wrap(err, "RoleManager.FetchByIdOrName")
  753. }
  754. }
  755. err = RolePolicyManager.newRecord(ctx, role.GetId(), projectId, policy.Id, tristate.True, prefList, input.ValidSince, input.ValidUntil)
  756. if err != nil {
  757. return nil, errors.Wrap(err, "newRecord")
  758. }
  759. return nil, nil
  760. }
  761. func (policy *SPolicy) GetI18N(ctx context.Context) *jsonutils.JSONDict {
  762. r := jsonutils.NewDict()
  763. act18 := locale.PredefinedPolicyI18nTable.Lookup(ctx, policy.Description)
  764. r.Set("description", jsonutils.NewString(act18))
  765. return r
  766. }
  767. func (policy *SPolicy) ValidateUpdateCondition(ctx context.Context) error {
  768. err := policy.SEnabledIdentityBaseResource.ValidateUpdateCondition(ctx)
  769. if err != nil {
  770. return errors.Wrap(err, "SEnabledIdentityBaseResource.ValidateUpdateCondition")
  771. }
  772. //if policy.IsSystem.IsTrue() {
  773. // return errors.Wrap(httperrors.ErrForbidden, "system policy")
  774. //}
  775. if options.Options.ThreeAdminRoleSystem {
  776. rps, err := RolePolicyManager.fetchByPolicyId(policy.Id)
  777. if err != nil {
  778. return errors.Wrap(err, "fetchByPolicyId")
  779. }
  780. if len(rps) > 0 {
  781. return errors.Wrap(httperrors.ErrForbidden, "policy in use")
  782. }
  783. }
  784. return nil
  785. }