mod_roleassignments.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  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 identity
  15. import (
  16. "fmt"
  17. "yunion.io/x/jsonutils"
  18. "yunion.io/x/pkg/errors"
  19. "yunion.io/x/pkg/util/rbacscope"
  20. "yunion.io/x/pkg/utils"
  21. "yunion.io/x/onecloud/pkg/httperrors"
  22. "yunion.io/x/onecloud/pkg/mcclient"
  23. "yunion.io/x/onecloud/pkg/mcclient/modulebase"
  24. "yunion.io/x/onecloud/pkg/mcclient/modules"
  25. )
  26. type RoleAssignmentManagerV3 struct {
  27. modulebase.ResourceManager
  28. }
  29. type role struct {
  30. id string
  31. name string
  32. domain struct {
  33. id string
  34. name string
  35. }
  36. }
  37. type projectRoles struct {
  38. id string
  39. name string
  40. domain struct {
  41. id string
  42. name string
  43. }
  44. typ string
  45. roles []role
  46. }
  47. func newProjectRoles(projectId, projectName, projectDomainId, projectDomainName, roleId, roleName, roleDomainId, roleDomainName, typ string) *projectRoles {
  48. r := role{
  49. id: roleId,
  50. name: roleName,
  51. }
  52. r.domain.id = roleDomainId
  53. r.domain.name = roleDomainName
  54. pr := &projectRoles{id: projectId, name: projectName, typ: typ, roles: []role{r}}
  55. pr.domain.id = projectDomainId
  56. pr.domain.name = projectDomainName
  57. return pr
  58. }
  59. func (this *projectRoles) add(roleId, roleName, roleDomainId, roleDomainName string) {
  60. r := role{id: roleId, name: roleName}
  61. r.domain.id = roleDomainId
  62. r.domain.name = roleDomainName
  63. this.roles = append(this.roles, r)
  64. }
  65. func (this *projectRoles) json() jsonutils.JSONObject {
  66. obj := jsonutils.NewDict()
  67. obj.Add(jsonutils.NewString(this.id), "id")
  68. obj.Add(jsonutils.NewString(this.name), "name")
  69. obj.Add(jsonutils.NewString(this.domain.id), "domain", "id")
  70. obj.Add(jsonutils.NewString(this.domain.name), "domain", "name")
  71. obj.Add(jsonutils.NewString(this.typ), "type")
  72. roles := jsonutils.NewArray()
  73. for _, r := range this.roles {
  74. role := jsonutils.NewDict()
  75. role.Add(jsonutils.NewString(r.id), "id")
  76. role.Add(jsonutils.NewString(r.name), "name")
  77. role.Add(jsonutils.NewString(r.domain.id), "domain", "id")
  78. role.Add(jsonutils.NewString(r.domain.name), "domain", "name")
  79. roles.Add(role)
  80. }
  81. obj.Add(roles, "roles")
  82. return obj
  83. }
  84. type sRole struct {
  85. Id string `json:"id"`
  86. Name string `json:"name"`
  87. Domain struct {
  88. Id string `json:"id"`
  89. Name string `json:"name"`
  90. } `json:"domain"`
  91. }
  92. type sGroupRole struct {
  93. Id string `json:"id"`
  94. Name string `json:"name"`
  95. Domain struct {
  96. Id string `json:"id"`
  97. Name string `json:"name"`
  98. } `json:"domain"`
  99. Roles []sRole `json:"roles"`
  100. Policies struct {
  101. Project []string `json:"project"`
  102. Domain []string `json:"domain"`
  103. System []string `json:"system"`
  104. } `json:"policies"`
  105. }
  106. type sProjectGroupRole struct {
  107. Id string `json:"id"`
  108. Name string `json:"name"`
  109. Metadata map[string]string `json:"metadata"`
  110. Domain struct {
  111. Id string `json:"id"`
  112. Name string `json:"name"`
  113. } `json:"domain"`
  114. Groups []sGroupRole `json:"groups"`
  115. }
  116. func (pgr *sProjectGroupRole) add(groupId, groupName, groupDomainId, groupDomainName, roleId, roleName, roleDomainId, roleDomainName string, projectPolicies, domainPolicies, systemPolicies []string) {
  117. groupIdx := -1
  118. for i := range pgr.Groups {
  119. if pgr.Groups[i].Id == groupId {
  120. groupIdx = i
  121. break
  122. }
  123. }
  124. if groupIdx < 0 {
  125. groupIdx = len(pgr.Groups)
  126. gr := sGroupRole{
  127. Id: groupId,
  128. Name: groupName,
  129. }
  130. gr.Domain.Id = groupDomainId
  131. gr.Domain.Name = groupDomainName
  132. pgr.Groups = append(pgr.Groups, gr)
  133. }
  134. pgr.Groups[groupIdx].add(roleId, roleName, roleDomainId, roleDomainName, projectPolicies, domainPolicies, systemPolicies)
  135. }
  136. func (gr *sGroupRole) add(roleId, roleName, roleDomainId, roleDomainName string, projectPolicies, domainPolicies, systemPolicies []string) {
  137. sr := sRole{
  138. Id: roleId,
  139. Name: roleName,
  140. }
  141. sr.Domain.Id = roleDomainId
  142. sr.Domain.Name = roleDomainName
  143. gr.Roles = append(gr.Roles, sr)
  144. for _, p := range projectPolicies {
  145. if !utils.IsInStringArray(p, gr.Policies.Project) {
  146. gr.Policies.Project = append(gr.Policies.Project, p)
  147. }
  148. }
  149. for _, p := range domainPolicies {
  150. if !utils.IsInStringArray(p, gr.Policies.Domain) {
  151. gr.Policies.Domain = append(gr.Policies.Domain, p)
  152. }
  153. }
  154. for _, p := range systemPolicies {
  155. if !utils.IsInStringArray(p, gr.Policies.System) {
  156. gr.Policies.System = append(gr.Policies.System, p)
  157. }
  158. }
  159. }
  160. var (
  161. RoleAssignments RoleAssignmentManagerV3
  162. )
  163. // get users for given project
  164. func (this *RoleAssignmentManagerV3) GetProjectUsers(s *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  165. query := jsonutils.NewDict()
  166. if params.Contains("effective") {
  167. query.Add(jsonutils.JSONNull, "effective")
  168. }
  169. if jsonutils.QueryBoolean(params, "system", false) {
  170. query.Add(jsonutils.JSONNull, "include_system")
  171. }
  172. resource, e := params.GetString("resource")
  173. if e != nil {
  174. return jsonutils.JSONNull, e
  175. }
  176. scope := false
  177. switch resource {
  178. case "domain",
  179. "project":
  180. {
  181. scope = true
  182. }
  183. case "user",
  184. "group",
  185. "role":
  186. {
  187. scope = false
  188. }
  189. default:
  190. return jsonutils.JSONNull, fmt.Errorf("not allowed resource %s", resource)
  191. }
  192. query.Add(jsonutils.JSONNull, "include_names")
  193. if scope {
  194. query.Add(jsonutils.NewString(id), "scope", resource, "id")
  195. } else {
  196. query.Add(jsonutils.NewString(id), resource, "id")
  197. }
  198. query.Add(jsonutils.JSONNull, "include_policies")
  199. result, err := this.List(s, query)
  200. if err != nil {
  201. return jsonutils.JSONNull, err
  202. }
  203. projects := make(map[string]*projectRoles)
  204. for _, roleAssign := range result.Data {
  205. typ := "user"
  206. roleId, _ := roleAssign.GetString("role", "id")
  207. roleName, _ := roleAssign.GetString("role", "name")
  208. roleDomainId, _ := roleAssign.GetString("role", "domain", "id")
  209. roleDomainName, _ := roleAssign.GetString("role", "domain", "name")
  210. userId, _ := roleAssign.GetString("user", "id")
  211. userName, _ := roleAssign.GetString("user", "name")
  212. userDomainId, _ := roleAssign.GetString("user", "domain", "id")
  213. userDomainName, _ := roleAssign.GetString("user", "domain", "name")
  214. if len(userName) == 0 {
  215. typ = "group"
  216. userName, _ = roleAssign.GetString("group", "name")
  217. userId, _ = roleAssign.GetString("group", "id")
  218. userDomainId, _ = roleAssign.GetString("group", "domain", "id")
  219. userDomainName, _ = roleAssign.GetString("group", "domain", "name")
  220. }
  221. _, ok := projects[userId]
  222. if ok {
  223. projects[userId].add(roleId, roleName, roleDomainId, roleDomainName)
  224. } else {
  225. projects[userId] = newProjectRoles(userId, userName, userDomainId, userDomainName, roleId, roleName, roleDomainId, roleDomainName, typ)
  226. }
  227. }
  228. projJson := jsonutils.NewArray()
  229. for _, proj := range projects {
  230. projJson.Add(proj.json())
  231. }
  232. data := jsonutils.NewDict()
  233. data.Add(projJson, "data")
  234. data.Add(jsonutils.NewInt(int64(len(projects))), "total")
  235. return data, nil
  236. }
  237. // get projects-roles for given resource, like domain, project, user, group, role
  238. func (this *RoleAssignmentManagerV3) GetProjectRole(s *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  239. data := jsonutils.NewDict()
  240. query := jsonutils.NewDict()
  241. if params.Contains("effective") {
  242. query.Add(jsonutils.JSONNull, "effective")
  243. }
  244. if jsonutils.QueryBoolean(params, "system", false) {
  245. query.Add(jsonutils.JSONNull, "include_system")
  246. }
  247. resource, err := params.GetString("resource")
  248. if err != nil {
  249. return jsonutils.JSONNull, err
  250. }
  251. scope := false
  252. switch resource {
  253. case "domain",
  254. "project":
  255. {
  256. scope = true
  257. }
  258. case "user",
  259. "group",
  260. "role":
  261. {
  262. }
  263. default:
  264. return jsonutils.JSONNull, fmt.Errorf("not allowed resource %s", resource)
  265. }
  266. // search by project id or name
  267. searchProjs := jsonutils.GetQueryStringArray(params, "projects")
  268. if len(searchProjs) > 0 {
  269. query.Add(jsonutils.NewStringArray(searchProjs), "projects")
  270. }
  271. // search by user id or name
  272. searchUsers := jsonutils.GetQueryStringArray(params, "users")
  273. if len(searchUsers) > 0 {
  274. query.Add(jsonutils.NewStringArray(searchUsers), "users")
  275. }
  276. groupBy, _ := params.GetString("group_by")
  277. if len(groupBy) == 0 {
  278. groupBy = "project"
  279. }
  280. if groupBy == "project" {
  281. } else if groupBy == "user" {
  282. } else {
  283. return nil, errors.Wrapf(httperrors.ErrInputParameter, "unsupported group_by value %s", groupBy)
  284. }
  285. query.Add(jsonutils.JSONNull, "include_names")
  286. if scope {
  287. query.Add(jsonutils.NewString(id), "scope", resource, "id")
  288. } else {
  289. query.Add(jsonutils.NewString(id), resource, "id")
  290. }
  291. query.Add(jsonutils.JSONNull, "include_policies")
  292. result, err := this.List(s, query)
  293. if err != nil {
  294. return jsonutils.JSONNull, err
  295. }
  296. lines := make([]sProjectGroupRole, 0)
  297. for _, roleAssign := range result.Data {
  298. roleId, _ := roleAssign.GetString("role", "id")
  299. roleName, _ := roleAssign.GetString("role", "name")
  300. roleDomainId, _ := roleAssign.GetString("role", "domain", "id")
  301. roleDomainName, _ := roleAssign.GetString("role", "domain", "name")
  302. var groupById, groupByName, groupByDomainId, groupByDomainName string
  303. metadatas := map[string]string{}
  304. if groupBy == "project" {
  305. groupById, _ = roleAssign.GetString("scope", "project", "id")
  306. groupByName, _ = roleAssign.GetString("scope", "project", "name")
  307. roleAssign.Unmarshal(&metadatas, "scope", "project", "metadata")
  308. groupByDomainId, _ = roleAssign.GetString("scope", "project", "domain", "id")
  309. groupByDomainName, _ = roleAssign.GetString("scope", "project", "domain", "name")
  310. } else if groupBy == "user" {
  311. groupById, _ = roleAssign.GetString("user", "id")
  312. groupByName, _ = roleAssign.GetString("user", "name")
  313. groupByDomainId, _ = roleAssign.GetString("user", "domain", "id")
  314. groupByDomainName, _ = roleAssign.GetString("user", "domain", "name")
  315. }
  316. groupId, _ := roleAssign.GetString("group", "id")
  317. groupName, _ := roleAssign.GetString("group", "name")
  318. groupDomainId, _ := roleAssign.GetString("group", "domain", "id")
  319. groupDomainName, _ := roleAssign.GetString("group", "domain", "name")
  320. projPolicies, _ := jsonutils.GetStringArray(roleAssign, "policies", "project")
  321. domPolicies, _ := jsonutils.GetStringArray(roleAssign, "policies", "domain")
  322. sysPolicies, _ := jsonutils.GetStringArray(roleAssign, "policies", "system")
  323. lineIdx := -1
  324. for i := range lines {
  325. if lines[i].Id == groupById {
  326. lineIdx = i
  327. break
  328. }
  329. }
  330. if lineIdx < 0 {
  331. lineIdx = len(lines)
  332. pgr := sProjectGroupRole{
  333. Id: groupById,
  334. Name: groupByName,
  335. Metadata: metadatas,
  336. }
  337. pgr.Domain.Id = groupByDomainId
  338. pgr.Domain.Name = groupByDomainName
  339. lines = append(lines, pgr)
  340. }
  341. lines[lineIdx].add(groupId, groupName, groupDomainId, groupDomainName, roleId, roleName, roleDomainId, roleDomainName, projPolicies, domPolicies, sysPolicies)
  342. }
  343. lineJson := jsonutils.NewArray()
  344. for _, line := range lines {
  345. lineJson.Add(jsonutils.Marshal(line))
  346. }
  347. data.Add(lineJson, "data")
  348. data.Add(jsonutils.NewInt(int64(len(lines))), "total")
  349. return data, nil
  350. }
  351. func (man *RoleAssignmentManagerV3) GetUserIdsByRolesInScope(s *mcclient.ClientSession, roleIds []string, roleScope rbacscope.TRbacScope, scopeId string) ([]string, error) {
  352. query := jsonutils.NewDict()
  353. query.Set("roles", jsonutils.Marshal(roleIds))
  354. query.Set("effective", jsonutils.JSONTrue)
  355. switch roleScope {
  356. case rbacscope.ScopeSystem:
  357. case rbacscope.ScopeDomain:
  358. if scopeId == "" {
  359. return nil, errors.Errorf("need projectDomainId")
  360. }
  361. query.Set("project_domain_id", jsonutils.NewString(scopeId))
  362. case rbacscope.ScopeProject:
  363. if scopeId == "" {
  364. return nil, errors.Errorf("need projectId")
  365. }
  366. query.Add(jsonutils.NewString(scopeId), "scope", "project", "id")
  367. }
  368. ret, err := man.List(s, query)
  369. if err != nil {
  370. return nil, errors.Wrapf(err, "list RoleAssignments with query %s", query.String())
  371. }
  372. users := make([]string, 0)
  373. for i := range ret.Data {
  374. ras := ret.Data[i]
  375. user, err := ras.Get("user")
  376. if err == nil {
  377. id, err := user.GetString("id")
  378. if err != nil {
  379. return nil, errors.Wrap(err, "unable to get user.id from result of RoleAssignments.List")
  380. }
  381. users = append(users, id)
  382. }
  383. }
  384. return users, nil
  385. }
  386. func init() {
  387. RoleAssignments = RoleAssignmentManagerV3{modules.NewIdentityV3Manager("role_assignment", "role_assignments",
  388. []string{"Scope", "User", "Group", "Role", "Policies"},
  389. []string{})}
  390. modules.Register(&RoleAssignments)
  391. }