guardian.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. package guardian
  2. import (
  3. "errors"
  4. "github.com/grafana/grafana/pkg/bus"
  5. "github.com/grafana/grafana/pkg/log"
  6. m "github.com/grafana/grafana/pkg/models"
  7. "github.com/grafana/grafana/pkg/setting"
  8. )
  9. var (
  10. ErrGuardianPermissionExists = errors.New("Permission already exists")
  11. ErrGuardianOverride = errors.New("You can only override a permission to be higher")
  12. )
  13. // DashboardGuardian to be used for guard against operations without access on dashboard and acl
  14. type DashboardGuardian interface {
  15. CanSave() (bool, error)
  16. CanEdit() (bool, error)
  17. CanView() (bool, error)
  18. CanAdmin() (bool, error)
  19. HasPermission(permission m.PermissionType) (bool, error)
  20. CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error)
  21. GetAcl() ([]*m.DashboardAclInfoDTO, error)
  22. }
  23. type dashboardGuardianImpl struct {
  24. user *m.SignedInUser
  25. dashId int64
  26. orgId int64
  27. acl []*m.DashboardAclInfoDTO
  28. groups []*m.Team
  29. log log.Logger
  30. }
  31. // New factory for creating a new dashboard guardian instance
  32. var New = func(dashId int64, orgId int64, user *m.SignedInUser) DashboardGuardian {
  33. return &dashboardGuardianImpl{
  34. user: user,
  35. dashId: dashId,
  36. orgId: orgId,
  37. log: log.New("guardians.dashboard"),
  38. }
  39. }
  40. func (g *dashboardGuardianImpl) CanSave() (bool, error) {
  41. return g.HasPermission(m.PERMISSION_EDIT)
  42. }
  43. func (g *dashboardGuardianImpl) CanEdit() (bool, error) {
  44. if setting.ViewersCanEdit {
  45. return g.HasPermission(m.PERMISSION_VIEW)
  46. }
  47. return g.HasPermission(m.PERMISSION_EDIT)
  48. }
  49. func (g *dashboardGuardianImpl) CanView() (bool, error) {
  50. return g.HasPermission(m.PERMISSION_VIEW)
  51. }
  52. func (g *dashboardGuardianImpl) CanAdmin() (bool, error) {
  53. return g.HasPermission(m.PERMISSION_ADMIN)
  54. }
  55. func (g *dashboardGuardianImpl) HasPermission(permission m.PermissionType) (bool, error) {
  56. if g.user.OrgRole == m.ROLE_ADMIN {
  57. return true, nil
  58. }
  59. acl, err := g.GetAcl()
  60. if err != nil {
  61. return false, err
  62. }
  63. return g.checkAcl(permission, acl)
  64. }
  65. func (g *dashboardGuardianImpl) checkAcl(permission m.PermissionType, acl []*m.DashboardAclInfoDTO) (bool, error) {
  66. orgRole := g.user.OrgRole
  67. teamAclItems := []*m.DashboardAclInfoDTO{}
  68. for _, p := range acl {
  69. // user match
  70. if !g.user.IsAnonymous {
  71. if p.UserId == g.user.UserId && p.Permission >= permission {
  72. return true, nil
  73. }
  74. }
  75. // role match
  76. if p.Role != nil {
  77. if *p.Role == orgRole && p.Permission >= permission {
  78. return true, nil
  79. }
  80. }
  81. // remember this rule for later
  82. if p.TeamId > 0 {
  83. teamAclItems = append(teamAclItems, p)
  84. }
  85. }
  86. // do we have team rules?
  87. if len(teamAclItems) == 0 {
  88. return false, nil
  89. }
  90. // load teams
  91. teams, err := g.getTeams()
  92. if err != nil {
  93. return false, err
  94. }
  95. // evaluate team rules
  96. for _, p := range acl {
  97. for _, ug := range teams {
  98. if ug.Id == p.TeamId && p.Permission >= permission {
  99. return true, nil
  100. }
  101. }
  102. }
  103. return false, nil
  104. }
  105. func (g *dashboardGuardianImpl) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) {
  106. acl := []*m.DashboardAclInfoDTO{}
  107. adminRole := m.ROLE_ADMIN
  108. everyoneWithAdminRole := &m.DashboardAclInfoDTO{DashboardId: g.dashId, UserId: 0, TeamId: 0, Role: &adminRole, Permission: m.PERMISSION_ADMIN}
  109. // validate that duplicate permissions don't exists
  110. for _, p := range updatePermissions {
  111. aclItem := &m.DashboardAclInfoDTO{DashboardId: p.DashboardId, UserId: p.UserId, TeamId: p.TeamId, Role: p.Role, Permission: p.Permission}
  112. if aclItem.IsDuplicateOf(everyoneWithAdminRole) {
  113. return false, ErrGuardianPermissionExists
  114. }
  115. for _, a := range acl {
  116. if a.IsDuplicateOf(aclItem) {
  117. return false, ErrGuardianPermissionExists
  118. }
  119. }
  120. acl = append(acl, aclItem)
  121. }
  122. existingPermissions, err := g.GetAcl()
  123. if err != nil {
  124. return false, err
  125. }
  126. // validate overridden permissions to be higher
  127. for _, a := range acl {
  128. for _, existingPerm := range existingPermissions {
  129. // handle default permissions
  130. if existingPerm.DashboardId == -1 {
  131. existingPerm.DashboardId = g.dashId
  132. }
  133. if a.DashboardId == existingPerm.DashboardId {
  134. continue
  135. }
  136. if a.IsDuplicateOf(existingPerm) && a.Permission <= existingPerm.Permission {
  137. return false, ErrGuardianOverride
  138. }
  139. }
  140. }
  141. if g.user.OrgRole == m.ROLE_ADMIN {
  142. return true, nil
  143. }
  144. return g.checkAcl(permission, acl)
  145. }
  146. // GetAcl returns dashboard acl
  147. func (g *dashboardGuardianImpl) GetAcl() ([]*m.DashboardAclInfoDTO, error) {
  148. if g.acl != nil {
  149. return g.acl, nil
  150. }
  151. query := m.GetDashboardAclInfoListQuery{DashboardId: g.dashId, OrgId: g.orgId}
  152. if err := bus.Dispatch(&query); err != nil {
  153. return nil, err
  154. }
  155. for _, a := range query.Result {
  156. // handle default permissions
  157. if a.DashboardId == -1 {
  158. a.DashboardId = g.dashId
  159. }
  160. }
  161. g.acl = query.Result
  162. return g.acl, nil
  163. }
  164. func (g *dashboardGuardianImpl) getTeams() ([]*m.Team, error) {
  165. if g.groups != nil {
  166. return g.groups, nil
  167. }
  168. query := m.GetTeamsByUserQuery{OrgId: g.orgId, UserId: g.user.UserId}
  169. err := bus.Dispatch(&query)
  170. g.groups = query.Result
  171. return query.Result, err
  172. }
  173. type FakeDashboardGuardian struct {
  174. DashId int64
  175. OrgId int64
  176. User *m.SignedInUser
  177. CanSaveValue bool
  178. CanEditValue bool
  179. CanViewValue bool
  180. CanAdminValue bool
  181. HasPermissionValue bool
  182. CheckPermissionBeforeUpdateValue bool
  183. CheckPermissionBeforeUpdateError error
  184. GetAclValue []*m.DashboardAclInfoDTO
  185. }
  186. func (g *FakeDashboardGuardian) CanSave() (bool, error) {
  187. return g.CanSaveValue, nil
  188. }
  189. func (g *FakeDashboardGuardian) CanEdit() (bool, error) {
  190. return g.CanEditValue, nil
  191. }
  192. func (g *FakeDashboardGuardian) CanView() (bool, error) {
  193. return g.CanViewValue, nil
  194. }
  195. func (g *FakeDashboardGuardian) CanAdmin() (bool, error) {
  196. return g.CanAdminValue, nil
  197. }
  198. func (g *FakeDashboardGuardian) HasPermission(permission m.PermissionType) (bool, error) {
  199. return g.HasPermissionValue, nil
  200. }
  201. func (g *FakeDashboardGuardian) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) {
  202. return g.CheckPermissionBeforeUpdateValue, g.CheckPermissionBeforeUpdateError
  203. }
  204. func (g *FakeDashboardGuardian) GetAcl() ([]*m.DashboardAclInfoDTO, error) {
  205. return g.GetAclValue, nil
  206. }
  207. func MockDashboardGuardian(mock *FakeDashboardGuardian) {
  208. New = func(dashId int64, orgId int64, user *m.SignedInUser) DashboardGuardian {
  209. mock.OrgId = orgId
  210. mock.DashId = dashId
  211. mock.User = user
  212. return mock
  213. }
  214. }