2
0

policy_test.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. package policy_test
  2. import (
  3. "testing"
  4. "github.com/porter-dev/porter/api/server/authz/policy"
  5. "github.com/porter-dev/porter/api/types"
  6. "github.com/stretchr/testify/assert"
  7. )
  8. type testHasScopeAccess struct {
  9. description string
  10. policy []*types.PolicyDocument
  11. reqScopes map[types.PermissionScope]*types.RequestAction
  12. expRes bool
  13. }
  14. var hasScopeAccessTests = []testHasScopeAccess{
  15. {
  16. description: "admin access to project",
  17. policy: types.AdminPolicy,
  18. reqScopes: map[types.PermissionScope]*types.RequestAction{
  19. types.ProjectScope: {
  20. Verb: types.APIVerbGet,
  21. Resource: types.NameOrUInt{
  22. UInt: 1,
  23. },
  24. },
  25. },
  26. expRes: true,
  27. },
  28. {
  29. description: "viewer access cannot perform write operation",
  30. policy: types.ViewerPolicy,
  31. reqScopes: map[types.PermissionScope]*types.RequestAction{
  32. types.ClusterScope: {
  33. Verb: types.APIVerbCreate,
  34. Resource: types.NameOrUInt{
  35. UInt: 1,
  36. },
  37. },
  38. },
  39. expRes: false,
  40. },
  41. {
  42. description: "developer access cannot write settings",
  43. policy: types.DeveloperPolicy,
  44. reqScopes: map[types.PermissionScope]*types.RequestAction{
  45. types.SettingsScope: {
  46. Verb: types.APIVerbUpdate,
  47. Resource: types.NameOrUInt{
  48. UInt: 1,
  49. },
  50. },
  51. },
  52. expRes: false,
  53. },
  54. {
  55. description: "custom policy for cluster 1 can write cluster 1",
  56. policy: testPolicySpecificClusters,
  57. reqScopes: map[types.PermissionScope]*types.RequestAction{
  58. types.ClusterScope: {
  59. Verb: types.APIVerbUpdate,
  60. Resource: types.NameOrUInt{
  61. UInt: 1,
  62. },
  63. },
  64. },
  65. expRes: true,
  66. },
  67. {
  68. description: "custom policy for cluster 1 cannot write cluster 2",
  69. policy: testPolicySpecificClusters,
  70. reqScopes: map[types.PermissionScope]*types.RequestAction{
  71. types.ClusterScope: {
  72. Verb: types.APIVerbUpdate,
  73. Resource: types.NameOrUInt{
  74. UInt: 2,
  75. },
  76. },
  77. },
  78. expRes: false,
  79. },
  80. {
  81. description: "cannot access wrong namespace + cluster combination",
  82. policy: testPolicyNamespaceSpecific,
  83. reqScopes: map[types.PermissionScope]*types.RequestAction{
  84. types.ClusterScope: {
  85. Verb: types.APIVerbGet,
  86. Resource: types.NameOrUInt{
  87. UInt: 500,
  88. },
  89. },
  90. types.NamespaceScope: {
  91. Verb: types.APIVerbGet,
  92. Resource: types.NameOrUInt{
  93. Name: "default",
  94. },
  95. },
  96. },
  97. expRes: false,
  98. },
  99. {
  100. description: "can access set namespace + cluster combination",
  101. policy: testPolicyNamespaceSpecific,
  102. reqScopes: map[types.PermissionScope]*types.RequestAction{
  103. types.ClusterScope: {
  104. Verb: types.APIVerbGet,
  105. Resource: types.NameOrUInt{
  106. UInt: 500,
  107. },
  108. },
  109. types.NamespaceScope: {
  110. Verb: types.APIVerbGet,
  111. Resource: types.NameOrUInt{
  112. Name: "abelanger",
  113. },
  114. },
  115. },
  116. expRes: true,
  117. },
  118. {
  119. description: "cannot write the set namespace + cluster combination",
  120. policy: testPolicyNamespaceSpecific,
  121. reqScopes: map[types.PermissionScope]*types.RequestAction{
  122. types.ClusterScope: {
  123. Verb: types.APIVerbGet,
  124. Resource: types.NameOrUInt{
  125. UInt: 500,
  126. },
  127. },
  128. types.NamespaceScope: {
  129. Verb: types.APIVerbDelete,
  130. Resource: types.NameOrUInt{
  131. Name: "abelanger",
  132. },
  133. },
  134. },
  135. expRes: false,
  136. },
  137. {
  138. description: "test invalid policy document",
  139. policy: testInvalidPolicyDocument,
  140. reqScopes: map[types.PermissionScope]*types.RequestAction{
  141. types.ProjectScope: {
  142. Verb: types.APIVerbGet,
  143. Resource: types.NameOrUInt{
  144. UInt: 1,
  145. },
  146. },
  147. },
  148. expRes: false,
  149. },
  150. {
  151. description: "test invalid policy document nested",
  152. policy: testInvalidPolicyDocumentNested,
  153. reqScopes: map[types.PermissionScope]*types.RequestAction{
  154. types.ProjectScope: {
  155. Verb: types.APIVerbGet,
  156. Resource: types.NameOrUInt{
  157. UInt: 1,
  158. },
  159. },
  160. },
  161. expRes: false,
  162. },
  163. }
  164. func TestHasScopeAccess(t *testing.T) {
  165. assert := assert.New(t)
  166. for _, test := range hasScopeAccessTests {
  167. res := policy.HasScopeAccess(
  168. test.policy,
  169. test.reqScopes,
  170. )
  171. assert.Equal(test.expRes, res, test.description)
  172. }
  173. }
  174. func BenchmarkSimpleHasScopeAccess(b *testing.B) {
  175. for i := 0; i < b.N; i++ {
  176. res := policy.HasScopeAccess(
  177. testPolicySpecificClusters,
  178. map[types.PermissionScope]*types.RequestAction{
  179. types.ClusterScope: {
  180. Verb: types.APIVerbCreate,
  181. Resource: types.NameOrUInt{
  182. UInt: 1,
  183. },
  184. },
  185. },
  186. )
  187. // we expect all results to be true, so fatal if not
  188. if !res {
  189. b.Fatalf("benchmark failed correctness: expected true")
  190. }
  191. }
  192. }
  193. var testPolicySpecificClusters = []*types.PolicyDocument{
  194. {
  195. Scope: types.ProjectScope,
  196. Verbs: types.ReadWriteVerbGroup(),
  197. Children: map[types.PermissionScope]*types.PolicyDocument{
  198. types.ClusterScope: {
  199. Scope: types.ClusterScope,
  200. Verbs: types.ReadWriteVerbGroup(),
  201. Resources: []types.NameOrUInt{
  202. {
  203. UInt: 1,
  204. },
  205. },
  206. },
  207. },
  208. },
  209. }
  210. var testPolicyNamespaceSpecific = []*types.PolicyDocument{
  211. // This document allows a user to view the namespace "abelanger" in the cluster
  212. // with id 500.
  213. {
  214. Scope: types.ProjectScope,
  215. Verbs: types.ReadWriteVerbGroup(),
  216. Children: map[types.PermissionScope]*types.PolicyDocument{
  217. types.ClusterScope: {
  218. Scope: types.ClusterScope,
  219. Verbs: types.ReadVerbGroup(),
  220. Resources: []types.NameOrUInt{
  221. {
  222. UInt: 500,
  223. },
  224. },
  225. Children: map[types.PermissionScope]*types.PolicyDocument{
  226. types.NamespaceScope: {
  227. Scope: types.NamespaceScope,
  228. Verbs: types.ReadVerbGroup(),
  229. Resources: []types.NameOrUInt{
  230. {
  231. Name: "abelanger",
  232. },
  233. },
  234. },
  235. },
  236. },
  237. },
  238. },
  239. // This document allows a user to view the namespace "default" in the cluster
  240. // with id 501.
  241. {
  242. Scope: types.ProjectScope,
  243. Verbs: types.ReadWriteVerbGroup(),
  244. Children: map[types.PermissionScope]*types.PolicyDocument{
  245. types.ClusterScope: {
  246. Scope: types.ClusterScope,
  247. Verbs: types.ReadVerbGroup(),
  248. Resources: []types.NameOrUInt{
  249. {
  250. UInt: 501,
  251. },
  252. },
  253. Children: map[types.PermissionScope]*types.PolicyDocument{
  254. types.NamespaceScope: {
  255. Scope: types.NamespaceScope,
  256. Verbs: types.ReadVerbGroup(),
  257. Resources: []types.NameOrUInt{
  258. {
  259. Name: "default",
  260. },
  261. },
  262. },
  263. },
  264. },
  265. },
  266. },
  267. }
  268. // NOTE: these are invalid policy documents that don't follow the accepted heirarchy
  269. // for scopes. Don't use this as a model for a valid doc.
  270. var testInvalidPolicyDocument = []*types.PolicyDocument{
  271. {
  272. // invalid because cluster above project
  273. Scope: types.ClusterScope,
  274. Verbs: types.ReadWriteVerbGroup(),
  275. Children: map[types.PermissionScope]*types.PolicyDocument{
  276. types.ProjectScope: {
  277. Scope: types.ProjectScope,
  278. Verbs: types.ReadWriteVerbGroup(),
  279. Resources: []types.NameOrUInt{
  280. {
  281. UInt: 1,
  282. },
  283. },
  284. },
  285. },
  286. },
  287. }
  288. var testInvalidPolicyDocumentNested = []*types.PolicyDocument{
  289. {
  290. // invalid because release is a child of cluster, not namespace scope
  291. Scope: types.ProjectScope,
  292. Verbs: types.ReadWriteVerbGroup(),
  293. Children: map[types.PermissionScope]*types.PolicyDocument{
  294. types.ClusterScope: {
  295. Scope: types.ClusterScope,
  296. Verbs: types.ReadWriteVerbGroup(),
  297. Resources: []types.NameOrUInt{
  298. {
  299. UInt: 1,
  300. },
  301. },
  302. Children: map[types.PermissionScope]*types.PolicyDocument{
  303. types.ReleaseScope: {
  304. Scope: types.ReleaseScope,
  305. Verbs: types.ReadWriteVerbGroup(),
  306. Resources: []types.NameOrUInt{
  307. {
  308. UInt: 1,
  309. },
  310. },
  311. },
  312. },
  313. },
  314. },
  315. },
  316. }