guardian.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  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. teams []*m.TeamDTO
  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 && p.UserId > 0 {
  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. if !existingPerm.Inherited {
  130. continue
  131. }
  132. if a.IsDuplicateOf(existingPerm) && a.Permission <= existingPerm.Permission {
  133. return false, ErrGuardianOverride
  134. }
  135. }
  136. }
  137. if g.user.OrgRole == m.ROLE_ADMIN {
  138. return true, nil
  139. }
  140. return g.checkAcl(permission, existingPermissions)
  141. }
  142. // GetAcl returns dashboard acl
  143. func (g *dashboardGuardianImpl) GetAcl() ([]*m.DashboardAclInfoDTO, error) {
  144. if g.acl != nil {
  145. return g.acl, nil
  146. }
  147. query := m.GetDashboardAclInfoListQuery{DashboardId: g.dashId, OrgId: g.orgId}
  148. if err := bus.Dispatch(&query); err != nil {
  149. return nil, err
  150. }
  151. g.acl = query.Result
  152. return g.acl, nil
  153. }
  154. func (g *dashboardGuardianImpl) getTeams() ([]*m.TeamDTO, error) {
  155. if g.teams != nil {
  156. return g.teams, nil
  157. }
  158. query := m.GetTeamsByUserQuery{OrgId: g.orgId, UserId: g.user.UserId}
  159. err := bus.Dispatch(&query)
  160. g.teams = query.Result
  161. return query.Result, err
  162. }
  163. type FakeDashboardGuardian struct {
  164. DashId int64
  165. OrgId int64
  166. User *m.SignedInUser
  167. CanSaveValue bool
  168. CanEditValue bool
  169. CanViewValue bool
  170. CanAdminValue bool
  171. HasPermissionValue bool
  172. CheckPermissionBeforeUpdateValue bool
  173. CheckPermissionBeforeUpdateError error
  174. GetAclValue []*m.DashboardAclInfoDTO
  175. }
  176. func (g *FakeDashboardGuardian) CanSave() (bool, error) {
  177. return g.CanSaveValue, nil
  178. }
  179. func (g *FakeDashboardGuardian) CanEdit() (bool, error) {
  180. return g.CanEditValue, nil
  181. }
  182. func (g *FakeDashboardGuardian) CanView() (bool, error) {
  183. return g.CanViewValue, nil
  184. }
  185. func (g *FakeDashboardGuardian) CanAdmin() (bool, error) {
  186. return g.CanAdminValue, nil
  187. }
  188. func (g *FakeDashboardGuardian) HasPermission(permission m.PermissionType) (bool, error) {
  189. return g.HasPermissionValue, nil
  190. }
  191. func (g *FakeDashboardGuardian) CheckPermissionBeforeUpdate(permission m.PermissionType, updatePermissions []*m.DashboardAcl) (bool, error) {
  192. return g.CheckPermissionBeforeUpdateValue, g.CheckPermissionBeforeUpdateError
  193. }
  194. func (g *FakeDashboardGuardian) GetAcl() ([]*m.DashboardAclInfoDTO, error) {
  195. return g.GetAclValue, nil
  196. }
  197. func MockDashboardGuardian(mock *FakeDashboardGuardian) {
  198. New = func(dashId int64, orgId int64, user *m.SignedInUser) DashboardGuardian {
  199. mock.OrgId = orgId
  200. mock.DashId = dashId
  201. mock.User = user
  202. return mock
  203. }
  204. }