middleware.go 4.7 KB

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