oauth2_callback.go 3.7 KB

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