/session/manager_http.go

https://github.com/ory/kratos · Go · 158 lines · 128 code · 28 blank · 2 comment · 35 complexity · 52160a0a21add9b042a09a4a5808d3c0 MD5 · raw file

  1. package session
  2. import (
  3. "context"
  4. "net/http"
  5. "time"
  6. "github.com/pkg/errors"
  7. "github.com/ory/x/sqlcon"
  8. "github.com/ory/herodot"
  9. "github.com/ory/kratos/identity"
  10. "github.com/ory/kratos/x"
  11. )
  12. type (
  13. managerHTTPDependencies interface {
  14. PersistenceProvider
  15. x.CookieProvider
  16. identity.PoolProvider
  17. x.CSRFProvider
  18. }
  19. managerHTTPConfiguration interface {
  20. SessionPersistentCookie() bool
  21. SessionLifespan() time.Duration
  22. SecretsSession() [][]byte
  23. SessionSameSiteMode() http.SameSite
  24. SessionDomain() string
  25. SessionPath() string
  26. }
  27. ManagerHTTP struct {
  28. c managerHTTPConfiguration
  29. cookieName string
  30. r managerHTTPDependencies
  31. }
  32. )
  33. func NewManagerHTTP(
  34. c managerHTTPConfiguration,
  35. r managerHTTPDependencies,
  36. ) *ManagerHTTP {
  37. return &ManagerHTTP{
  38. c: c,
  39. r: r,
  40. cookieName: DefaultSessionCookieName,
  41. }
  42. }
  43. func (s *ManagerHTTP) CreateAndIssueCookie(ctx context.Context, w http.ResponseWriter, r *http.Request, ss *Session) error {
  44. if err := s.r.SessionPersister().CreateSession(ctx, ss); err != nil {
  45. return err
  46. }
  47. if err := s.IssueCookie(ctx, w, r, ss); err != nil {
  48. return err
  49. }
  50. return nil
  51. }
  52. func (s *ManagerHTTP) IssueCookie(ctx context.Context, w http.ResponseWriter, r *http.Request, session *Session) error {
  53. cookie, _ := s.r.CookieManager().Get(r, s.cookieName)
  54. if s.c.SessionDomain() != "" {
  55. cookie.Options.Domain = s.c.SessionDomain()
  56. }
  57. old, err := s.FetchFromRequest(context.Background(), r)
  58. if err != nil {
  59. // No session was set prior -> regenerate anti-csrf token
  60. _ = s.r.CSRFHandler().RegenerateToken(w, r)
  61. } else if old.Identity.ID != session.Identity.ID {
  62. // No session was set prior -> regenerate anti-csrf token
  63. _ = s.r.CSRFHandler().RegenerateToken(w, r)
  64. }
  65. if s.c.SessionPath() != "" {
  66. cookie.Options.Path = s.c.SessionPath()
  67. }
  68. if s.c.SessionSameSiteMode() != 0 {
  69. cookie.Options.SameSite = s.c.SessionSameSiteMode()
  70. }
  71. cookie.Options.MaxAge = 0
  72. if s.c.SessionPersistentCookie() {
  73. cookie.Options.MaxAge = int(s.c.SessionLifespan().Seconds())
  74. }
  75. cookie.Values["session_token"] = session.Token
  76. if err := cookie.Save(r, w); err != nil {
  77. return errors.WithStack(err)
  78. }
  79. return nil
  80. }
  81. func (s *ManagerHTTP) extractToken(r *http.Request) string {
  82. if token, ok := bearerTokenFromRequest(r); ok {
  83. return token
  84. }
  85. cookie, err := s.r.CookieManager().Get(r, s.cookieName)
  86. if err != nil {
  87. return ""
  88. }
  89. token, ok := cookie.Values["session_token"].(string)
  90. if ok {
  91. return token
  92. }
  93. return ""
  94. }
  95. func (s *ManagerHTTP) FetchFromRequest(ctx context.Context, r *http.Request) (*Session, error) {
  96. token := s.extractToken(r)
  97. if token == "" {
  98. return nil, errors.WithStack(ErrNoActiveSessionFound)
  99. }
  100. se, err := s.r.SessionPersister().GetSessionByToken(ctx, token)
  101. if err != nil {
  102. if errors.Is(err, herodot.ErrNotFound) || errors.Is(err, sqlcon.ErrNoRows) {
  103. return nil, errors.WithStack(ErrNoActiveSessionFound)
  104. }
  105. return nil, err
  106. }
  107. if !se.IsActive() {
  108. return nil, errors.WithStack(ErrNoActiveSessionFound)
  109. }
  110. se.Identity = se.Identity.CopyWithoutCredentials()
  111. return se, nil
  112. }
  113. func (s *ManagerHTTP) PurgeFromRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
  114. if token, ok := bearerTokenFromRequest(r); ok {
  115. return errors.WithStack(s.r.SessionPersister().RevokeSessionByToken(ctx, token))
  116. }
  117. cookie, _ := s.r.CookieManager().Get(r, s.cookieName)
  118. token, ok := cookie.Values["session_token"].(string)
  119. if !ok {
  120. return nil
  121. }
  122. if err := s.r.SessionPersister().RevokeSessionByToken(ctx, token); err != nil {
  123. return errors.WithStack(err)
  124. }
  125. cookie.Options.MaxAge = -1
  126. if err := cookie.Save(r, w); err != nil {
  127. return errors.WithStack(err)
  128. }
  129. return nil
  130. }