middleware.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package middleware
  2. import (
  3. "strconv"
  4. "strings"
  5. "github.com/Unknwon/macaron"
  6. "github.com/grafana/grafana/pkg/bus"
  7. "github.com/grafana/grafana/pkg/components/apikeygen"
  8. "github.com/grafana/grafana/pkg/log"
  9. "github.com/grafana/grafana/pkg/metrics"
  10. m "github.com/grafana/grafana/pkg/models"
  11. "github.com/grafana/grafana/pkg/setting"
  12. )
  13. type Context struct {
  14. *macaron.Context
  15. *m.SignedInUser
  16. Session SessionStore
  17. IsSignedIn bool
  18. AllowAnonymous bool
  19. }
  20. func GetContextHandler() macaron.Handler {
  21. return func(c *macaron.Context) {
  22. ctx := &Context{
  23. Context: c,
  24. SignedInUser: &m.SignedInUser{},
  25. Session: GetSession(),
  26. IsSignedIn: false,
  27. AllowAnonymous: false,
  28. }
  29. h := ctx.Req.Host
  30. if i := strings.Index(h, ":"); i >= 0 {
  31. h = h[:i]
  32. }
  33. if !strings.EqualFold(h, setting.Domain) {
  34. ctx.Redirect(strings.TrimSuffix(setting.AppUrl, "/") + ctx.Req.RequestURI, 301)
  35. return
  36. }
  37. // the order in which these are tested are important
  38. // look for api key in Authorization header first
  39. // then init session and look for userId in session
  40. // then look for api key in session (special case for render calls via api)
  41. // then test if anonymous access is enabled
  42. if initContextWithApiKey(ctx) ||
  43. initContextWithUserSessionCookie(ctx) ||
  44. initContextWithApiKeyFromSession(ctx) ||
  45. initContextWithAnonymousUser(ctx) {
  46. }
  47. c.Map(ctx)
  48. }
  49. }
  50. func initContextWithAnonymousUser(ctx *Context) bool {
  51. if !setting.AnonymousEnabled {
  52. return false
  53. }
  54. orgQuery := m.GetOrgByNameQuery{Name: setting.AnonymousOrgName}
  55. if err := bus.Dispatch(&orgQuery); err != nil {
  56. log.Error(3, "Anonymous access organization error: '%s': %s", setting.AnonymousOrgName, err)
  57. return false
  58. } else {
  59. ctx.IsSignedIn = false
  60. ctx.AllowAnonymous = true
  61. ctx.SignedInUser = &m.SignedInUser{}
  62. ctx.OrgRole = m.RoleType(setting.AnonymousOrgRole)
  63. ctx.OrgId = orgQuery.Result.Id
  64. ctx.OrgName = orgQuery.Result.Name
  65. return true
  66. }
  67. }
  68. func initContextWithUserSessionCookie(ctx *Context) bool {
  69. // initialize session
  70. if err := ctx.Session.Start(ctx); err != nil {
  71. log.Error(3, "Failed to start session", err)
  72. return false
  73. }
  74. var userId int64
  75. if userId = getRequestUserId(ctx); userId == 0 {
  76. return false
  77. }
  78. query := m.GetSignedInUserQuery{UserId: userId}
  79. if err := bus.Dispatch(&query); err != nil {
  80. return false
  81. } else {
  82. ctx.SignedInUser = query.Result
  83. ctx.IsSignedIn = true
  84. return true
  85. }
  86. }
  87. func initContextWithApiKey(ctx *Context) bool {
  88. var keyString string
  89. if keyString = getApiKey(ctx); keyString == "" {
  90. return false
  91. }
  92. // base64 decode key
  93. decoded, err := apikeygen.Decode(keyString)
  94. if err != nil {
  95. ctx.JsonApiErr(401, "Invalid API key", err)
  96. return true
  97. }
  98. // fetch key
  99. keyQuery := m.GetApiKeyByNameQuery{KeyName: decoded.Name, OrgId: decoded.OrgId}
  100. if err := bus.Dispatch(&keyQuery); err != nil {
  101. ctx.JsonApiErr(401, "Invalid API key", err)
  102. return true
  103. } else {
  104. apikey := keyQuery.Result
  105. // validate api key
  106. if !apikeygen.IsValid(decoded, apikey.Key) {
  107. ctx.JsonApiErr(401, "Invalid API key", err)
  108. return true
  109. }
  110. ctx.IsSignedIn = true
  111. ctx.SignedInUser = &m.SignedInUser{}
  112. ctx.OrgRole = apikey.Role
  113. ctx.ApiKeyId = apikey.Id
  114. ctx.OrgId = apikey.OrgId
  115. return true
  116. }
  117. }
  118. // special case for panel render calls with api key
  119. func initContextWithApiKeyFromSession(ctx *Context) bool {
  120. keyId := ctx.Session.Get(SESS_KEY_APIKEY)
  121. if keyId == nil {
  122. return false
  123. }
  124. keyQuery := m.GetApiKeyByIdQuery{ApiKeyId: keyId.(int64)}
  125. if err := bus.Dispatch(&keyQuery); err != nil {
  126. log.Error(3, "Failed to get api key by id", err)
  127. return false
  128. } else {
  129. apikey := keyQuery.Result
  130. ctx.IsSignedIn = true
  131. ctx.SignedInUser = &m.SignedInUser{}
  132. ctx.OrgRole = apikey.Role
  133. ctx.ApiKeyId = apikey.Id
  134. ctx.OrgId = apikey.OrgId
  135. return true
  136. }
  137. }
  138. // Handle handles and logs error by given status.
  139. func (ctx *Context) Handle(status int, title string, err error) {
  140. if err != nil {
  141. log.Error(4, "%s: %v", title, err)
  142. if setting.Env != setting.PROD {
  143. ctx.Data["ErrorMsg"] = err
  144. }
  145. }
  146. switch status {
  147. case 200:
  148. metrics.M_Page_Status_200.Inc(1)
  149. case 404:
  150. metrics.M_Page_Status_404.Inc(1)
  151. case 500:
  152. metrics.M_Page_Status_500.Inc(1)
  153. }
  154. ctx.Data["Title"] = title
  155. ctx.HTML(status, strconv.Itoa(status))
  156. }
  157. func (ctx *Context) JsonOK(message string) {
  158. resp := make(map[string]interface{})
  159. resp["message"] = message
  160. ctx.JSON(200, resp)
  161. }
  162. func (ctx *Context) IsApiRequest() bool {
  163. return strings.HasPrefix(ctx.Req.URL.Path, "/api")
  164. }
  165. func (ctx *Context) JsonApiErr(status int, message string, err error) {
  166. resp := make(map[string]interface{})
  167. if err != nil {
  168. log.Error(4, "%s: %v", message, err)
  169. if setting.Env != setting.PROD {
  170. resp["error"] = err.Error()
  171. }
  172. }
  173. switch status {
  174. case 404:
  175. resp["message"] = "Not Found"
  176. metrics.M_Api_Status_500.Inc(1)
  177. case 500:
  178. metrics.M_Api_Status_404.Inc(1)
  179. resp["message"] = "Internal Server Error"
  180. }
  181. if message != "" {
  182. resp["message"] = message
  183. }
  184. ctx.JSON(status, resp)
  185. }