guardian_util_test.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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.Team
  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 permissionScenario(desc string, dashboardID int64, sc *scenarioContext, permissions []*m.DashboardAclInfoDTO, fn scenarioFunc) {
  45. bus.ClearBusHandlers()
  46. bus.AddHandler("test", func(query *m.GetDashboardAclInfoListQuery) error {
  47. if query.OrgId != sc.givenUser.OrgId {
  48. sc.reportFailure("Invalid organization id for GetDashboardAclInfoListQuery", sc.givenUser.OrgId, query.OrgId)
  49. }
  50. if query.DashboardId != sc.givenDashboardID {
  51. sc.reportFailure("Invalid dashboard id for GetDashboardAclInfoListQuery", sc.givenDashboardID, query.DashboardId)
  52. }
  53. query.Result = permissions
  54. return nil
  55. })
  56. teams := []*m.Team{}
  57. for _, p := range permissions {
  58. if p.TeamId > 0 {
  59. teams = append(teams, &m.Team{Id: p.TeamId})
  60. }
  61. }
  62. bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
  63. if query.OrgId != sc.givenUser.OrgId {
  64. sc.reportFailure("Invalid organization id for GetTeamsByUserQuery", sc.givenUser.OrgId, query.OrgId)
  65. }
  66. if query.UserId != sc.givenUser.UserId {
  67. sc.reportFailure("Invalid user id for GetTeamsByUserQuery", sc.givenUser.UserId, query.UserId)
  68. }
  69. query.Result = teams
  70. return nil
  71. })
  72. sc.permissionScenario = desc
  73. sc.g = New(dashboardID, sc.givenUser.OrgId, sc.givenUser)
  74. sc.givenDashboardID = dashboardID
  75. sc.givenPermissions = permissions
  76. sc.givenTeams = teams
  77. Convey(desc, func() {
  78. fn(sc)
  79. })
  80. }
  81. type permissionType uint8
  82. const (
  83. USER permissionType = 1 << iota
  84. TEAM
  85. EDITOR
  86. VIEWER
  87. )
  88. func (p permissionType) String() string {
  89. names := map[uint8]string{
  90. uint8(USER): "user",
  91. uint8(TEAM): "team",
  92. uint8(EDITOR): "editor role",
  93. uint8(VIEWER): "viewer role",
  94. }
  95. return names[uint8(p)]
  96. }
  97. type permissionFlags uint8
  98. const (
  99. NO_ACCESS permissionFlags = 1 << iota
  100. CAN_ADMIN
  101. CAN_EDIT
  102. CAN_SAVE
  103. CAN_VIEW
  104. FULL_ACCESS = CAN_ADMIN | CAN_EDIT | CAN_SAVE | CAN_VIEW
  105. EDITOR_ACCESS = CAN_EDIT | CAN_SAVE | CAN_VIEW
  106. VIEWER_ACCESS = CAN_VIEW
  107. )
  108. func (flag permissionFlags) canAdmin() bool {
  109. return flag&CAN_ADMIN != 0
  110. }
  111. func (flag permissionFlags) canEdit() bool {
  112. return flag&CAN_EDIT != 0
  113. }
  114. func (flag permissionFlags) canSave() bool {
  115. return flag&CAN_SAVE != 0
  116. }
  117. func (flag permissionFlags) canView() bool {
  118. return flag&CAN_VIEW != 0
  119. }
  120. func (flag permissionFlags) noAccess() bool {
  121. return flag&(CAN_ADMIN|CAN_EDIT|CAN_SAVE|CAN_VIEW) == 0
  122. }
  123. func (f permissionFlags) String() string {
  124. r := []string{}
  125. if f.canAdmin() {
  126. r = append(r, "admin")
  127. }
  128. if f.canEdit() {
  129. r = append(r, "edit")
  130. }
  131. if f.canSave() {
  132. r = append(r, "save")
  133. }
  134. if f.canView() {
  135. r = append(r, "view")
  136. }
  137. if f.noAccess() {
  138. r = append(r, "<no access>")
  139. }
  140. return strings.Join(r[:], ", ")
  141. }
  142. func (sc *scenarioContext) reportSuccess() {
  143. So(true, ShouldBeTrue)
  144. }
  145. func (sc *scenarioContext) reportFailure(desc string, expected interface{}, actual interface{}) {
  146. var buf bytes.Buffer
  147. buf.WriteString("\n")
  148. buf.WriteString(sc.orgRoleScenario)
  149. buf.WriteString(" ")
  150. buf.WriteString(sc.permissionScenario)
  151. buf.WriteString("\n ")
  152. buf.WriteString(desc)
  153. buf.WriteString("\n")
  154. buf.WriteString(fmt.Sprintf("Source test: %s:%d\n", sc.callerFile, sc.callerLine))
  155. buf.WriteString(fmt.Sprintf("Expected: %v\n", expected))
  156. buf.WriteString(fmt.Sprintf("Actual: %v\n", actual))
  157. buf.WriteString("Context:")
  158. buf.WriteString(fmt.Sprintf("\n Given user: orgRole=%s, id=%d, orgId=%d", sc.givenUser.OrgRole, sc.givenUser.UserId, sc.givenUser.OrgId))
  159. buf.WriteString(fmt.Sprintf("\n Given dashboard id: %d", sc.givenDashboardID))
  160. for i, p := range sc.givenPermissions {
  161. r := "<nil>"
  162. if p.Role != nil {
  163. r = string(*p.Role)
  164. }
  165. 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()))
  166. }
  167. for i, t := range sc.givenTeams {
  168. buf.WriteString(fmt.Sprintf("\n Given team (%d): id=%d", i, t.Id))
  169. }
  170. for i, p := range sc.updatePermissions {
  171. r := "<nil>"
  172. if p.Role != nil {
  173. r = string(*p.Role)
  174. }
  175. 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()))
  176. }
  177. sc.t.Fatalf(buf.String())
  178. }
  179. func newCustomUserPermission(dashboardID int64, userID int64, permission m.PermissionType) *m.DashboardAcl {
  180. return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, UserId: userID, Permission: permission}
  181. }
  182. func newDefaultUserPermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
  183. return newCustomUserPermission(dashboardID, userID, permission)
  184. }
  185. func newCustomTeamPermission(dashboardID int64, teamID int64, permission m.PermissionType) *m.DashboardAcl {
  186. return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, TeamId: teamID, Permission: permission}
  187. }
  188. func newDefaultTeamPermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
  189. return newCustomTeamPermission(dashboardID, teamID, permission)
  190. }
  191. func newAdminRolePermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
  192. return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, Role: &adminRole, Permission: permission}
  193. }
  194. func newEditorRolePermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
  195. return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, Role: &editorRole, Permission: permission}
  196. }
  197. func newViewerRolePermission(dashboardID int64, permission m.PermissionType) *m.DashboardAcl {
  198. return &m.DashboardAcl{OrgId: orgID, DashboardId: dashboardID, Role: &viewerRole, Permission: permission}
  199. }
  200. func toDto(acl *m.DashboardAcl) *m.DashboardAclInfoDTO {
  201. return &m.DashboardAclInfoDTO{
  202. OrgId: acl.OrgId,
  203. DashboardId: acl.DashboardId,
  204. UserId: acl.UserId,
  205. TeamId: acl.TeamId,
  206. Role: acl.Role,
  207. Permission: acl.Permission,
  208. PermissionName: acl.Permission.String(),
  209. }
  210. }