abac_test.go 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package abac
  14. import (
  15. "context"
  16. "io/ioutil"
  17. "os"
  18. "reflect"
  19. "testing"
  20. "k8s.io/apimachinery/pkg/runtime"
  21. "k8s.io/apiserver/pkg/authentication/user"
  22. "k8s.io/apiserver/pkg/authorization/authorizer"
  23. "k8s.io/kubernetes/pkg/apis/abac"
  24. "k8s.io/kubernetes/pkg/apis/abac/v0"
  25. "k8s.io/kubernetes/pkg/apis/abac/v1beta1"
  26. )
  27. func TestEmptyFile(t *testing.T) {
  28. _, err := newWithContents(t, "")
  29. if err != nil {
  30. t.Errorf("unable to read policy file: %v", err)
  31. }
  32. }
  33. func TestOneLineFileNoNewLine(t *testing.T) {
  34. _, err := newWithContents(t, `{"user":"scheduler", "readonly": true, "resource": "pods", "namespace":"ns1"}`)
  35. if err != nil {
  36. t.Errorf("unable to read policy file: %v", err)
  37. }
  38. }
  39. func TestTwoLineFile(t *testing.T) {
  40. _, err := newWithContents(t, `{"user":"scheduler", "readonly": true, "resource": "pods"}
  41. {"user":"scheduler", "readonly": true, "resource": "services"}
  42. `)
  43. if err != nil {
  44. t.Errorf("unable to read policy file: %v", err)
  45. }
  46. }
  47. // Test the file that we will point users at as an example.
  48. func TestExampleFile(t *testing.T) {
  49. _, err := NewFromFile("./example_policy_file.jsonl")
  50. if err != nil {
  51. t.Errorf("unable to read policy file: %v", err)
  52. }
  53. }
  54. func TestAuthorizeV0(t *testing.T) {
  55. a, err := newWithContents(t, `{ "readonly": true, "resource": "events" }
  56. {"user":"scheduler", "readonly": true, "resource": "pods" }
  57. {"user":"scheduler", "resource": "bindings" }
  58. {"user":"kubelet", "readonly": true, "resource": "bindings" }
  59. {"user":"kubelet", "resource": "events" }
  60. {"user":"alice", "namespace": "projectCaribou"}
  61. {"user":"bob", "readonly": true, "namespace": "projectCaribou"}
  62. `)
  63. if err != nil {
  64. t.Fatalf("unable to read policy file: %v", err)
  65. }
  66. authenticatedGroup := []string{user.AllAuthenticated}
  67. uScheduler := user.DefaultInfo{Name: "scheduler", UID: "uid1", Groups: authenticatedGroup}
  68. uAlice := user.DefaultInfo{Name: "alice", UID: "uid3", Groups: authenticatedGroup}
  69. uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5", Groups: authenticatedGroup}
  70. testCases := []struct {
  71. User user.DefaultInfo
  72. Verb string
  73. Resource string
  74. NS string
  75. APIGroup string
  76. Path string
  77. ExpectDecision authorizer.Decision
  78. }{
  79. // Scheduler can read pods
  80. {User: uScheduler, Verb: "list", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
  81. {User: uScheduler, Verb: "list", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionAllow},
  82. // Scheduler cannot write pods
  83. {User: uScheduler, Verb: "create", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  84. {User: uScheduler, Verb: "create", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
  85. // Scheduler can write bindings
  86. {User: uScheduler, Verb: "get", Resource: "bindings", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
  87. {User: uScheduler, Verb: "get", Resource: "bindings", NS: "", ExpectDecision: authorizer.DecisionAllow},
  88. // Alice can read and write anything in the right namespace.
  89. {User: uAlice, Verb: "get", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  90. {User: uAlice, Verb: "get", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  91. {User: uAlice, Verb: "get", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  92. {User: uAlice, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  93. {User: uAlice, Verb: "update", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  94. {User: uAlice, Verb: "update", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  95. {User: uAlice, Verb: "update", Resource: "foo", NS: "projectCaribou", APIGroup: "bar", ExpectDecision: authorizer.DecisionAllow},
  96. // .. but not the wrong namespace.
  97. {User: uAlice, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  98. {User: uAlice, Verb: "get", Resource: "widgets", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  99. {User: uAlice, Verb: "get", Resource: "", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  100. // Chuck can read events, since anyone can.
  101. {User: uChuck, Verb: "get", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
  102. {User: uChuck, Verb: "get", Resource: "events", NS: "", ExpectDecision: authorizer.DecisionAllow},
  103. // Chuck can't do other things.
  104. {User: uChuck, Verb: "update", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  105. {User: uChuck, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  106. {User: uChuck, Verb: "get", Resource: "floop", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  107. // Chunk can't access things with no kind or namespace
  108. {User: uChuck, Verb: "get", Path: "/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
  109. }
  110. for i, tc := range testCases {
  111. attr := authorizer.AttributesRecord{
  112. User: &tc.User,
  113. Verb: tc.Verb,
  114. Resource: tc.Resource,
  115. Namespace: tc.NS,
  116. APIGroup: tc.APIGroup,
  117. Path: tc.Path,
  118. ResourceRequest: len(tc.NS) > 0 || len(tc.Resource) > 0,
  119. }
  120. decision, _, _ := a.Authorize(context.Background(), attr)
  121. if tc.ExpectDecision != decision {
  122. t.Logf("tc: %v -> attr %v", tc, attr)
  123. t.Errorf("%d: Expected allowed=%v but actually allowed=%v\n\t%v",
  124. i, tc.ExpectDecision, decision, tc)
  125. }
  126. }
  127. }
  128. func getResourceRules(infos []authorizer.ResourceRuleInfo) []authorizer.DefaultResourceRuleInfo {
  129. rules := make([]authorizer.DefaultResourceRuleInfo, len(infos))
  130. for i, info := range infos {
  131. rules[i] = authorizer.DefaultResourceRuleInfo{
  132. Verbs: info.GetVerbs(),
  133. APIGroups: info.GetAPIGroups(),
  134. Resources: info.GetResources(),
  135. ResourceNames: info.GetResourceNames(),
  136. }
  137. }
  138. return rules
  139. }
  140. func getNonResourceRules(infos []authorizer.NonResourceRuleInfo) []authorizer.DefaultNonResourceRuleInfo {
  141. rules := make([]authorizer.DefaultNonResourceRuleInfo, len(infos))
  142. for i, info := range infos {
  143. rules[i] = authorizer.DefaultNonResourceRuleInfo{
  144. Verbs: info.GetVerbs(),
  145. NonResourceURLs: info.GetNonResourceURLs(),
  146. }
  147. }
  148. return rules
  149. }
  150. func TestRulesFor(t *testing.T) {
  151. a, err := newWithContents(t, `
  152. { "readonly": true, "resource": "events" }
  153. {"user":"scheduler", "readonly": true, "resource": "pods" }
  154. {"user":"scheduler", "resource": "bindings" }
  155. {"user":"kubelet", "readonly": true, "resource": "pods" }
  156. {"user":"kubelet", "resource": "events" }
  157. {"user":"alice", "namespace": "projectCaribou"}
  158. {"user":"bob", "readonly": true, "namespace": "projectCaribou"}
  159. {"user":"bob", "readonly": true, "nonResourcePath": "*"}
  160. {"group":"a", "resource": "bindings" }
  161. {"group":"b", "readonly": true, "nonResourcePath": "*"}
  162. `)
  163. if err != nil {
  164. t.Fatalf("unable to read policy file: %v", err)
  165. }
  166. authenticatedGroup := []string{user.AllAuthenticated}
  167. uScheduler := user.DefaultInfo{Name: "scheduler", UID: "uid1", Groups: authenticatedGroup}
  168. uKubelet := user.DefaultInfo{Name: "kubelet", UID: "uid2", Groups: []string{"a", "b"}}
  169. uAlice := user.DefaultInfo{Name: "alice", UID: "uid3", Groups: authenticatedGroup}
  170. uBob := user.DefaultInfo{Name: "bob", UID: "uid4", Groups: authenticatedGroup}
  171. uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5", Groups: []string{"a", "b"}}
  172. testCases := []struct {
  173. User user.DefaultInfo
  174. Namespace string
  175. ExpectResourceRules []authorizer.DefaultResourceRuleInfo
  176. ExpectNonResourceRules []authorizer.DefaultNonResourceRuleInfo
  177. }{
  178. {
  179. User: uScheduler,
  180. Namespace: "ns1",
  181. ExpectResourceRules: []authorizer.DefaultResourceRuleInfo{
  182. {
  183. Verbs: []string{"get", "list", "watch"},
  184. APIGroups: []string{"*"},
  185. Resources: []string{"events"},
  186. },
  187. {
  188. Verbs: []string{"get", "list", "watch"},
  189. APIGroups: []string{"*"},
  190. Resources: []string{"pods"},
  191. },
  192. {
  193. Verbs: []string{"*"},
  194. APIGroups: []string{"*"},
  195. Resources: []string{"bindings"},
  196. },
  197. },
  198. ExpectNonResourceRules: []authorizer.DefaultNonResourceRuleInfo{},
  199. },
  200. {
  201. User: uKubelet,
  202. Namespace: "ns1",
  203. ExpectResourceRules: []authorizer.DefaultResourceRuleInfo{
  204. {
  205. Verbs: []string{"get", "list", "watch"},
  206. APIGroups: []string{"*"},
  207. Resources: []string{"pods"},
  208. },
  209. {
  210. Verbs: []string{"*"},
  211. APIGroups: []string{"*"},
  212. Resources: []string{"events"},
  213. },
  214. {
  215. Verbs: []string{"*"},
  216. APIGroups: []string{"*"},
  217. Resources: []string{"bindings"},
  218. },
  219. {
  220. Verbs: []string{"get", "list", "watch"},
  221. APIGroups: []string{"*"},
  222. Resources: []string{"*"},
  223. },
  224. },
  225. ExpectNonResourceRules: []authorizer.DefaultNonResourceRuleInfo{
  226. {
  227. Verbs: []string{"get", "list", "watch"},
  228. NonResourceURLs: []string{"*"},
  229. },
  230. },
  231. },
  232. {
  233. User: uAlice,
  234. Namespace: "projectCaribou",
  235. ExpectResourceRules: []authorizer.DefaultResourceRuleInfo{
  236. {
  237. Verbs: []string{"get", "list", "watch"},
  238. APIGroups: []string{"*"},
  239. Resources: []string{"events"},
  240. },
  241. {
  242. Verbs: []string{"*"},
  243. APIGroups: []string{"*"},
  244. Resources: []string{"*"},
  245. },
  246. },
  247. ExpectNonResourceRules: []authorizer.DefaultNonResourceRuleInfo{},
  248. },
  249. {
  250. User: uBob,
  251. Namespace: "projectCaribou",
  252. ExpectResourceRules: []authorizer.DefaultResourceRuleInfo{
  253. {
  254. Verbs: []string{"get", "list", "watch"},
  255. APIGroups: []string{"*"},
  256. Resources: []string{"events"},
  257. },
  258. {
  259. Verbs: []string{"get", "list", "watch"},
  260. APIGroups: []string{"*"},
  261. Resources: []string{"*"},
  262. },
  263. {
  264. Verbs: []string{"get", "list", "watch"},
  265. APIGroups: []string{"*"},
  266. Resources: []string{"*"},
  267. },
  268. },
  269. ExpectNonResourceRules: []authorizer.DefaultNonResourceRuleInfo{
  270. {
  271. Verbs: []string{"get", "list", "watch"},
  272. NonResourceURLs: []string{"*"},
  273. },
  274. },
  275. },
  276. {
  277. User: uChuck,
  278. Namespace: "ns1",
  279. ExpectResourceRules: []authorizer.DefaultResourceRuleInfo{
  280. {
  281. Verbs: []string{"*"},
  282. APIGroups: []string{"*"},
  283. Resources: []string{"bindings"},
  284. },
  285. {
  286. Verbs: []string{"get", "list", "watch"},
  287. APIGroups: []string{"*"},
  288. Resources: []string{"*"},
  289. },
  290. },
  291. ExpectNonResourceRules: []authorizer.DefaultNonResourceRuleInfo{
  292. {
  293. Verbs: []string{"get", "list", "watch"},
  294. NonResourceURLs: []string{"*"},
  295. },
  296. },
  297. },
  298. }
  299. for i, tc := range testCases {
  300. attr := authorizer.AttributesRecord{
  301. User: &tc.User,
  302. Namespace: tc.Namespace,
  303. }
  304. resourceRules, nonResourceRules, _, _ := a.RulesFor(attr.GetUser(), attr.GetNamespace())
  305. actualResourceRules := getResourceRules(resourceRules)
  306. if !reflect.DeepEqual(tc.ExpectResourceRules, actualResourceRules) {
  307. t.Logf("tc: %v -> attr %v", tc, attr)
  308. t.Errorf("%d: Expected: \n%#v\n but actual: \n%#v\n",
  309. i, tc.ExpectResourceRules, actualResourceRules)
  310. }
  311. actualNonResourceRules := getNonResourceRules(nonResourceRules)
  312. if !reflect.DeepEqual(tc.ExpectNonResourceRules, actualNonResourceRules) {
  313. t.Logf("tc: %v -> attr %v", tc, attr)
  314. t.Errorf("%d: Expected: \n%#v\n but actual: \n%#v\n",
  315. i, tc.ExpectNonResourceRules, actualNonResourceRules)
  316. }
  317. }
  318. }
  319. func TestAuthorizeV1beta1(t *testing.T) {
  320. a, err := newWithContents(t,
  321. `
  322. # Comment line, after a blank line
  323. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"*", "readonly": true, "nonResourcePath": "/api"}}
  324. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"*", "nonResourcePath": "/custom"}}
  325. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"*", "nonResourcePath": "/root/*"}}
  326. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"noresource", "nonResourcePath": "*"}}
  327. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"*", "readonly": true, "resource": "events", "namespace": "*"}}
  328. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"scheduler", "readonly": true, "resource": "pods", "namespace": "*"}}
  329. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"scheduler", "resource": "bindings", "namespace": "*"}}
  330. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"kubelet", "readonly": true, "resource": "bindings", "namespace": "*"}}
  331. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"kubelet", "resource": "events", "namespace": "*"}}
  332. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"alice", "resource": "*", "namespace": "projectCaribou"}}
  333. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"bob", "readonly": true, "resource": "*", "namespace": "projectCaribou"}}
  334. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"debbie", "resource": "pods", "namespace": "projectCaribou"}}
  335. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"apigroupuser", "resource": "*", "namespace": "projectAnyGroup", "apiGroup": "*"}}
  336. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"apigroupuser", "resource": "*", "namespace": "projectEmptyGroup", "apiGroup": "" }}
  337. {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"apigroupuser", "resource": "*", "namespace": "projectXGroup", "apiGroup": "x"}}`)
  338. if err != nil {
  339. t.Fatalf("unable to read policy file: %v", err)
  340. }
  341. authenticatedGroup := []string{user.AllAuthenticated}
  342. uScheduler := user.DefaultInfo{Name: "scheduler", UID: "uid1", Groups: authenticatedGroup}
  343. uAlice := user.DefaultInfo{Name: "alice", UID: "uid3", Groups: authenticatedGroup}
  344. uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5", Groups: authenticatedGroup}
  345. uDebbie := user.DefaultInfo{Name: "debbie", UID: "uid6", Groups: authenticatedGroup}
  346. uNoResource := user.DefaultInfo{Name: "noresource", UID: "uid7", Groups: authenticatedGroup}
  347. uAPIGroup := user.DefaultInfo{Name: "apigroupuser", UID: "uid8", Groups: authenticatedGroup}
  348. testCases := []struct {
  349. User user.DefaultInfo
  350. Verb string
  351. Resource string
  352. APIGroup string
  353. NS string
  354. Path string
  355. ExpectDecision authorizer.Decision
  356. }{
  357. // Scheduler can read pods
  358. {User: uScheduler, Verb: "list", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
  359. {User: uScheduler, Verb: "list", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionAllow},
  360. // Scheduler cannot write pods
  361. {User: uScheduler, Verb: "create", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  362. {User: uScheduler, Verb: "create", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
  363. // Scheduler can write bindings
  364. {User: uScheduler, Verb: "get", Resource: "bindings", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
  365. {User: uScheduler, Verb: "get", Resource: "bindings", NS: "", ExpectDecision: authorizer.DecisionAllow},
  366. // Alice can read and write anything in the right namespace.
  367. {User: uAlice, Verb: "get", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  368. {User: uAlice, Verb: "get", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  369. {User: uAlice, Verb: "get", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  370. {User: uAlice, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  371. {User: uAlice, Verb: "update", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  372. {User: uAlice, Verb: "update", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  373. // .. but not the wrong namespace.
  374. {User: uAlice, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  375. {User: uAlice, Verb: "get", Resource: "widgets", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  376. {User: uAlice, Verb: "get", Resource: "", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  377. // Debbie can write to pods in the right namespace
  378. {User: uDebbie, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
  379. // Chuck can read events, since anyone can.
  380. {User: uChuck, Verb: "get", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
  381. {User: uChuck, Verb: "get", Resource: "events", NS: "", ExpectDecision: authorizer.DecisionAllow},
  382. // Chuck can't do other things.
  383. {User: uChuck, Verb: "update", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  384. {User: uChuck, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  385. {User: uChuck, Verb: "get", Resource: "floop", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
  386. // Chuck can't access things with no resource or namespace
  387. {User: uChuck, Verb: "get", Path: "/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
  388. // but can access /api
  389. {User: uChuck, Verb: "get", Path: "/api", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
  390. // though he cannot write to it
  391. {User: uChuck, Verb: "create", Path: "/api", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
  392. // while he can write to /custom
  393. {User: uChuck, Verb: "update", Path: "/custom", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
  394. // he cannot get "/root"
  395. {User: uChuck, Verb: "get", Path: "/root", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
  396. // but can get any subpath
  397. {User: uChuck, Verb: "get", Path: "/root/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
  398. {User: uChuck, Verb: "get", Path: "/root/test/1/2/3", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
  399. // the user "noresource" can get any non-resource request
  400. {User: uNoResource, Verb: "get", Path: "", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
  401. {User: uNoResource, Verb: "get", Path: "/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
  402. {User: uNoResource, Verb: "get", Path: "/foo/bar/baz", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
  403. // but cannot get any request where IsResourceRequest() == true
  404. {User: uNoResource, Verb: "get", Path: "/", Resource: "", NS: "bar", ExpectDecision: authorizer.DecisionNoOpinion},
  405. {User: uNoResource, Verb: "get", Path: "/foo/bar/baz", Resource: "foo", NS: "bar", ExpectDecision: authorizer.DecisionNoOpinion},
  406. // Test APIGroup matching
  407. {User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectAnyGroup", ExpectDecision: authorizer.DecisionAllow},
  408. {User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectEmptyGroup", ExpectDecision: authorizer.DecisionNoOpinion},
  409. {User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectXGroup", ExpectDecision: authorizer.DecisionAllow},
  410. }
  411. for i, tc := range testCases {
  412. attr := authorizer.AttributesRecord{
  413. User: &tc.User,
  414. Verb: tc.Verb,
  415. Resource: tc.Resource,
  416. APIGroup: tc.APIGroup,
  417. Namespace: tc.NS,
  418. ResourceRequest: len(tc.NS) > 0 || len(tc.Resource) > 0,
  419. Path: tc.Path,
  420. }
  421. // t.Logf("tc %2v: %v -> attr %v", i, tc, attr)
  422. decision, _, _ := a.Authorize(context.Background(), attr)
  423. if tc.ExpectDecision != decision {
  424. t.Errorf("%d: Expected allowed=%v but actually allowed=%v, for case %+v & %+v",
  425. i, tc.ExpectDecision, decision, tc, attr)
  426. }
  427. }
  428. }
  429. func TestSubjectMatches(t *testing.T) {
  430. testCases := map[string]struct {
  431. User user.DefaultInfo
  432. Policy runtime.Object
  433. ExpectMatch bool
  434. }{
  435. "v0 empty policy does not match unauthed user": {
  436. User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
  437. Policy: &v0.Policy{
  438. User: "",
  439. Group: "",
  440. },
  441. ExpectMatch: false,
  442. },
  443. "v0 * user policy does not match unauthed user": {
  444. User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
  445. Policy: &v0.Policy{
  446. User: "*",
  447. Group: "",
  448. },
  449. ExpectMatch: false,
  450. },
  451. "v0 * group policy does not match unauthed user": {
  452. User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
  453. Policy: &v0.Policy{
  454. User: "",
  455. Group: "*",
  456. },
  457. ExpectMatch: false,
  458. },
  459. "v0 empty policy matches authed user": {
  460. User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}},
  461. Policy: &v0.Policy{
  462. User: "",
  463. Group: "",
  464. },
  465. ExpectMatch: true,
  466. },
  467. "v0 empty policy matches authed user with groups": {
  468. User: user.DefaultInfo{Name: "Foo", Groups: []string{"a", "b", user.AllAuthenticated}},
  469. Policy: &v0.Policy{
  470. User: "",
  471. Group: "",
  472. },
  473. ExpectMatch: true,
  474. },
  475. "v0 user policy does not match unauthed user": {
  476. User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
  477. Policy: &v0.Policy{
  478. User: "Foo",
  479. Group: "",
  480. },
  481. ExpectMatch: false,
  482. },
  483. "v0 user policy does not match different user": {
  484. User: user.DefaultInfo{Name: "Bar", Groups: []string{user.AllAuthenticated}},
  485. Policy: &v0.Policy{
  486. User: "Foo",
  487. Group: "",
  488. },
  489. ExpectMatch: false,
  490. },
  491. "v0 user policy is case-sensitive": {
  492. User: user.DefaultInfo{Name: "foo", Groups: []string{user.AllAuthenticated}},
  493. Policy: &v0.Policy{
  494. User: "Foo",
  495. Group: "",
  496. },
  497. ExpectMatch: false,
  498. },
  499. "v0 user policy does not match substring": {
  500. User: user.DefaultInfo{Name: "FooBar", Groups: []string{user.AllAuthenticated}},
  501. Policy: &v0.Policy{
  502. User: "Foo",
  503. Group: "",
  504. },
  505. ExpectMatch: false,
  506. },
  507. "v0 user policy matches username": {
  508. User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}},
  509. Policy: &v0.Policy{
  510. User: "Foo",
  511. Group: "",
  512. },
  513. ExpectMatch: true,
  514. },
  515. "v0 group policy does not match unauthed user": {
  516. User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
  517. Policy: &v0.Policy{
  518. User: "",
  519. Group: "Foo",
  520. },
  521. ExpectMatch: false,
  522. },
  523. "v0 group policy does not match user in different group": {
  524. User: user.DefaultInfo{Name: "FooBar", Groups: []string{"B", user.AllAuthenticated}},
  525. Policy: &v0.Policy{
  526. User: "",
  527. Group: "A",
  528. },
  529. ExpectMatch: false,
  530. },
  531. "v0 group policy is case-sensitive": {
  532. User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
  533. Policy: &v0.Policy{
  534. User: "",
  535. Group: "b",
  536. },
  537. ExpectMatch: false,
  538. },
  539. "v0 group policy does not match substring": {
  540. User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "BBB", "C", user.AllAuthenticated}},
  541. Policy: &v0.Policy{
  542. User: "",
  543. Group: "B",
  544. },
  545. ExpectMatch: false,
  546. },
  547. "v0 group policy matches user in group": {
  548. User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
  549. Policy: &v0.Policy{
  550. User: "",
  551. Group: "B",
  552. },
  553. ExpectMatch: true,
  554. },
  555. "v0 user and group policy requires user match": {
  556. User: user.DefaultInfo{Name: "Bar", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
  557. Policy: &v0.Policy{
  558. User: "Foo",
  559. Group: "B",
  560. },
  561. ExpectMatch: false,
  562. },
  563. "v0 user and group policy requires group match": {
  564. User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
  565. Policy: &v0.Policy{
  566. User: "Foo",
  567. Group: "D",
  568. },
  569. ExpectMatch: false,
  570. },
  571. "v0 user and group policy matches": {
  572. User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
  573. Policy: &v0.Policy{
  574. User: "Foo",
  575. Group: "B",
  576. },
  577. ExpectMatch: true,
  578. },
  579. "v1 empty policy does not match unauthed user": {
  580. User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
  581. Policy: &v1beta1.Policy{
  582. Spec: v1beta1.PolicySpec{
  583. User: "",
  584. Group: "",
  585. },
  586. },
  587. ExpectMatch: false,
  588. },
  589. "v1 * user policy does not match unauthed user": {
  590. User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
  591. Policy: &v1beta1.Policy{
  592. Spec: v1beta1.PolicySpec{
  593. User: "*",
  594. Group: "",
  595. },
  596. },
  597. ExpectMatch: false,
  598. },
  599. "v1 * group policy does not match unauthed user": {
  600. User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
  601. Policy: &v1beta1.Policy{
  602. Spec: v1beta1.PolicySpec{
  603. User: "",
  604. Group: "*",
  605. },
  606. },
  607. ExpectMatch: false,
  608. },
  609. "v1 empty policy does not match authed user": {
  610. User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}},
  611. Policy: &v1beta1.Policy{
  612. Spec: v1beta1.PolicySpec{
  613. User: "",
  614. Group: "",
  615. },
  616. },
  617. ExpectMatch: false,
  618. },
  619. "v1 empty policy does not match authed user with groups": {
  620. User: user.DefaultInfo{Name: "Foo", Groups: []string{"a", "b", user.AllAuthenticated}},
  621. Policy: &v1beta1.Policy{
  622. Spec: v1beta1.PolicySpec{
  623. User: "",
  624. Group: "",
  625. },
  626. },
  627. ExpectMatch: false,
  628. },
  629. "v1 user policy does not match unauthed user": {
  630. User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
  631. Policy: &v1beta1.Policy{
  632. Spec: v1beta1.PolicySpec{
  633. User: "Foo",
  634. Group: "",
  635. },
  636. },
  637. ExpectMatch: false,
  638. },
  639. "v1 user policy does not match different user": {
  640. User: user.DefaultInfo{Name: "Bar", Groups: []string{user.AllAuthenticated}},
  641. Policy: &v1beta1.Policy{
  642. Spec: v1beta1.PolicySpec{
  643. User: "Foo",
  644. Group: "",
  645. },
  646. },
  647. ExpectMatch: false,
  648. },
  649. "v1 user policy is case-sensitive": {
  650. User: user.DefaultInfo{Name: "foo", Groups: []string{user.AllAuthenticated}},
  651. Policy: &v1beta1.Policy{
  652. Spec: v1beta1.PolicySpec{
  653. User: "Foo",
  654. Group: "",
  655. },
  656. },
  657. ExpectMatch: false,
  658. },
  659. "v1 user policy does not match substring": {
  660. User: user.DefaultInfo{Name: "FooBar", Groups: []string{user.AllAuthenticated}},
  661. Policy: &v1beta1.Policy{
  662. Spec: v1beta1.PolicySpec{
  663. User: "Foo",
  664. Group: "",
  665. },
  666. },
  667. ExpectMatch: false,
  668. },
  669. "v1 user policy matches username": {
  670. User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}},
  671. Policy: &v1beta1.Policy{
  672. Spec: v1beta1.PolicySpec{
  673. User: "Foo",
  674. Group: "",
  675. },
  676. },
  677. ExpectMatch: true,
  678. },
  679. "v1 group policy does not match unauthed user": {
  680. User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
  681. Policy: &v1beta1.Policy{
  682. Spec: v1beta1.PolicySpec{
  683. User: "",
  684. Group: "Foo",
  685. },
  686. },
  687. ExpectMatch: false,
  688. },
  689. "v1 group policy does not match user in different group": {
  690. User: user.DefaultInfo{Name: "FooBar", Groups: []string{"B", user.AllAuthenticated}},
  691. Policy: &v1beta1.Policy{
  692. Spec: v1beta1.PolicySpec{
  693. User: "",
  694. Group: "A",
  695. },
  696. },
  697. ExpectMatch: false,
  698. },
  699. "v1 group policy is case-sensitive": {
  700. User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
  701. Policy: &v1beta1.Policy{
  702. Spec: v1beta1.PolicySpec{
  703. User: "",
  704. Group: "b",
  705. },
  706. },
  707. ExpectMatch: false,
  708. },
  709. "v1 group policy does not match substring": {
  710. User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "BBB", "C", user.AllAuthenticated}},
  711. Policy: &v1beta1.Policy{
  712. Spec: v1beta1.PolicySpec{
  713. User: "",
  714. Group: "B",
  715. },
  716. },
  717. ExpectMatch: false,
  718. },
  719. "v1 group policy matches user in group": {
  720. User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
  721. Policy: &v1beta1.Policy{
  722. Spec: v1beta1.PolicySpec{
  723. User: "",
  724. Group: "B",
  725. },
  726. },
  727. ExpectMatch: true,
  728. },
  729. "v1 user and group policy requires user match": {
  730. User: user.DefaultInfo{Name: "Bar", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
  731. Policy: &v1beta1.Policy{
  732. Spec: v1beta1.PolicySpec{
  733. User: "Foo",
  734. Group: "B",
  735. },
  736. },
  737. ExpectMatch: false,
  738. },
  739. "v1 user and group policy requires group match": {
  740. User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
  741. Policy: &v1beta1.Policy{
  742. Spec: v1beta1.PolicySpec{
  743. User: "Foo",
  744. Group: "D",
  745. },
  746. },
  747. ExpectMatch: false,
  748. },
  749. "v1 user and group policy matches": {
  750. User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
  751. Policy: &v1beta1.Policy{
  752. Spec: v1beta1.PolicySpec{
  753. User: "Foo",
  754. Group: "B",
  755. },
  756. },
  757. ExpectMatch: true,
  758. },
  759. }
  760. for k, tc := range testCases {
  761. policy := &abac.Policy{}
  762. if err := abac.Scheme.Convert(tc.Policy, policy, nil); err != nil {
  763. t.Errorf("%s: error converting: %v", k, err)
  764. continue
  765. }
  766. attr := authorizer.AttributesRecord{
  767. User: &tc.User,
  768. }
  769. actualMatch := subjectMatches(*policy, attr.GetUser())
  770. if tc.ExpectMatch != actualMatch {
  771. t.Errorf("%v: Expected actorMatches=%v but actually got=%v",
  772. k, tc.ExpectMatch, actualMatch)
  773. }
  774. }
  775. }
  776. func newWithContents(t *testing.T, contents string) (PolicyList, error) {
  777. f, err := ioutil.TempFile("", "abac_test")
  778. if err != nil {
  779. t.Fatalf("unexpected error creating policyfile: %v", err)
  780. }
  781. f.Close()
  782. defer os.Remove(f.Name())
  783. if err := ioutil.WriteFile(f.Name(), []byte(contents), 0700); err != nil {
  784. t.Fatalf("unexpected error writing policyfile: %v", err)
  785. }
  786. pl, err := NewFromFile(f.Name())
  787. return pl, err
  788. }
  789. func TestPolicy(t *testing.T) {
  790. tests := []struct {
  791. policy runtime.Object
  792. attr authorizer.Attributes
  793. matches bool
  794. name string
  795. }{
  796. // v0 mismatches
  797. {
  798. policy: &v0.Policy{
  799. Readonly: true,
  800. },
  801. attr: authorizer.AttributesRecord{
  802. User: &user.DefaultInfo{
  803. Name: "foo",
  804. Groups: []string{user.AllAuthenticated},
  805. },
  806. Verb: "create",
  807. },
  808. matches: false,
  809. name: "v0 read-only mismatch",
  810. },
  811. {
  812. policy: &v0.Policy{
  813. User: "foo",
  814. },
  815. attr: authorizer.AttributesRecord{
  816. User: &user.DefaultInfo{
  817. Name: "bar",
  818. Groups: []string{user.AllAuthenticated},
  819. },
  820. },
  821. matches: false,
  822. name: "v0 user name mis-match",
  823. },
  824. {
  825. policy: &v0.Policy{
  826. Resource: "foo",
  827. },
  828. attr: authorizer.AttributesRecord{
  829. User: &user.DefaultInfo{
  830. Name: "foo",
  831. Groups: []string{user.AllAuthenticated},
  832. },
  833. Resource: "bar",
  834. ResourceRequest: true,
  835. },
  836. matches: false,
  837. name: "v0 resource mis-match",
  838. },
  839. {
  840. policy: &v0.Policy{
  841. User: "foo",
  842. Resource: "foo",
  843. Namespace: "foo",
  844. },
  845. attr: authorizer.AttributesRecord{
  846. User: &user.DefaultInfo{
  847. Name: "foo",
  848. Groups: []string{user.AllAuthenticated},
  849. },
  850. Resource: "foo",
  851. Namespace: "foo",
  852. ResourceRequest: true,
  853. },
  854. matches: true,
  855. name: "v0 namespace mis-match",
  856. },
  857. // v0 matches
  858. {
  859. policy: &v0.Policy{},
  860. attr: authorizer.AttributesRecord{
  861. User: &user.DefaultInfo{
  862. Name: "foo",
  863. Groups: []string{user.AllAuthenticated},
  864. },
  865. ResourceRequest: true,
  866. },
  867. matches: true,
  868. name: "v0 null resource",
  869. },
  870. {
  871. policy: &v0.Policy{
  872. Readonly: true,
  873. },
  874. attr: authorizer.AttributesRecord{
  875. User: &user.DefaultInfo{
  876. Name: "foo",
  877. Groups: []string{user.AllAuthenticated},
  878. },
  879. Verb: "get",
  880. },
  881. matches: true,
  882. name: "v0 read-only match",
  883. },
  884. {
  885. policy: &v0.Policy{
  886. User: "foo",
  887. },
  888. attr: authorizer.AttributesRecord{
  889. User: &user.DefaultInfo{
  890. Name: "foo",
  891. Groups: []string{user.AllAuthenticated},
  892. },
  893. },
  894. matches: true,
  895. name: "v0 user name match",
  896. },
  897. {
  898. policy: &v0.Policy{
  899. Resource: "foo",
  900. },
  901. attr: authorizer.AttributesRecord{
  902. User: &user.DefaultInfo{
  903. Name: "foo",
  904. Groups: []string{user.AllAuthenticated},
  905. },
  906. Resource: "foo",
  907. ResourceRequest: true,
  908. },
  909. matches: true,
  910. name: "v0 resource match",
  911. },
  912. // v1 mismatches
  913. {
  914. policy: &v1beta1.Policy{},
  915. attr: authorizer.AttributesRecord{
  916. User: &user.DefaultInfo{
  917. Name: "foo",
  918. Groups: []string{user.AllAuthenticated},
  919. },
  920. ResourceRequest: true,
  921. },
  922. matches: false,
  923. name: "v1 null",
  924. },
  925. {
  926. policy: &v1beta1.Policy{
  927. Spec: v1beta1.PolicySpec{
  928. User: "foo",
  929. },
  930. },
  931. attr: authorizer.AttributesRecord{
  932. User: &user.DefaultInfo{
  933. Name: "bar",
  934. Groups: []string{user.AllAuthenticated},
  935. },
  936. ResourceRequest: true,
  937. },
  938. matches: false,
  939. name: "v1 user name mis-match",
  940. },
  941. {
  942. policy: &v1beta1.Policy{
  943. Spec: v1beta1.PolicySpec{
  944. User: "*",
  945. Readonly: true,
  946. },
  947. },
  948. attr: authorizer.AttributesRecord{
  949. User: &user.DefaultInfo{
  950. Name: "foo",
  951. Groups: []string{user.AllAuthenticated},
  952. },
  953. ResourceRequest: true,
  954. },
  955. matches: false,
  956. name: "v1 read-only mismatch",
  957. },
  958. {
  959. policy: &v1beta1.Policy{
  960. Spec: v1beta1.PolicySpec{
  961. User: "*",
  962. Resource: "foo",
  963. },
  964. },
  965. attr: authorizer.AttributesRecord{
  966. User: &user.DefaultInfo{
  967. Name: "foo",
  968. Groups: []string{user.AllAuthenticated},
  969. },
  970. Resource: "bar",
  971. ResourceRequest: true,
  972. },
  973. matches: false,
  974. name: "v1 resource mis-match",
  975. },
  976. {
  977. policy: &v1beta1.Policy{
  978. Spec: v1beta1.PolicySpec{
  979. User: "foo",
  980. Namespace: "barr",
  981. Resource: "baz",
  982. },
  983. },
  984. attr: authorizer.AttributesRecord{
  985. User: &user.DefaultInfo{
  986. Name: "foo",
  987. Groups: []string{user.AllAuthenticated},
  988. },
  989. Namespace: "bar",
  990. Resource: "baz",
  991. ResourceRequest: true,
  992. },
  993. matches: false,
  994. name: "v1 namespace mis-match",
  995. },
  996. {
  997. policy: &v1beta1.Policy{
  998. Spec: v1beta1.PolicySpec{
  999. User: "*",
  1000. NonResourcePath: "/api",
  1001. },
  1002. },
  1003. attr: authorizer.AttributesRecord{
  1004. User: &user.DefaultInfo{
  1005. Name: "foo",
  1006. Groups: []string{user.AllAuthenticated},
  1007. },
  1008. Path: "/api2",
  1009. ResourceRequest: false,
  1010. },
  1011. matches: false,
  1012. name: "v1 non-resource mis-match",
  1013. },
  1014. {
  1015. policy: &v1beta1.Policy{
  1016. Spec: v1beta1.PolicySpec{
  1017. User: "*",
  1018. NonResourcePath: "/api/*",
  1019. },
  1020. },
  1021. attr: authorizer.AttributesRecord{
  1022. User: &user.DefaultInfo{
  1023. Name: "foo",
  1024. Groups: []string{user.AllAuthenticated},
  1025. },
  1026. Path: "/api2/foo",
  1027. ResourceRequest: false,
  1028. },
  1029. matches: false,
  1030. name: "v1 non-resource wildcard subpath mis-match",
  1031. },
  1032. // v1 matches
  1033. {
  1034. policy: &v1beta1.Policy{
  1035. Spec: v1beta1.PolicySpec{
  1036. User: "foo",
  1037. },
  1038. },
  1039. attr: authorizer.AttributesRecord{
  1040. User: &user.DefaultInfo{
  1041. Name: "foo",
  1042. Groups: []string{user.AllAuthenticated},
  1043. },
  1044. ResourceRequest: true,
  1045. },
  1046. matches: true,
  1047. name: "v1 user match",
  1048. },
  1049. {
  1050. policy: &v1beta1.Policy{
  1051. Spec: v1beta1.PolicySpec{
  1052. User: "*",
  1053. },
  1054. },
  1055. attr: authorizer.AttributesRecord{
  1056. User: &user.DefaultInfo{
  1057. Name: "foo",
  1058. Groups: []string{user.AllAuthenticated},
  1059. },
  1060. ResourceRequest: true,
  1061. },
  1062. matches: true,
  1063. name: "v1 user wildcard match",
  1064. },
  1065. {
  1066. policy: &v1beta1.Policy{
  1067. Spec: v1beta1.PolicySpec{
  1068. Group: "bar",
  1069. },
  1070. },
  1071. attr: authorizer.AttributesRecord{
  1072. User: &user.DefaultInfo{
  1073. Name: "foo",
  1074. Groups: []string{"bar", user.AllAuthenticated},
  1075. },
  1076. ResourceRequest: true,
  1077. },
  1078. matches: true,
  1079. name: "v1 group match",
  1080. },
  1081. {
  1082. policy: &v1beta1.Policy{
  1083. Spec: v1beta1.PolicySpec{
  1084. Group: "*",
  1085. },
  1086. },
  1087. attr: authorizer.AttributesRecord{
  1088. User: &user.DefaultInfo{
  1089. Name: "foo",
  1090. Groups: []string{"bar", user.AllAuthenticated},
  1091. },
  1092. ResourceRequest: true,
  1093. },
  1094. matches: true,
  1095. name: "v1 group wildcard match",
  1096. },
  1097. {
  1098. policy: &v1beta1.Policy{
  1099. Spec: v1beta1.PolicySpec{
  1100. User: "*",
  1101. Readonly: true,
  1102. },
  1103. },
  1104. attr: authorizer.AttributesRecord{
  1105. User: &user.DefaultInfo{
  1106. Name: "foo",
  1107. Groups: []string{user.AllAuthenticated},
  1108. },
  1109. Verb: "get",
  1110. ResourceRequest: true,
  1111. },
  1112. matches: true,
  1113. name: "v1 read-only match",
  1114. },
  1115. {
  1116. policy: &v1beta1.Policy{
  1117. Spec: v1beta1.PolicySpec{
  1118. User: "*",
  1119. Resource: "foo",
  1120. },
  1121. },
  1122. attr: authorizer.AttributesRecord{
  1123. User: &user.DefaultInfo{
  1124. Name: "foo",
  1125. Groups: []string{user.AllAuthenticated},
  1126. },
  1127. Resource: "foo",
  1128. ResourceRequest: true,
  1129. },
  1130. matches: true,
  1131. name: "v1 resource match",
  1132. },
  1133. {
  1134. policy: &v1beta1.Policy{
  1135. Spec: v1beta1.PolicySpec{
  1136. User: "foo",
  1137. Namespace: "bar",
  1138. Resource: "baz",
  1139. },
  1140. },
  1141. attr: authorizer.AttributesRecord{
  1142. User: &user.DefaultInfo{
  1143. Name: "foo",
  1144. Groups: []string{user.AllAuthenticated},
  1145. },
  1146. Namespace: "bar",
  1147. Resource: "baz",
  1148. ResourceRequest: true,
  1149. },
  1150. matches: true,
  1151. name: "v1 namespace match",
  1152. },
  1153. {
  1154. policy: &v1beta1.Policy{
  1155. Spec: v1beta1.PolicySpec{
  1156. User: "*",
  1157. NonResourcePath: "/api",
  1158. },
  1159. },
  1160. attr: authorizer.AttributesRecord{
  1161. User: &user.DefaultInfo{
  1162. Name: "foo",
  1163. Groups: []string{user.AllAuthenticated},
  1164. },
  1165. Path: "/api",
  1166. ResourceRequest: false,
  1167. },
  1168. matches: true,
  1169. name: "v1 non-resource match",
  1170. },
  1171. {
  1172. policy: &v1beta1.Policy{
  1173. Spec: v1beta1.PolicySpec{
  1174. User: "*",
  1175. NonResourcePath: "*",
  1176. },
  1177. },
  1178. attr: authorizer.AttributesRecord{
  1179. User: &user.DefaultInfo{
  1180. Name: "foo",
  1181. Groups: []string{user.AllAuthenticated},
  1182. },
  1183. Path: "/api",
  1184. ResourceRequest: false,
  1185. },
  1186. matches: true,
  1187. name: "v1 non-resource wildcard match",
  1188. },
  1189. {
  1190. policy: &v1beta1.Policy{
  1191. Spec: v1beta1.PolicySpec{
  1192. User: "*",
  1193. NonResourcePath: "/api/*",
  1194. },
  1195. },
  1196. attr: authorizer.AttributesRecord{
  1197. User: &user.DefaultInfo{
  1198. Name: "foo",
  1199. Groups: []string{user.AllAuthenticated},
  1200. },
  1201. Path: "/api/foo",
  1202. ResourceRequest: false,
  1203. },
  1204. matches: true,
  1205. name: "v1 non-resource wildcard subpath match",
  1206. },
  1207. }
  1208. for _, test := range tests {
  1209. policy := &abac.Policy{}
  1210. if err := abac.Scheme.Convert(test.policy, policy, nil); err != nil {
  1211. t.Errorf("%s: error converting: %v", test.name, err)
  1212. continue
  1213. }
  1214. matches := matches(*policy, test.attr)
  1215. if test.matches != matches {
  1216. t.Errorf("%s: expected: %t, saw: %t", test.name, test.matches, matches)
  1217. continue
  1218. }
  1219. }
  1220. }