roles.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  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. "fmt"
  19. "time"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/gotypes"
  24. "yunion.io/x/pkg/tristate"
  25. "yunion.io/x/pkg/util/netutils"
  26. "yunion.io/x/pkg/util/rbacscope"
  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/db"
  31. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  32. "yunion.io/x/onecloud/pkg/httperrors"
  33. "yunion.io/x/onecloud/pkg/keystone/locale"
  34. "yunion.io/x/onecloud/pkg/mcclient"
  35. "yunion.io/x/onecloud/pkg/util/stringutils2"
  36. )
  37. type SRoleManager struct {
  38. SIdentityBaseResourceManager
  39. db.SSharableBaseResourceManager
  40. }
  41. var RoleManager *SRoleManager
  42. func init() {
  43. RoleManager = &SRoleManager{
  44. SIdentityBaseResourceManager: NewIdentityBaseResourceManager(
  45. SRole{},
  46. "role",
  47. "role",
  48. "roles",
  49. ),
  50. }
  51. RoleManager.SetVirtualObject(RoleManager)
  52. }
  53. /*
  54. +------------+--------------+------+-----+----------+-------+
  55. | Field | Type | Null | Key | Default | Extra |
  56. +------------+--------------+------+-----+----------+-------+
  57. | id | varchar(64) | NO | PRI | NULL | |
  58. | name | varchar(255) | NO | MUL | NULL | |
  59. | extra | text | YES | | NULL | |
  60. | domain_id | varchar(64) | NO | | <<null>> | |
  61. | created_at | datetime | YES | | NULL | |
  62. +------------+--------------+------+-----+----------+-------+
  63. */
  64. type SRole struct {
  65. SIdentityBaseResource `"name->update":""`
  66. db.SSharableBaseResource `"is_public->create":"domain_optional" "public_scope->create":"domain_optional"`
  67. }
  68. func (manager *SRoleManager) GetContextManagers() [][]db.IModelManager {
  69. return [][]db.IModelManager{
  70. {ProjectManager, UserManager},
  71. {ProjectManager, GroupManager},
  72. }
  73. }
  74. const (
  75. ROLE_DEFAULT_DOMAIN_ID = "<<null>>"
  76. )
  77. func (manager *SRoleManager) InitializeData() error {
  78. q := manager.Query()
  79. q = q.IsNull("description").IsNotNull("extra")
  80. roles := make([]SRole, 0)
  81. err := db.FetchModelObjects(manager, q, &roles)
  82. if err != nil {
  83. return errors.Wrap(err, "query")
  84. }
  85. for i := range roles {
  86. if gotypes.IsNil(roles[i].Extra) {
  87. continue
  88. }
  89. desc, _ := roles[i].Extra.GetString("description")
  90. _, err = db.Update(&roles[i], func() error {
  91. roles[i].Description = desc
  92. return nil
  93. })
  94. if err != nil {
  95. return errors.Wrap(err, "update description")
  96. }
  97. }
  98. err = manager.initializeDomainId()
  99. if err != nil {
  100. return errors.Wrap(err, "InitializeDomainId")
  101. }
  102. err = manager.initSysRole(context.TODO())
  103. if err != nil {
  104. return errors.Wrap(err, "initSysRole")
  105. }
  106. return nil
  107. }
  108. func (manager *SRoleManager) initializeDomainId() error {
  109. q := manager.Query().Equals("domain_id", ROLE_DEFAULT_DOMAIN_ID)
  110. roles := make([]SRole, 0)
  111. err := db.FetchModelObjects(manager, q, &roles)
  112. if err != nil {
  113. return err
  114. }
  115. for i := range roles {
  116. db.Update(&roles[i], func() error {
  117. roles[i].DomainId = api.DEFAULT_DOMAIN_ID
  118. return nil
  119. })
  120. }
  121. return nil
  122. }
  123. func (manager *SRoleManager) initSysRole(ctx context.Context) error {
  124. q := manager.Query().Equals("name", api.SystemAdminRole)
  125. q = q.Equals("domain_id", api.DEFAULT_DOMAIN_ID)
  126. cnt, err := q.CountWithError()
  127. if err != nil {
  128. return errors.Wrap(err, "query")
  129. }
  130. if cnt == 1 {
  131. return nil
  132. }
  133. if cnt > 2 {
  134. // ???
  135. log.Fatalf("duplicate system role???")
  136. }
  137. // insert
  138. role := SRole{}
  139. role.Name = api.SystemAdminRole
  140. role.IsPublic = true
  141. role.PublicScope = string(rbacscope.ScopeSystem)
  142. role.DomainId = api.DEFAULT_DOMAIN_ID
  143. role.Description = "Boostrap system default admin role"
  144. role.SetModelManager(manager, &role)
  145. err = manager.TableSpec().Insert(ctx, &role)
  146. if err != nil {
  147. return errors.Wrap(err, "insert")
  148. }
  149. return nil
  150. }
  151. func (role *SRole) GetUserCount() (int, error) {
  152. q := AssignmentManager.fetchRoleUserIdsQuery(role.Id)
  153. return q.CountWithError()
  154. }
  155. func (role *SRole) GetGroupCount() (int, error) {
  156. q := AssignmentManager.fetchRoleGroupIdsQuery(role.Id)
  157. return q.CountWithError()
  158. }
  159. func (role *SRole) GetProjectCount() (int, error) {
  160. q := AssignmentManager.fetchRoleProjectIdsQuery(role.Id)
  161. return q.CountWithError()
  162. }
  163. func (role *SRole) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RoleUpdateInput) (api.RoleUpdateInput, error) {
  164. if len(input.Name) > 0 {
  165. return input, httperrors.NewForbiddenError("cannot alter name of role")
  166. }
  167. var err error
  168. input.IdentityBaseUpdateInput, err = role.SIdentityBaseResource.ValidateUpdateData(ctx, userCred, query, input.IdentityBaseUpdateInput)
  169. if err != nil {
  170. return input, errors.Wrap(err, "SIdentityBaseResource.ValidateUpdateData")
  171. }
  172. return input, nil
  173. }
  174. func (role *SRole) IsSystemRole() bool {
  175. return role.Name == api.SystemAdminRole && role.DomainId == api.DEFAULT_DOMAIN_ID
  176. }
  177. func (role *SRole) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  178. // if role.IsShared() {
  179. // return httperrors.NewInvalidStatusError("cannot delete shared role")
  180. // }
  181. if role.IsSystemRole() {
  182. return httperrors.NewForbiddenError("cannot delete system role")
  183. }
  184. usrCnt, _ := role.GetUserCount()
  185. if usrCnt > 0 {
  186. return httperrors.NewNotEmptyError("role is being assigned to user")
  187. }
  188. grpCnt, _ := role.GetGroupCount()
  189. if grpCnt > 0 {
  190. return httperrors.NewNotEmptyError("role is being assigned to group")
  191. }
  192. rps, err := RolePolicyManager.fetchByRoleId(role.Id)
  193. if err != nil {
  194. return errors.Wrap(err, "FetchByRoleId")
  195. }
  196. if len(rps) > 0 {
  197. return httperrors.NewNotEmptyError("role is in associated with %d policies", len(rps))
  198. }
  199. return role.SIdentityBaseResource.ValidateDeleteCondition(ctx, nil)
  200. }
  201. func (manager *SRoleManager) FetchCustomizeColumns(
  202. ctx context.Context,
  203. userCred mcclient.TokenCredential,
  204. query jsonutils.JSONObject,
  205. objs []interface{},
  206. fields stringutils2.SSortedStrings,
  207. isList bool,
  208. ) []api.RoleDetails {
  209. rows := make([]api.RoleDetails, len(objs))
  210. identRows := manager.SIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  211. shareRows := manager.SSharableBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  212. for i := range rows {
  213. rows[i] = api.RoleDetails{
  214. IdentityBaseResourceDetails: identRows[i],
  215. SharableResourceBaseInfo: shareRows[i],
  216. }
  217. role := objs[i].(*SRole)
  218. rows[i].UserCount, _ = role.GetUserCount()
  219. rows[i].GroupCount, _ = role.GetGroupCount()
  220. rows[i].ProjectCount, _ = role.GetProjectCount()
  221. names, _, _ := RolePolicyManager.GetMatchPolicyGroup2(false, []string{role.Id}, "", "", time.Time{}, true)
  222. rows[i].Policies = names
  223. mp := make([]string, 0)
  224. for _, v := range names {
  225. mp = append(mp, v...)
  226. }
  227. rows[i].MatchPolicies = mp
  228. }
  229. return rows
  230. }
  231. // 角色列表
  232. func (manager *SRoleManager) ListItemFilter(
  233. ctx context.Context,
  234. q *sqlchemy.SQuery,
  235. userCred mcclient.TokenCredential,
  236. query api.RoleListInput,
  237. ) (*sqlchemy.SQuery, error) {
  238. var err error
  239. q, err = manager.SIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.IdentityBaseResourceListInput)
  240. if err != nil {
  241. return nil, errors.Wrap(err, "SIdentityBaseResourceManager.ListItemFilter")
  242. }
  243. q, err = manager.SSharableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SharableResourceBaseListInput)
  244. if err != nil {
  245. return nil, errors.Wrap(err, "SSharableBaseResourceManager.ListItemFilter")
  246. }
  247. var projectId string
  248. projectStr := query.ProjectId
  249. if len(projectStr) > 0 {
  250. project, err := ProjectManager.FetchProjectById(projectStr)
  251. if err != nil {
  252. if err == sql.ErrNoRows {
  253. return nil, httperrors.NewResourceNotFoundError2(ProjectManager.Keyword(), projectStr)
  254. } else {
  255. return nil, httperrors.NewGeneralError(err)
  256. }
  257. }
  258. projectId = project.Id
  259. }
  260. userStr := query.UserId
  261. if len(projectId) > 0 && len(userStr) > 0 {
  262. userObj, err := UserManager.FetchById(userStr)
  263. if err != nil {
  264. if err == sql.ErrNoRows {
  265. return nil, httperrors.NewResourceNotFoundError2(UserManager.Keyword(), userStr)
  266. } else {
  267. return nil, httperrors.NewGeneralError(err)
  268. }
  269. }
  270. subq := AssignmentManager.fetchUserProjectRoleIdsQuery(userObj.GetId(), projectId)
  271. q = q.In("id", subq.SubQuery())
  272. }
  273. groupStr := query.GroupId
  274. if len(projectId) > 0 && len(groupStr) > 0 {
  275. groupObj, err := GroupManager.FetchById(groupStr)
  276. if err != nil {
  277. if err == sql.ErrNoRows {
  278. return nil, httperrors.NewResourceNotFoundError2(GroupManager.Keyword(), groupStr)
  279. } else {
  280. return nil, httperrors.NewGeneralError(err)
  281. }
  282. }
  283. subq := AssignmentManager.fetchGroupProjectRoleIdsQuery(groupObj.GetId(), projectId)
  284. q = q.In("id", subq.SubQuery())
  285. }
  286. return q, nil
  287. }
  288. func (manager *SRoleManager) OrderByExtraFields(
  289. ctx context.Context,
  290. q *sqlchemy.SQuery,
  291. userCred mcclient.TokenCredential,
  292. query api.RoleListInput,
  293. ) (*sqlchemy.SQuery, error) {
  294. var err error
  295. q, err = manager.SIdentityBaseResourceManager.OrderByExtraFields(ctx, q, userCred, query.IdentityBaseResourceListInput)
  296. if err != nil {
  297. return nil, errors.Wrap(err, "SIdentityBaseResourceManager.OrderByExtraFields")
  298. }
  299. return q, nil
  300. }
  301. func (manager *SRoleManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  302. var err error
  303. q, err = manager.SIdentityBaseResourceManager.QueryDistinctExtraField(q, field)
  304. if err == nil {
  305. return q, nil
  306. }
  307. return q, httperrors.ErrNotFound
  308. }
  309. func (role *SRole) UpdateInContext(ctx context.Context, userCred mcclient.TokenCredential, ctxObjs []db.IModel, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  310. if len(ctxObjs) != 2 {
  311. return nil, httperrors.NewInputParameterError("not supported update context")
  312. }
  313. project, ok := ctxObjs[0].(*SProject)
  314. if !ok {
  315. return nil, httperrors.NewInputParameterError("not supported update context %s", ctxObjs[0].Keyword())
  316. }
  317. if project.DomainId != role.DomainId {
  318. projectOwner := &db.SOwnerId{
  319. ProjectId: project.Id,
  320. DomainId: project.DomainId,
  321. }
  322. if !role.IsSharable(projectOwner) {
  323. return nil, httperrors.NewInputParameterError("inconsistent domain for project and roles")
  324. }
  325. }
  326. err := validateJoinProject(userCred, project, []string{role.Id})
  327. if err != nil {
  328. return nil, errors.Wrap(err, "validateJoinProject")
  329. }
  330. switch obj := ctxObjs[1].(type) {
  331. case *SUser:
  332. return nil, AssignmentManager.ProjectAddUser(ctx, userCred, project, obj, role)
  333. case *SGroup:
  334. return nil, AssignmentManager.projectAddGroup(ctx, userCred, project, obj, role)
  335. default:
  336. return nil, httperrors.NewInputParameterError("not supported secondary update context %s", ctxObjs[0].Keyword())
  337. }
  338. }
  339. func (role *SRole) DeleteInContext(ctx context.Context, userCred mcclient.TokenCredential, ctxObjs []db.IModel, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  340. if len(ctxObjs) != 2 {
  341. return nil, httperrors.NewInputParameterError("not supported update context")
  342. }
  343. project, ok := ctxObjs[0].(*SProject)
  344. if !ok {
  345. return nil, httperrors.NewInputParameterError("not supported update context %s", ctxObjs[0].Keyword())
  346. }
  347. switch obj := ctxObjs[1].(type) {
  348. case *SUser:
  349. return nil, AssignmentManager.projectRemoveUser(ctx, userCred, project, obj, role)
  350. case *SGroup:
  351. return nil, AssignmentManager.projectRemoveGroup(ctx, userCred, project, obj, role)
  352. default:
  353. return nil, httperrors.NewInputParameterError("not supported secondary update context %s", ctxObjs[0].Keyword())
  354. }
  355. }
  356. func (manager *SRoleManager) FetchRoleByName(roleName string, domainId, domainName string) (*SRole, error) {
  357. obj, err := db.NewModelObject(manager)
  358. if err != nil {
  359. return nil, err
  360. }
  361. domain, err := DomainManager.FetchDomain(domainId, domainName)
  362. if err != nil {
  363. return nil, err
  364. }
  365. q := manager.Query().Equals("name", roleName).Equals("domain_id", domain.Id)
  366. err = q.First(obj)
  367. if err != nil {
  368. return nil, err
  369. }
  370. return obj.(*SRole), err
  371. }
  372. func (manager *SRoleManager) FetchRoleById(roleId string) (*SRole, error) {
  373. obj, err := db.NewModelObject(manager)
  374. if err != nil {
  375. return nil, err
  376. }
  377. q := manager.Query().Equals("id", roleId)
  378. err = q.First(obj)
  379. if err != nil {
  380. return nil, err
  381. }
  382. return obj.(*SRole), err
  383. }
  384. func (manager *SRoleManager) FetchRole(roleId, roleName string, domainId, domainName string) (*SRole, error) {
  385. if len(roleId) > 0 {
  386. return manager.FetchRoleById(roleId)
  387. }
  388. if len(roleName) > 0 {
  389. return manager.FetchRoleByName(roleName, domainId, domainName)
  390. }
  391. return nil, fmt.Errorf("no role Id or name provided")
  392. }
  393. func (role *SRole) IsShared() bool {
  394. return db.SharableModelIsShared(role)
  395. }
  396. func (role *SRole) IsSharable(reqUsrId mcclient.IIdentityProvider) bool {
  397. return db.SharableModelIsSharable(role, reqUsrId)
  398. }
  399. func (role *SRole) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicDomainInput) (jsonutils.JSONObject, error) {
  400. err := db.SharablePerformPublic(role, ctx, userCred, apis.PerformPublicProjectInput{PerformPublicDomainInput: input})
  401. if err != nil {
  402. return nil, errors.Wrap(err, "SharablePerformPublic")
  403. }
  404. return nil, nil
  405. }
  406. func (role *SRole) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) (jsonutils.JSONObject, error) {
  407. err := db.SharablePerformPrivate(role, ctx, userCred)
  408. if err != nil {
  409. return nil, errors.Wrap(err, "SharablePerformPrivate")
  410. }
  411. return nil, nil
  412. }
  413. func (role *SRole) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  414. db.SharableModelCustomizeCreate(role, ctx, userCred, ownerId, query, data)
  415. return role.SIdentityBaseResource.CustomizeCreate(ctx, userCred, ownerId, query, data)
  416. }
  417. func (role *SRole) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  418. db.SharedResourceManager.CleanModelShares(ctx, userCred, role)
  419. return role.SIdentityBaseResource.RealDelete(ctx, userCred)
  420. }
  421. func (manager *SRoleManager) ValidateCreateData(
  422. ctx context.Context,
  423. userCred mcclient.TokenCredential,
  424. ownerId mcclient.IIdentityProvider,
  425. query jsonutils.JSONObject,
  426. input api.RoleCreateInput,
  427. ) (api.RoleCreateInput, error) {
  428. err := db.ValidateCreateDomainId(ownerId.GetProjectDomainId())
  429. if err != nil {
  430. return input, errors.Wrap(err, "ValidateCreateDomainId")
  431. }
  432. input.IdentityBaseResourceCreateInput, err = manager.SIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input.IdentityBaseResourceCreateInput)
  433. if err != nil {
  434. return input, errors.Wrap(err, "SIdentityBaseResourceManager.ValidateCreateData")
  435. }
  436. input.SharableResourceBaseCreateInput, err = db.SharableManagerValidateCreateData(manager, ctx, userCred, ownerId, query, input.SharableResourceBaseCreateInput)
  437. if err != nil {
  438. return input, errors.Wrap(err, "SharableManagerValidateCreateData")
  439. }
  440. quota := &SIdentityQuota{
  441. SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
  442. Role: 1,
  443. }
  444. err = quotas.CheckSetPendingQuota(ctx, userCred, quota)
  445. if err != nil {
  446. return input, errors.Wrap(err, "CheckSetPendingQuota")
  447. }
  448. return input, nil
  449. }
  450. func (role *SRole) GetUsages() []db.IUsage {
  451. if role.Deleted {
  452. return nil
  453. }
  454. usage := SIdentityQuota{Role: 1}
  455. usage.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: role.DomainId})
  456. return []db.IUsage{
  457. &usage,
  458. }
  459. }
  460. func (role *SRole) PostCreate(
  461. ctx context.Context,
  462. userCred mcclient.TokenCredential,
  463. ownerId mcclient.IIdentityProvider,
  464. query jsonutils.JSONObject,
  465. data jsonutils.JSONObject,
  466. ) {
  467. role.SIdentityBaseResource.PostCreate(ctx, userCred, ownerId, query, data)
  468. quota := &SIdentityQuota{
  469. SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
  470. Role: 1,
  471. }
  472. err := quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
  473. if err != nil {
  474. log.Errorf("CancelPendingUsage fail %s", err)
  475. }
  476. }
  477. func (manager *SRoleManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  478. return db.SharableManagerFilterByOwner(ctx, manager, q, userCred, owner, scope)
  479. }
  480. func (role *SRole) GetSharableTargetDomainIds() []string {
  481. return nil
  482. }
  483. func (role *SRole) GetRequiredSharedDomainIds() []string {
  484. return []string{role.DomainId}
  485. }
  486. func (role *SRole) GetSharedDomains() []string {
  487. return db.SharableGetSharedProjects(role, db.SharedTargetDomain)
  488. }
  489. func validateRolePolicies(userCred mcclient.TokenCredential, policyIds []string) error {
  490. _, assignPolicies, err := RolePolicyManager.GetPolicyGroupByIds(policyIds, false)
  491. if err != nil {
  492. return errors.Wrapf(err, "RolePolicyManager.GetPolicyGroupByIds %s", policyIds)
  493. }
  494. return validateAssignPolicies(userCred, "", assignPolicies)
  495. }
  496. func (role *SRole) PerformSetPolicies(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RolePerformSetPoliciesInput) (jsonutils.JSONObject, error) {
  497. if len(input.Action) == 0 {
  498. input.Action = api.ROLE_SET_POLICY_ACTION_DEFAULT
  499. }
  500. inputPolicyIds := stringutils2.NewSortedStrings(nil)
  501. normalInputIds := stringutils2.NewSortedStrings(nil)
  502. normalInputs := make(map[string]sRolePerformAddPolicyInput, len(input.Policies))
  503. for i := range input.Policies {
  504. normalInput, err := role.normalizeRoleAddPolicyInput(ctx, userCred, input.Policies[i])
  505. if err != nil {
  506. return nil, errors.Wrapf(err, "normalizeRoleAddPolicyInput at %d", i)
  507. }
  508. inputPolicyIds = stringutils2.Append(inputPolicyIds, normalInput.policyId)
  509. idstr := normalInput.getId()
  510. if _, ok := normalInputs[idstr]; !ok {
  511. normalInputs[idstr] = normalInput
  512. normalInputIds = stringutils2.Append(normalInputIds, idstr)
  513. } else {
  514. log.Warningf("duplicate input key id %s", idstr)
  515. }
  516. }
  517. existRpList, err := RolePolicyManager.fetchByRoleId(role.Id)
  518. if err != nil {
  519. return nil, errors.Wrap(err, "RolePolicyManager.fetchByRoleId")
  520. }
  521. existPolicyIds := stringutils2.NewSortedStrings(nil)
  522. existRpIds := stringutils2.NewSortedStrings(nil)
  523. existRpMap := make(map[string]*SRolePolicy)
  524. for i := range existRpList {
  525. existPolicyIds = stringutils2.Append(existPolicyIds, existRpList[i].PolicyId)
  526. idstr := existRpList[i].GetId()
  527. if _, ok := existRpMap[idstr]; !ok {
  528. existRpMap[idstr] = &existRpList[i]
  529. existRpIds = stringutils2.Append(existRpIds, idstr)
  530. }
  531. }
  532. addedIds, updatedIds, deletedIds := stringutils2.Split(normalInputIds, existRpIds)
  533. isBootStrap, err := RolePolicyManager.isBootstrapRolePolicy()
  534. if !isBootStrap {
  535. // validate
  536. var newPolicyIds []string
  537. if input.Action == api.ROLE_SET_POLICY_ACTION_REPLACE {
  538. newPolicyIds = inputPolicyIds
  539. } else {
  540. newPolicyIds = stringutils2.Append(newPolicyIds, inputPolicyIds...)
  541. newPolicyIds = stringutils2.Append(newPolicyIds, existPolicyIds...)
  542. }
  543. err = validateRolePolicies(userCred, newPolicyIds)
  544. if err != nil {
  545. return nil, errors.Wrap(err, "validateRolePolicies")
  546. }
  547. }
  548. if input.Action == api.ROLE_SET_POLICY_ACTION_REPLACE {
  549. for _, idstr := range deletedIds {
  550. toDel := existRpMap[idstr]
  551. err := RolePolicyManager.deleteRecord(ctx, toDel.RoleId, toDel.ProjectId, toDel.PolicyId)
  552. if err != nil {
  553. return nil, errors.Wrap(err, "RolePolicyManager.deleteRecord")
  554. }
  555. }
  556. }
  557. for _, idstr := range updatedIds {
  558. toUpdate := normalInputs[idstr]
  559. err := RolePolicyManager.newRecord(ctx, toUpdate.roleId, toUpdate.projectId, toUpdate.policyId, tristate.True, toUpdate.prefixes, toUpdate.validSince, toUpdate.validUntil)
  560. if err != nil {
  561. return nil, errors.Wrap(err, "RolePolicyManager.updateRecord")
  562. }
  563. }
  564. for _, idstr := range addedIds {
  565. toAdd := normalInputs[idstr]
  566. err := RolePolicyManager.newRecord(ctx, toAdd.roleId, toAdd.projectId, toAdd.policyId, tristate.True, toAdd.prefixes, toAdd.validSince, toAdd.validUntil)
  567. if err != nil {
  568. return nil, errors.Wrap(err, "RolePolicyManager.newRecord")
  569. }
  570. }
  571. return nil, nil
  572. }
  573. type sRolePerformAddPolicyInput struct {
  574. prefixes []netutils.IPV4Prefix
  575. roleId string
  576. projectId string
  577. policyId string
  578. validSince time.Time
  579. validUntil time.Time
  580. }
  581. func (s sRolePerformAddPolicyInput) getId() string {
  582. return fmt.Sprintf("%s:%s:%s", s.roleId, s.projectId, s.policyId)
  583. }
  584. func (role *SRole) normalizeRoleAddPolicyInput(ctx context.Context, userCred mcclient.TokenCredential, input api.RolePerformAddPolicyInput) (sRolePerformAddPolicyInput, error) {
  585. output := sRolePerformAddPolicyInput{}
  586. prefList := make([]netutils.IPV4Prefix, 0)
  587. for _, ipStr := range input.Ips {
  588. pref, err := netutils.NewIPV4Prefix(ipStr)
  589. if err != nil {
  590. return output, errors.Wrapf(httperrors.ErrInputParameter, "invalid prefix %s", ipStr)
  591. }
  592. prefList = append(prefList, pref)
  593. }
  594. if len(input.ProjectId) > 0 {
  595. proj, err := ProjectManager.FetchByIdOrName(ctx, userCred, input.ProjectId)
  596. if err != nil {
  597. if errors.Cause(err) == sql.ErrNoRows {
  598. return output, errors.Wrapf(httperrors.ErrNotFound, "%s %s", ProjectManager.Keyword(), input.ProjectId)
  599. } else {
  600. return output, errors.Wrap(err, "ProjectManager.FetchByIdOrName")
  601. }
  602. }
  603. output.projectId = proj.GetId()
  604. }
  605. if len(input.PolicyId) == 0 {
  606. return output, errors.Wrap(httperrors.ErrInputParameter, "missing policy_id")
  607. }
  608. policy, err := PolicyManager.FetchByIdOrName(ctx, userCred, input.PolicyId)
  609. if err != nil {
  610. if errors.Cause(err) == sql.ErrNoRows {
  611. return output, errors.Wrapf(httperrors.ErrNotFound, "%s %s", PolicyManager.Keyword(), input.PolicyId)
  612. } else {
  613. return output, errors.Wrap(err, "PolicyManager.FetchByIdOrName")
  614. }
  615. }
  616. output.roleId = role.Id
  617. output.prefixes = prefList
  618. output.policyId = policy.GetId()
  619. output.validSince = input.ValidSince
  620. output.validUntil = input.ValidUntil
  621. return output, nil
  622. }
  623. func (role *SRole) PerformAddPolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RolePerformAddPolicyInput) (jsonutils.JSONObject, error) {
  624. normalInput, err := role.normalizeRoleAddPolicyInput(ctx, userCred, input)
  625. if err != nil {
  626. return nil, errors.Wrap(err, "normalizeRoleAddPolicyInput")
  627. }
  628. isBootStrap, err := RolePolicyManager.isBootstrapRolePolicy()
  629. if !isBootStrap {
  630. // validate
  631. rps, err := RolePolicyManager.fetchByRoleId(role.Id)
  632. if err != nil {
  633. return nil, errors.Wrap(err, "fetchByRoleId")
  634. }
  635. newPolicyIds := stringutils2.NewSortedStrings(nil)
  636. for i := range rps {
  637. newPolicyIds = stringutils2.Append(newPolicyIds, rps[i].PolicyId)
  638. }
  639. newPolicyIds = stringutils2.Append(newPolicyIds, normalInput.policyId)
  640. err = validateRolePolicies(userCred, newPolicyIds)
  641. if err != nil {
  642. return nil, errors.Wrap(err, "validateRolePolicies")
  643. }
  644. }
  645. err = RolePolicyManager.newRecord(ctx, normalInput.roleId, normalInput.projectId, normalInput.policyId, tristate.True, normalInput.prefixes, normalInput.validSince, normalInput.validUntil)
  646. if err != nil {
  647. return nil, errors.Wrap(err, "newRecord")
  648. }
  649. return nil, nil
  650. }
  651. func (role *SRole) PerformRemovePolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.RolePerformRemovePolicyInput) (jsonutils.JSONObject, error) {
  652. if len(input.ProjectId) > 0 {
  653. proj, err := ProjectManager.FetchByIdOrName(ctx, userCred, input.ProjectId)
  654. if err != nil {
  655. if errors.Cause(err) == sql.ErrNoRows {
  656. return nil, errors.Wrapf(httperrors.ErrNotFound, "%s %s", ProjectManager.Keyword(), input.ProjectId)
  657. } else {
  658. return nil, errors.Wrap(err, "ProjectManager.FetchByIdOrName")
  659. }
  660. }
  661. input.ProjectId = proj.GetId()
  662. }
  663. if len(input.PolicyId) == 0 {
  664. return nil, errors.Wrap(httperrors.ErrInputParameter, "missing policy_id")
  665. }
  666. policy, err := PolicyManager.FetchByIdOrName(ctx, userCred, input.PolicyId)
  667. if err != nil {
  668. if errors.Cause(err) == sql.ErrNoRows {
  669. return nil, errors.Wrapf(httperrors.ErrNotFound, "%s %s", PolicyManager.Keyword(), input.PolicyId)
  670. } else {
  671. return nil, errors.Wrap(err, "PolicyManager.FetchByIdOrName")
  672. }
  673. }
  674. err = RolePolicyManager.deleteRecord(ctx, role.Id, input.ProjectId, policy.GetId())
  675. if err != nil {
  676. return nil, errors.Wrap(err, "deleteRecord")
  677. }
  678. return nil, nil
  679. }
  680. func (role *SRole) GetChangeOwnerCandidateDomainIds() []string {
  681. return db.ISharableChangeOwnerCandidateDomainIds(role)
  682. }
  683. func (role *SRole) GetI18N(ctx context.Context) *jsonutils.JSONDict {
  684. r := jsonutils.NewDict()
  685. act18 := locale.PredefinedRoleI18nTable.Lookup(ctx, role.Description)
  686. r.Set("description", jsonutils.NewString(act18))
  687. return r
  688. }