auth_token.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package auth
  2. import (
  3. "crypto/sha256"
  4. "encoding/hex"
  5. "time"
  6. "github.com/grafana/grafana/pkg/models"
  7. "github.com/grafana/grafana/pkg/setting"
  8. "github.com/grafana/grafana/pkg/util"
  9. macaron "gopkg.in/macaron.v1"
  10. "github.com/grafana/grafana/pkg/log"
  11. "github.com/grafana/grafana/pkg/registry"
  12. "github.com/grafana/grafana/pkg/services/sqlstore"
  13. )
  14. func init() {
  15. registry.RegisterService(&UserAuthTokenService{})
  16. }
  17. var now = time.Now
  18. // UserAuthTokenService are used for generating and validating user auth tokens
  19. type UserAuthTokenService struct {
  20. SQLStore *sqlstore.SqlStore `inject:""`
  21. log log.Logger
  22. }
  23. // Init this service
  24. func (s *UserAuthTokenService) Init() error {
  25. s.log = log.New("auth")
  26. return nil
  27. }
  28. const sessionCookieKey = "grafana_session"
  29. func (s *UserAuthTokenService) UserAuthenticatedHook(user *models.User, c *models.ReqContext) error {
  30. userToken, err := s.CreateToken(user.Id, c.RemoteAddr(), c.Req.UserAgent())
  31. if err != nil {
  32. return err
  33. }
  34. c.Resp.Header().Del("Set-Cookie")
  35. c.SetCookie(sessionCookieKey, userToken.unhashedToken, setting.AppSubUrl+"/", setting.Domain, false, true)
  36. return nil
  37. }
  38. func (s *UserAuthTokenService) UserSignedOutHook(c *models.ReqContext) {
  39. c.SetCookie(sessionCookieKey, "", -1, setting.AppSubUrl+"/", setting.Domain, false, true)
  40. }
  41. func (s *UserAuthTokenService) RequestMiddleware() macaron.Handler {
  42. return func(ctx *models.ReqContext) {
  43. authToken := ctx.GetCookie(sessionCookieKey)
  44. userToken, err := s.lookupToken(authToken)
  45. if err != nil {
  46. }
  47. ctx.Next()
  48. refreshed, err := s.refreshToken(userToken, ctx.RemoteAddr(), ctx.Req.UserAgent())
  49. if err != nil {
  50. }
  51. if refreshed {
  52. ctx.Resp.Header().Del("Set-Cookie")
  53. ctx.SetCookie(sessionCookieKey, userToken.unhashedToken, setting.AppSubUrl+"/", setting.Domain, false, true)
  54. }
  55. }
  56. }
  57. func (s *UserAuthTokenService) CreateToken(userId int64, clientIP, userAgent string) (*userAuthToken, error) {
  58. clientIP = util.ParseIPAddress(clientIP)
  59. token, err := util.RandomHex(16)
  60. if err != nil {
  61. return nil, err
  62. }
  63. hashedToken := hashToken(token)
  64. userToken := userAuthToken{
  65. UserId: userId,
  66. AuthToken: hashedToken,
  67. PrevAuthToken: hashedToken,
  68. ClientIp: clientIP,
  69. UserAgent: userAgent,
  70. RotatedAt: now().Unix(),
  71. CreatedAt: now().Unix(),
  72. UpdatedAt: now().Unix(),
  73. SeenAt: 0,
  74. AuthTokenSeen: false,
  75. }
  76. _, err = s.SQLStore.NewSession().Insert(&userToken)
  77. if err != nil {
  78. return nil, err
  79. }
  80. userToken.unhashedToken = token
  81. return &userToken, nil
  82. }
  83. func (s *UserAuthTokenService) lookupToken(unhashedToken string) (*userAuthToken, error) {
  84. hashedToken := hashToken(unhashedToken)
  85. var userToken userAuthToken
  86. exists, err := s.SQLStore.NewSession().Where("auth_token = ? OR prev_auth_token = ?", hashedToken, hashedToken).Get(&userToken)
  87. if err != nil {
  88. return nil, err
  89. }
  90. if !exists {
  91. return nil, ErrAuthTokenNotFound
  92. }
  93. if userToken.AuthToken != hashedToken && userToken.PrevAuthToken == hashedToken && userToken.AuthTokenSeen {
  94. userToken.AuthTokenSeen = false
  95. expireBefore := now().Add(-1 * time.Minute).Unix()
  96. affectedRows, err := s.SQLStore.NewSession().Where("id = ? AND prev_auth_token = ? AND rotated_at < ?", userToken.Id, userToken.PrevAuthToken, expireBefore).AllCols().Update(&userToken)
  97. if err != nil {
  98. return nil, err
  99. }
  100. if affectedRows == 0 {
  101. s.log.Debug("prev seen token unchanged", "userTokenId", userToken.Id, "userId", userToken.UserId, "authToken", userToken.AuthToken, "clientIP", userToken.ClientIp, "userAgent", userToken.UserAgent)
  102. } else {
  103. s.log.Debug("prev seen token", "userTokenId", userToken.Id, "userId", userToken.UserId, "authToken", userToken.AuthToken, "clientIP", userToken.ClientIp, "userAgent", userToken.UserAgent)
  104. }
  105. }
  106. if !userToken.AuthTokenSeen && userToken.AuthToken == hashedToken {
  107. userTokenCopy := userToken
  108. userTokenCopy.AuthTokenSeen = true
  109. userTokenCopy.SeenAt = now().Unix()
  110. affectedRows, err := s.SQLStore.NewSession().Where("id = ? AND auth_token = ?", userTokenCopy.Id, userTokenCopy.AuthToken).AllCols().Update(&userTokenCopy)
  111. if err != nil {
  112. return nil, err
  113. }
  114. if affectedRows == 1 {
  115. userToken = userTokenCopy
  116. }
  117. if affectedRows == 0 {
  118. s.log.Debug("seen wrong token", "userTokenId", userToken.Id, "userId", userToken.UserId, "authToken", userToken.AuthToken, "clientIP", userToken.ClientIp, "userAgent", userToken.UserAgent)
  119. } else {
  120. s.log.Debug("seen token", "userTokenId", userToken.Id, "userId", userToken.UserId, "authToken", userToken.AuthToken, "clientIP", userToken.ClientIp, "userAgent", userToken.UserAgent)
  121. }
  122. }
  123. userToken.unhashedToken = unhashedToken
  124. return &userToken, nil
  125. }
  126. func (s *UserAuthTokenService) refreshToken(token *userAuthToken, clientIP, userAgent string) (bool, error) {
  127. // lookup token in db
  128. // refresh token if needed
  129. return false, nil
  130. }
  131. func hashToken(token string) string {
  132. hashBytes := sha256.Sum256([]byte(token + setting.SecretKey))
  133. return hex.EncodeToString(hashBytes[:])
  134. }