guardian_util_test.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. package guardian
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strings"
  6. "testing"
  7. "github.com/grafana/grafana/pkg/bus"
  8. m "github.com/grafana/grafana/pkg/models"
  9. . "github.com/smartystreets/goconvey/convey"
  10. )
  11. type scenarioContext struct {
  12. t *testing.T
  13. orgRoleScenario string
  14. permissionScenario string
  15. g DashboardGuardian
  16. givenUser *m.SignedInUser
  17. givenDashboardID int64
  18. givenPermissions []*m.DashboardAclInfoDTO
  19. givenTeams []*m.TeamDTO
  20. updatePermissions []*m.DashboardAcl
  21. expectedFlags permissionFlags
  22. callerFile string
  23. callerLine int
  24. }
  25. type scenarioFunc func(c *scenarioContext)
  26. func orgRoleScenario(desc string, t *testing.T, role m.RoleType, fn scenarioFunc) {
  27. user := &m.SignedInUser{
  28. UserId: userID,
  29. OrgId: orgID,
  30. OrgRole: role,
  31. }
  32. guard := New(dashboardID, orgID, user)
  33. sc := &scenarioContext{
  34. t: t,
  35. orgRoleScenario: desc,
  36. givenUser: user,
  37. givenDashboardID: dashboardID,
  38. g: guard,
  39. }
  40. Convey(desc, func() {
  41. fn(sc)
  42. })
  43. }
  44. func apiKeyScenario(desc string, t *testing.T, role m.RoleType, fn scenarioFunc) {
  45. user := &m.SignedInUser{
  46. UserId: 0,
  47. OrgId: orgID,
  48. OrgRole: role,
  49. ApiKeyId: 10,
  50. }
  51. guard := New(dashboardID, orgID, user)
  52. sc := &scenarioContext{
  53. t: t,
  54. orgRoleScenario: desc,
  55. givenUser: user,
  56. givenDashboardID: dashboardID,
  57. g: guard,
  58. }
  59. Convey(desc, func() {
  60. fn(sc)
  61. })
  62. }
  63. func permissionScenario(desc string, dashboardID int64, sc *scenarioContext, permissions []*m.DashboardAclInfoDTO, fn scenarioFunc) {
  64. bus.ClearBusHandlers()
  65. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  66. if query.OrgId != sc.givenUser.OrgId {
  67. sc.reportFailure("Invalid organization id for GetDashboardAclInfoListQuery", sc.givenUser.OrgId, query.OrgId)
  68. }
  69. if query.DashboardId != sc.givenDashboardID {
  70. sc.reportFailure("Invalid dashboard id for GetDashboardAclInfoListQuery", sc.givenDashboardID, query.DashboardId)
  71. }
  72. query.Result = permissions
  73. return nil
  74. })
  75. teams := []*m.TeamDTO{}
  76. for _, p := range permissions {
  77. if p.TeamId > 0 {
  78. teams = append(teams, &m.TeamDTO{Id: p.TeamId})
  79. }
  80. }
  81. bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
  82. if query.OrgId != sc.givenUser.OrgId {
  83. sc.reportFailure("Invalid organization id for GetTeamsByUserQuery", sc.givenUser.OrgId, query.OrgId)
  84. }
  85. if query.UserId != sc.givenUser.UserId {
  86. sc.reportFailure("Invalid user id for GetTeamsByUserQuery", sc.givenUser.UserId, query.UserId)
  87. }
  88. query.Result = teams
  89. return nil
  90. })
  91. sc.permissionScenario = desc
  92. sc.g = New(dashboardID, sc.givenUser.OrgId, sc.givenUser)
  93. sc.givenDashboardID = dashboardID
  94. sc.givenPermissions = permissions
  95. sc.givenTeams = teams
  96. Convey(desc, func() {
  97. fn(sc)
  98. })
  99. }
  100. type permissionType uint8
  101. const (
  102. USER permissionType = 1 << iota
  103. TEAM
  104. EDITOR
  105. VIEWER
  106. )
  107. func (p permissionType) String() string {
  108. names := map[uint8]string{
  109. uint8(USER): "user",
  110. uint8(TEAM): "team",
  111. uint8(EDITOR): "editor role",
  112. uint8(VIEWER): "viewer role",
  113. }
  114. return names[uint8(p)]
  115. }
  116. type permissionFlags uint8
  117. const (
  118. NO_ACCESS permissionFlags = 1 << iota
  119. CAN_ADMIN
  120. CAN_EDIT
  121. CAN_SAVE
  122. CAN_VIEW
  123. FULL_ACCESS = CAN_ADMIN | CAN_EDIT | CAN_SAVE | CAN_VIEW
  124. EDITOR_ACCESS = CAN_EDIT | CAN_SAVE | CAN_VIEW
  125. VIEWER_ACCESS = CAN_VIEW
  126. )
  127. func (flag permissionFlags) canAdmin() bool {
  128. return flag&CAN_ADMIN != 0
  129. }
  130. func (flag permissionFlags) canEdit() bool {
  131. return flag&CAN_EDIT != 0
  132. }
  133. func (flag permissionFlags) canSave() bool {
  134. return flag&CAN_SAVE != 0
  135. }
  136. func (flag permissionFlags) canView() bool {
  137. return flag&CAN_VIEW != 0
  138. }
  139. func (flag permissionFlags) noAccess() bool {
  140. return flag&(CAN_ADMIN|CAN_EDIT|CAN_SAVE|CAN_VIEW) == 0
  141. }
  142. func (f permissionFlags) String() string {
  143. r := []string{}
  144. if f.canAdmin() {
  145. r = append(r, "admin")
  146. }
  147. if f.canEdit() {
  148. r = append(r, "edit")
  149. }
  150. if f.canSave() {
  151. r = append(r, "save")
  152. }
  153. if f.canView() {
  154. r = append(r, "view")
  155. }
  156. if f.noAccess() {
  157. r = append(r, "<no access>")
  158. }
  159. return strings.Join(r[:], ", ")
  160. }
  161. func (sc *scenarioContext) reportSuccess() {
  162. So(true, ShouldBeTrue)
  163. }
  164. func (sc *scenarioContext) reportFailure(desc string, expected interface{}, actual interface{}) {
  165. var buf bytes.Buffer
  166. buf.WriteString("\n")
  167. buf.WriteString(sc.orgRoleScenario)
  168. buf.WriteString(" ")
  169. buf.WriteString(sc.permissionScenario)
  170. buf.WriteString("\n ")
  171. buf.WriteString(desc)
  172. buf.WriteString("\n")
  173. buf.WriteString(fmt.Sprintf("Source test: %s:%d\n", sc.callerFile, sc.callerLine))
  174. buf.WriteString(fmt.Sprintf("Expected: %v\n", expected))
  175. buf.WriteString(fmt.Sprintf("Actual: %v\n", actual))
  176. buf.WriteString("Context:")
  177. buf.WriteString(fmt.Sprintf("\n Given user: orgRole=%s, id=%d, orgId=%d", sc.givenUser.OrgRole, sc.givenUser.UserId, sc.givenUser.OrgId))
  178. buf.WriteString(fmt.Sprintf("\n Given dashboard id: %d", sc.givenDashboardID))
  179. for i, p := range sc.givenPermissions {
  180. r := "<nil>"
  181. if p.Role != nil {
  182. r = string(*p.Role)
  183. }
  184. buf.WriteString(fmt.Sprintf("\n Given permission (%d): dashboardId=%d, userId=%d, teamId=%d, role=%v, permission=%s", i, p.DashboardId, p.UserId, p.TeamId, r, p.Permission.String()))
  185. }
  186. for i, t := range sc.givenTeams {
  187. buf.WriteString(fmt.Sprintf("\n Given team (%d): id=%d", i, t.Id))
  188. }
  189. for i, p := range sc.updatePermissions {
  190. r := "<nil>"
  191. if p.Role != nil {
  192. r = string(*p.Role)
  193. }
  194. buf.WriteString(fmt.Sprintf("\n Update permission (%d): dashboardId=%d, userId=%d, teamId=%d, role=%v, permission=%s", i, p.DashboardId, p.UserId, p.TeamId, r, p.Permission.String()))
  195. }
  196. sc.t.Fatalf(buf.String())
  197. }
  198. func newCustomUserPermission(dashboardID int64, userID int64, permission m.PermissionType) *m.DashboardAcl {
  199. return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, UserId: userID, Permission: permission}
  200. }
  201. func newDefaultUserPermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
  202. return newCustomUserPermission(dashboardID, userID, permission)
  203. }
  204. func newCustomTeamPermission(dashboardID int64, teamID int64, permission m.PermissionType) *m.DashboardAcl {
  205. return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, TeamId: teamID, Permission: permission}
  206. }
  207. func newDefaultTeamPermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
  208. return newCustomTeamPermission(dashboardID, teamID, permission)
  209. }
  210. func newAdminRolePermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
  211. return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, Role: &adminRole, Permission: permission}
  212. }
  213. func newEditorRolePermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
  214. return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, Role: &editorRole, Permission: permission}
  215. }
  216. func newViewerRolePermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
  217. return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, Role: &viewerRole, Permission: permission}
  218. }
  219. func toDto(acl *m.DashboardAcl) *m.DashboardAclInfoDTO {
  220. return &m.DashboardAclInfoDTO{
  221. OrgId: acl.OrgId,
  222. DashboardId: acl.DashboardId,
  223. UserId: acl.UserId,
  224. TeamId: acl.TeamId,
  225. Role: acl.Role,
  226. Permission: acl.Permission,
  227. PermissionName: acl.Permission.String(),
  228. }
  229. }