oauth2_callback.go 3.4 KB

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