policy.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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 rbacutils
  15. import (
  16. "regexp"
  17. "yunion.io/x/jsonutils"
  18. "yunion.io/x/pkg/errors"
  19. "yunion.io/x/pkg/util/netutils"
  20. "yunion.io/x/pkg/util/rbacscope"
  21. )
  22. type SRbacPolicy struct {
  23. // condition, when the policy takes effects
  24. // Deprecated
  25. Condition string
  26. DomainId string
  27. IsPublic bool
  28. PublicScope rbacscope.TRbacScope
  29. SharedDomainIds []string
  30. Projects []string
  31. Roles []string
  32. Ips []netutils.IPV4Prefix
  33. Auth bool // whether needs authentication
  34. // scope, the scope of the policy, system/domain/project
  35. Scope rbacscope.TRbacScope
  36. // Deprecated
  37. // is_admin=true means scope=system, is_admin=false means scope=project
  38. IsAdmin bool
  39. Rules TPolicy
  40. }
  41. func (p SRbacPolicy) needAuth() bool {
  42. if len(p.Condition) > 0 {
  43. return true
  44. }
  45. if len(p.DomainId) > 0 {
  46. return true
  47. }
  48. if len(p.SharedDomainIds) > 0 {
  49. return true
  50. }
  51. if len(p.Projects) > 0 {
  52. return true
  53. }
  54. if len(p.Roles) > 0 {
  55. return true
  56. }
  57. if p.Auth {
  58. return true
  59. }
  60. return false
  61. }
  62. var (
  63. tenantEqualsPattern = regexp.MustCompile(`tenant\s*==\s*['"]?(\w+)['"]?`)
  64. roleContainsPattern = regexp.MustCompile(`roles.contains\(['"]?(\w+)['"]?\)`)
  65. )
  66. func searchMatchStrings(pattern *regexp.Regexp, condstr string) []string {
  67. ret := make([]string, 0)
  68. matches := pattern.FindAllStringSubmatch(condstr, -1)
  69. for _, match := range matches {
  70. ret = append(ret, match[1])
  71. }
  72. return ret
  73. }
  74. func searchMatchTenants(condstr string) []string {
  75. return searchMatchStrings(tenantEqualsPattern, condstr)
  76. }
  77. func searchMatchRoles(condstr string) []string {
  78. return searchMatchStrings(roleContainsPattern, condstr)
  79. }
  80. // Deprecated
  81. func (policy *SRbacPolicy) Decode(policyJson jsonutils.JSONObject) error {
  82. policy.Condition, _ = policyJson.GetString("condition")
  83. if policyJson.Contains("projects") {
  84. projectJson, _ := policyJson.GetArray("projects")
  85. policy.Projects = jsonutils.JSONArray2StringArray(projectJson)
  86. }
  87. if policyJson.Contains("roles") {
  88. roleJson, _ := policyJson.GetArray("roles")
  89. policy.Roles = jsonutils.JSONArray2StringArray(roleJson)
  90. }
  91. if len(policy.Projects) == 0 && len(policy.Roles) == 0 && len(policy.Condition) > 0 {
  92. // XXX hack
  93. // for smooth transtion from condition to projects&roles
  94. policy.Projects = searchMatchTenants(policy.Condition)
  95. policy.Roles = searchMatchRoles(policy.Condition)
  96. }
  97. // empty condition, no longer use this field
  98. policy.Condition = ""
  99. if policyJson.Contains("ips") {
  100. ipsJson, _ := policyJson.GetArray("ips")
  101. ipStrs := jsonutils.JSONArray2StringArray(ipsJson)
  102. policy.Ips = make([]netutils.IPV4Prefix, 0)
  103. for _, ipStr := range ipStrs {
  104. if len(ipStr) == 0 || ipStr == "0.0.0.0" {
  105. continue
  106. }
  107. prefix, err := netutils.NewIPV4Prefix(ipStr)
  108. if err != nil {
  109. continue
  110. }
  111. policy.Ips = append(policy.Ips, prefix)
  112. }
  113. }
  114. policy.Auth = jsonutils.QueryBoolean(policyJson, "auth", true)
  115. if len(policy.Ips) > 0 || len(policy.Roles) > 0 || len(policy.Projects) > 0 {
  116. policy.Auth = true
  117. }
  118. scopeStr, _ := policyJson.GetString("scope")
  119. if len(scopeStr) > 0 {
  120. policy.Scope = rbacscope.TRbacScope(scopeStr)
  121. } else {
  122. policy.IsAdmin = jsonutils.QueryBoolean(policyJson, "is_admin", false)
  123. if len(policy.Scope) == 0 {
  124. if policy.IsAdmin {
  125. policy.Scope = rbacscope.ScopeSystem
  126. } else {
  127. policy.Scope = rbacscope.ScopeProject
  128. }
  129. }
  130. }
  131. policyBody, err := policyJson.Get("policy")
  132. if err != nil {
  133. return errors.Wrap(err, "Get policy")
  134. }
  135. policy.Rules, err = decodePolicy(policyBody)
  136. if err != nil {
  137. return errors.Wrap(err, "DecodePolicy")
  138. }
  139. return nil
  140. }
  141. func (policy *SRbacPolicy) Encode() jsonutils.JSONObject {
  142. ret := jsonutils.NewDict()
  143. if !policy.Auth && len(policy.Projects) == 0 && len(policy.Roles) == 0 && len(policy.Ips) == 0 {
  144. ret.Add(jsonutils.JSONFalse, "auth")
  145. } else {
  146. ret.Add(jsonutils.JSONTrue, "auth")
  147. }
  148. if len(policy.Projects) > 0 {
  149. ret.Add(jsonutils.NewStringArray(policy.Projects), "projects")
  150. }
  151. if len(policy.Roles) > 0 {
  152. ret.Add(jsonutils.NewStringArray(policy.Roles), "roles")
  153. }
  154. if len(policy.Ips) > 0 {
  155. ipStrs := make([]string, len(policy.Ips))
  156. for i := range policy.Ips {
  157. ipStrs[i] = policy.Ips[i].String()
  158. }
  159. ret.Add(jsonutils.NewStringArray(ipStrs), "ips")
  160. }
  161. ret.Add(jsonutils.NewString(string(policy.Scope)), "scope")
  162. ret.Add(policy.Rules.encode(), "policy")
  163. return ret
  164. }
  165. func (policy *SRbacPolicy) IsSystemWidePolicy() bool {
  166. return (len(policy.DomainId) == 0 || (policy.IsPublic && policy.PublicScope == rbacscope.ScopeSystem)) && len(policy.Roles) == 0 && len(policy.Projects) == 0
  167. }
  168. func (policy *SRbacPolicy) MatchDomain(domainId string) bool {
  169. if len(policy.DomainId) == 0 || len(domainId) == 0 {
  170. return true
  171. }
  172. if policy.DomainId == domainId {
  173. return true
  174. }
  175. if policy.IsPublic {
  176. if policy.PublicScope == rbacscope.ScopeSystem {
  177. return true
  178. }
  179. if contains(policy.SharedDomainIds, domainId) {
  180. return true
  181. }
  182. }
  183. return false
  184. }
  185. func (policy *SRbacPolicy) MatchProject(projectName string) bool {
  186. if len(policy.Projects) == 0 || len(projectName) == 0 {
  187. return true
  188. }
  189. if contains(policy.Projects, projectName) {
  190. return true
  191. }
  192. return false
  193. }
  194. func (policy *SRbacPolicy) MatchRoles(roleNames []string) bool {
  195. if len(policy.Roles) == 0 {
  196. return true
  197. }
  198. if intersect(policy.Roles, roleNames) {
  199. return true
  200. }
  201. return false
  202. }
  203. // check whether policy maches a userCred
  204. // return value
  205. // bool isMatched
  206. // int match weight, the higher the value, the more exact the match
  207. // the more exact match wins
  208. func (policy *SRbacPolicy) Match(userCred IRbacIdentity2) (bool, int) {
  209. if !policy.needAuth() {
  210. if len(policy.Ips) == 0 {
  211. return true, 1
  212. }
  213. if containsIp(policy.Ips, userCred.GetLoginIp()) {
  214. return true, 1
  215. }
  216. }
  217. if userCred == nil || len(userCred.GetTokenString()) == 0 || userCred.GetTokenString() == GUEST_TOKEN {
  218. return false, 0
  219. }
  220. weight := 0
  221. if policy.MatchDomain(userCred.GetProjectDomainId()) {
  222. if len(policy.DomainId) > 0 {
  223. if policy.DomainId == userCred.GetProjectDomainId() {
  224. weight += 30 // exact domain match
  225. } else if len(policy.SharedDomainIds) > 0 {
  226. weight += 20 // shared domain match
  227. } else {
  228. weight += 10 // else, system scope match
  229. }
  230. }
  231. if policy.MatchRoles(userCred.GetRoles()) {
  232. if len(policy.Roles) != 0 {
  233. weight += 100
  234. }
  235. if policy.MatchProject(userCred.GetProjectName()) {
  236. if len(policy.Projects) > 0 {
  237. weight += 1000
  238. }
  239. if len(policy.Ips) == 0 || containsIp(policy.Ips, userCred.GetLoginIp()) {
  240. if len(policy.Ips) > 0 {
  241. weight += 10000
  242. }
  243. return true, weight
  244. }
  245. }
  246. }
  247. }
  248. return false, 0
  249. }