oauth2_callback.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright 2017 Frédéric Guillot. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package ui // import "miniflux.app/ui"
  5. import (
  6. "net/http"
  7. "miniflux.app/http/cookie"
  8. "miniflux.app/http/request"
  9. "miniflux.app/http/response/html"
  10. "miniflux.app/http/route"
  11. "miniflux.app/locale"
  12. "miniflux.app/logger"
  13. "miniflux.app/model"
  14. "miniflux.app/ui/session"
  15. )
  16. func (h *handler) oauth2Callback(w http.ResponseWriter, r *http.Request) {
  17. clientIP := request.ClientIP(r)
  18. printer := locale.NewPrinter(request.UserLanguage(r))
  19. sess := session.New(h.store, request.SessionID(r))
  20. provider := request.RouteStringParam(r, "provider")
  21. if provider == "" {
  22. logger.Error("[OAuth2] Invalid or missing provider")
  23. html.Redirect(w, r, route.Path(h.router, "login"))
  24. return
  25. }
  26. code := request.QueryStringParam(r, "code", "")
  27. if code == "" {
  28. logger.Error("[OAuth2] No code received on callback")
  29. html.Redirect(w, r, route.Path(h.router, "login"))
  30. return
  31. }
  32. state := request.QueryStringParam(r, "state", "")
  33. if state == "" || state != request.OAuth2State(r) {
  34. logger.Error(`[OAuth2] Invalid state value: got "%s" instead of "%s"`, state, request.OAuth2State(r))
  35. html.Redirect(w, r, route.Path(h.router, "login"))
  36. return
  37. }
  38. authProvider, err := getOAuth2Manager(h.cfg).Provider(provider)
  39. if err != nil {
  40. logger.Error("[OAuth2] %v", err)
  41. html.Redirect(w, r, route.Path(h.router, "login"))
  42. return
  43. }
  44. profile, err := authProvider.GetProfile(code)
  45. if err != nil {
  46. logger.Error("[OAuth2] %v", err)
  47. html.Redirect(w, r, route.Path(h.router, "login"))
  48. return
  49. }
  50. logger.Info("[OAuth2] [ClientIP=%s] Successful auth for %s", clientIP, profile)
  51. if request.IsAuthenticated(r) {
  52. user, err := h.store.UserByExtraField(profile.Key, profile.ID)
  53. if err != nil {
  54. html.ServerError(w, r, err)
  55. return
  56. }
  57. if user != nil {
  58. logger.Error("[OAuth2] User #%d cannot be associated because %s is already associated", request.UserID(r), user.Username)
  59. sess.NewFlashErrorMessage(printer.Printf("error.duplicate_linked_account"))
  60. html.Redirect(w, r, route.Path(h.router, "settings"))
  61. return
  62. }
  63. if err := h.store.UpdateExtraField(request.UserID(r), profile.Key, profile.ID); err != nil {
  64. html.ServerError(w, r, err)
  65. return
  66. }
  67. sess.NewFlashMessage(printer.Printf("alert.account_linked"))
  68. html.Redirect(w, r, route.Path(h.router, "settings"))
  69. return
  70. }
  71. user, err := h.store.UserByExtraField(profile.Key, profile.ID)
  72. if err != nil {
  73. html.ServerError(w, r, err)
  74. return
  75. }
  76. if user == nil {
  77. if !h.cfg.IsOAuth2UserCreationAllowed() {
  78. html.Forbidden(w, r)
  79. return
  80. }
  81. user = model.NewUser()
  82. user.Username = profile.Username
  83. user.IsAdmin = false
  84. user.Extra[profile.Key] = profile.ID
  85. if err := h.store.CreateUser(user); err != nil {
  86. html.ServerError(w, r, err)
  87. return
  88. }
  89. }
  90. sessionToken, _, err := h.store.CreateUserSession(user.Username, r.UserAgent(), clientIP)
  91. if err != nil {
  92. html.ServerError(w, r, err)
  93. return
  94. }
  95. logger.Info("[OAuth2] [ClientIP=%s] username=%s (%s) just logged in", clientIP, user.Username, profile)
  96. h.store.SetLastLogin(user.ID)
  97. sess.SetLanguage(user.Language)
  98. sess.SetTheme(user.Theme)
  99. http.SetCookie(w, cookie.New(
  100. cookie.CookieUserSessionID,
  101. sessionToken,
  102. h.cfg.IsHTTPS,
  103. h.cfg.BasePath(),
  104. ))
  105. html.Redirect(w, r, route.Path(h.router, "unread"))
  106. }