rbac.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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. "yunion.io/x/log"
  17. "yunion.io/x/pkg/util/netutils"
  18. )
  19. type TRbacResult string
  20. const (
  21. WILD_MATCH = "*"
  22. Allow = TRbacResult("allow")
  23. Deny = TRbacResult("deny")
  24. // no more many allow levels, only allow/deny
  25. AdminAllow = TRbacResult("admin") // deprecated
  26. OwnerAllow = TRbacResult("owner") // deprecated
  27. UserAllow = TRbacResult("user") // deprecated
  28. GuestAllow = TRbacResult("guest") // deprecated
  29. /*ScopeSystem = rbacscope.ScopeSystem
  30. ScopeDomain = rbacscope.ScopeDomain
  31. ScopeProject = rbacscope.ScopeProject
  32. // ScopeObject = "object"
  33. ScopeUser = rbacscope.ScopeUser
  34. ScopeNone = rbacscope.ScopeNone*/
  35. GUEST_TOKEN = "guest_token"
  36. )
  37. func (r TRbacResult) IsAllow() bool {
  38. return r == Allow
  39. }
  40. func (r TRbacResult) IsDeny() bool {
  41. return r == Deny
  42. }
  43. var (
  44. strictness = map[TRbacResult]int{
  45. Deny: 0,
  46. AdminAllow: 1,
  47. OwnerAllow: 2,
  48. UserAllow: 3,
  49. GuestAllow: 4,
  50. Allow: 5,
  51. }
  52. )
  53. func (r TRbacResult) Strictness() int {
  54. return strictness[r]
  55. }
  56. func (r1 TRbacResult) StricterThan(r2 TRbacResult) bool {
  57. return r1.Strictness() < r2.Strictness()
  58. }
  59. func (r1 TRbacResult) LooserThan(r2 TRbacResult) bool {
  60. return r1.Strictness() > r2.Strictness()
  61. }
  62. type SRbacRule struct {
  63. Service string
  64. Resource string
  65. Action string
  66. Extra []string
  67. Result TRbacResult
  68. }
  69. func (r SRbacRule) clone() SRbacRule {
  70. nr := r
  71. nr.Extra = make([]string, len(r.Extra))
  72. if len(r.Extra) > 0 {
  73. copy(nr.Extra, r.Extra)
  74. }
  75. return nr
  76. }
  77. func isWildMatch(str string) bool {
  78. return len(str) == 0 || str == WILD_MATCH
  79. }
  80. func (rule *SRbacRule) contains(rule2 *SRbacRule) bool {
  81. if !isWildMatch(rule.Service) && rule.Service != rule2.Service {
  82. return false
  83. }
  84. if !isWildMatch(rule.Resource) && rule.Resource != rule2.Resource {
  85. return false
  86. }
  87. if !isWildMatch(rule.Action) && rule.Action != rule2.Action {
  88. return false
  89. }
  90. if len(rule.Extra) > 0 {
  91. for i := 0; i < len(rule.Extra); i += 1 {
  92. if !isWildMatch(rule.Extra[i]) && (rule2.Extra == nil || len(rule2.Extra) < i || rule.Extra[i] != rule2.Extra[i]) {
  93. return false
  94. }
  95. }
  96. }
  97. if string(rule.Result) != string(rule2.Result) {
  98. return false
  99. }
  100. return true
  101. }
  102. func (rule *SRbacRule) stricterThan(r2 *SRbacRule) bool {
  103. return rule.Result.StricterThan(r2.Result)
  104. }
  105. func (rule *SRbacRule) looserThan(r2 *SRbacRule) bool {
  106. return rule.Result.LooserThan(r2.Result)
  107. }
  108. func (rule *SRbacRule) match(service string, resource string, action string, extra ...string) (bool, int, int) {
  109. matched := 0
  110. weight := 0
  111. if !isWildMatch(rule.Service) {
  112. if rule.Service != service {
  113. return false, 0, 0
  114. }
  115. matched += 1
  116. weight += 1
  117. }
  118. if !isWildMatch(rule.Resource) {
  119. if rule.Resource != resource {
  120. return false, 0, 0
  121. }
  122. matched += 1
  123. weight += 10
  124. }
  125. if !isWildMatch(rule.Action) {
  126. if rule.Action != action {
  127. return false, 0, 0
  128. }
  129. matched += 1
  130. weight += 100
  131. }
  132. for i := 0; i < len(rule.Extra) && i < len(extra); i += 1 {
  133. if !isWildMatch(rule.Extra[i]) {
  134. if rule.Extra[i] != extra[i] {
  135. return false, 0, 0
  136. }
  137. matched += 1
  138. weight += 1000 * (i + 1)
  139. }
  140. }
  141. return true, matched, weight
  142. }
  143. var (
  144. ShowMatchRuleDebug = false
  145. )
  146. func GetMatchRule(rules []SRbacRule, service string, resource string, action string, extra ...string) *SRbacRule {
  147. maxMatchCnt := 0
  148. minWeight := 1000000
  149. var matchRule *SRbacRule
  150. for i := 0; i < len(rules); i += 1 {
  151. match, matchCnt, weight := rules[i].match(service, resource, action, extra...)
  152. if match && ShowMatchRuleDebug {
  153. log.Debugf("rule %s match cnt %d weight %d", rules[i], matchCnt, weight)
  154. }
  155. if match && (maxMatchCnt < matchCnt ||
  156. (maxMatchCnt == matchCnt && minWeight > weight) ||
  157. (maxMatchCnt == matchCnt && minWeight == weight && matchRule.stricterThan(&rules[i]))) {
  158. maxMatchCnt = matchCnt
  159. minWeight = weight
  160. matchRule = &rules[i]
  161. }
  162. }
  163. return matchRule
  164. }
  165. const (
  166. levelService = 0
  167. levelResource = 1
  168. levelAction = 2
  169. levelExtra = 3
  170. )
  171. func (rule *SRbacRule) toStringArray() []string {
  172. strArr := make([]string, 0)
  173. strArr = append(strArr, rule.Service)
  174. strArr = append(strArr, rule.Resource)
  175. strArr = append(strArr, rule.Action)
  176. if rule.Extra != nil {
  177. strArr = append(strArr, rule.Extra...)
  178. }
  179. i := len(strArr) - 1
  180. for i > 0 && (len(strArr[i]) == 0 || strArr[i] == WILD_MATCH) {
  181. i -= 1
  182. }
  183. return strArr[0 : i+1]
  184. }
  185. func contains(s1 []string, s string) bool {
  186. for i := range s1 {
  187. if s1[i] == s {
  188. return true
  189. }
  190. }
  191. return false
  192. }
  193. func intersect(s1 []string, s2 []string) bool {
  194. for i := range s1 {
  195. for j := range s2 {
  196. if s1[i] == s2[j] {
  197. return true
  198. }
  199. }
  200. }
  201. return false
  202. }
  203. func containsIp(ips []netutils.IPV4Prefix, ipStr string) bool {
  204. if len(ipStr) == 0 {
  205. // user comes from unknown ip, assume matches
  206. return true
  207. }
  208. ip, err := netutils.NewIPV4Addr(ipStr)
  209. if err != nil {
  210. log.Errorf("user comes from invalid ipv4 addr %s: %s", ipStr, err)
  211. return false
  212. }
  213. for i := range ips {
  214. if ips[i].Contains(ip) {
  215. return true
  216. }
  217. }
  218. return false
  219. }
  220. const (
  221. FAKE_TOKEN = "fake_token"
  222. )
  223. type IBaseIdentity interface {
  224. GetLoginIp() string
  225. GetTokenString() string
  226. }
  227. type IRbacIdentity interface {
  228. GetProjectId() string
  229. GetRoleIds() []string
  230. IBaseIdentity
  231. }
  232. type IRbacIdentity2 interface {
  233. GetProjectDomainId() string
  234. GetProjectName() string
  235. GetRoles() []string
  236. IBaseIdentity
  237. }
  238. type sSimpleRbacIdentity struct {
  239. projectDomainId string
  240. projectId string
  241. projectName string
  242. roleIds []string
  243. roles []string
  244. ip string
  245. }
  246. func (id sSimpleRbacIdentity) GetRoles() []string {
  247. return id.roles
  248. }
  249. func (id sSimpleRbacIdentity) GetRoleIds() []string {
  250. return id.roleIds
  251. }
  252. func (id sSimpleRbacIdentity) GetProjectName() string {
  253. return id.projectName
  254. }
  255. func (id sSimpleRbacIdentity) GetProjectId() string {
  256. return id.projectId
  257. }
  258. func (id sSimpleRbacIdentity) GetProjectDomainId() string {
  259. return id.projectDomainId
  260. }
  261. func (id sSimpleRbacIdentity) GetLoginIp() string {
  262. return id.ip
  263. }
  264. func (id sSimpleRbacIdentity) GetTokenString() string {
  265. return FAKE_TOKEN
  266. }
  267. func newRbacIdentity2(projectDomainId, projectName string, roles []string, ip string) IRbacIdentity2 {
  268. return sSimpleRbacIdentity{
  269. projectDomainId: projectDomainId,
  270. projectName: projectName,
  271. roles: roles,
  272. ip: ip,
  273. }
  274. }
  275. func NewRbacIdentity(projectId string, roleIds []string, ip string) IRbacIdentity {
  276. return sSimpleRbacIdentity{
  277. projectId: projectId,
  278. roleIds: roleIds,
  279. ip: ip,
  280. }
  281. }