middleware.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. package httpd
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "runtime/debug"
  7. "strings"
  8. "time"
  9. "github.com/go-chi/chi/v5/middleware"
  10. "github.com/go-chi/jwtauth/v5"
  11. "github.com/lestrrat-go/jwx/jwt"
  12. "github.com/rs/xid"
  13. "github.com/drakkan/sftpgo/v2/common"
  14. "github.com/drakkan/sftpgo/v2/dataprovider"
  15. "github.com/drakkan/sftpgo/v2/logger"
  16. "github.com/drakkan/sftpgo/v2/sdk"
  17. "github.com/drakkan/sftpgo/v2/util"
  18. )
  19. var (
  20. forwardedProtoKey = &contextKey{"forwarded proto"}
  21. errInvalidToken = errors.New("invalid JWT token")
  22. )
  23. type contextKey struct {
  24. name string
  25. }
  26. func (k *contextKey) String() string {
  27. return "context value " + k.name
  28. }
  29. func validateJWTToken(w http.ResponseWriter, r *http.Request, audience tokenAudience) error {
  30. token, _, err := jwtauth.FromContext(r.Context())
  31. var redirectPath string
  32. if audience == tokenAudienceWebAdmin {
  33. redirectPath = webLoginPath
  34. } else {
  35. redirectPath = webClientLoginPath
  36. }
  37. isAPIToken := (audience == tokenAudienceAPI || audience == tokenAudienceAPIUser)
  38. if err != nil || token == nil {
  39. logger.Debug(logSender, "", "error getting jwt token: %v", err)
  40. if isAPIToken {
  41. sendAPIResponse(w, r, err, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
  42. } else {
  43. http.Redirect(w, r, redirectPath, http.StatusFound)
  44. }
  45. return errInvalidToken
  46. }
  47. err = jwt.Validate(token)
  48. if err != nil {
  49. logger.Debug(logSender, "", "error validating jwt token: %v", err)
  50. if isAPIToken {
  51. sendAPIResponse(w, r, err, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
  52. } else {
  53. http.Redirect(w, r, redirectPath, http.StatusFound)
  54. }
  55. return errInvalidToken
  56. }
  57. if !util.IsStringInSlice(audience, token.Audience()) {
  58. logger.Debug(logSender, "", "the token is not valid for audience %#v", audience)
  59. if isAPIToken {
  60. sendAPIResponse(w, r, nil, "Your token audience is not valid", http.StatusUnauthorized)
  61. } else {
  62. http.Redirect(w, r, redirectPath, http.StatusFound)
  63. }
  64. return errInvalidToken
  65. }
  66. if isTokenInvalidated(r) {
  67. logger.Debug(logSender, "", "the token has been invalidated")
  68. if isAPIToken {
  69. sendAPIResponse(w, r, nil, "Your token is no longer valid", http.StatusUnauthorized)
  70. } else {
  71. http.Redirect(w, r, redirectPath, http.StatusFound)
  72. }
  73. return errInvalidToken
  74. }
  75. return nil
  76. }
  77. func jwtAuthenticatorAPI(next http.Handler) http.Handler {
  78. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  79. if err := validateJWTToken(w, r, tokenAudienceAPI); err != nil {
  80. return
  81. }
  82. // Token is authenticated, pass it through
  83. next.ServeHTTP(w, r)
  84. })
  85. }
  86. func jwtAuthenticatorAPIUser(next http.Handler) http.Handler {
  87. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  88. if err := validateJWTToken(w, r, tokenAudienceAPIUser); err != nil {
  89. return
  90. }
  91. // Token is authenticated, pass it through
  92. next.ServeHTTP(w, r)
  93. })
  94. }
  95. func jwtAuthenticatorWebAdmin(next http.Handler) http.Handler {
  96. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  97. if err := validateJWTToken(w, r, tokenAudienceWebAdmin); err != nil {
  98. return
  99. }
  100. // Token is authenticated, pass it through
  101. next.ServeHTTP(w, r)
  102. })
  103. }
  104. func jwtAuthenticatorWebClient(next http.Handler) http.Handler {
  105. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  106. if err := validateJWTToken(w, r, tokenAudienceWebClient); err != nil {
  107. return
  108. }
  109. // Token is authenticated, pass it through
  110. next.ServeHTTP(w, r)
  111. })
  112. }
  113. func checkHTTPUserPerm(perm string) func(next http.Handler) http.Handler {
  114. return func(next http.Handler) http.Handler {
  115. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  116. _, claims, err := jwtauth.FromContext(r.Context())
  117. if err != nil {
  118. if isWebRequest(r) {
  119. renderClientBadRequestPage(w, r, err)
  120. } else {
  121. sendAPIResponse(w, r, err, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  122. }
  123. return
  124. }
  125. tokenClaims := jwtTokenClaims{}
  126. tokenClaims.Decode(claims)
  127. // for web client perms are negated and not granted
  128. if tokenClaims.hasPerm(perm) {
  129. if isWebRequest(r) {
  130. renderClientForbiddenPage(w, r, "You don't have permission for this action")
  131. } else {
  132. sendAPIResponse(w, r, nil, http.StatusText(http.StatusForbidden), http.StatusForbidden)
  133. }
  134. return
  135. }
  136. next.ServeHTTP(w, r)
  137. })
  138. }
  139. }
  140. func checkPerm(perm string) func(next http.Handler) http.Handler {
  141. return func(next http.Handler) http.Handler {
  142. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  143. _, claims, err := jwtauth.FromContext(r.Context())
  144. if err != nil {
  145. if isWebRequest(r) {
  146. renderBadRequestPage(w, r, err)
  147. } else {
  148. sendAPIResponse(w, r, err, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  149. }
  150. return
  151. }
  152. tokenClaims := jwtTokenClaims{}
  153. tokenClaims.Decode(claims)
  154. if !tokenClaims.hasPerm(perm) {
  155. if isWebRequest(r) {
  156. renderForbiddenPage(w, r, "You don't have permission for this action")
  157. } else {
  158. sendAPIResponse(w, r, nil, http.StatusText(http.StatusForbidden), http.StatusForbidden)
  159. }
  160. return
  161. }
  162. next.ServeHTTP(w, r)
  163. })
  164. }
  165. }
  166. func verifyCSRFHeader(next http.Handler) http.Handler {
  167. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  168. tokenString := r.Header.Get(csrfHeaderToken)
  169. token, err := jwtauth.VerifyToken(csrfTokenAuth, tokenString)
  170. if err != nil || token == nil {
  171. logger.Debug(logSender, "", "error validating CSRF header: %v", err)
  172. sendAPIResponse(w, r, err, "Invalid token", http.StatusForbidden)
  173. return
  174. }
  175. if !util.IsStringInSlice(tokenAudienceCSRF, token.Audience()) {
  176. logger.Debug(logSender, "", "error validating CSRF header audience")
  177. sendAPIResponse(w, r, errors.New("the token is not valid"), "", http.StatusForbidden)
  178. return
  179. }
  180. next.ServeHTTP(w, r)
  181. })
  182. }
  183. func checkAPIKeyAuth(tokenAuth *jwtauth.JWTAuth, scope dataprovider.APIKeyScope) func(next http.Handler) http.Handler {
  184. return func(next http.Handler) http.Handler {
  185. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  186. apiKey := r.Header.Get("X-SFTPGO-API-KEY")
  187. if apiKey == "" {
  188. next.ServeHTTP(w, r)
  189. return
  190. }
  191. keyParams := strings.SplitN(apiKey, ".", 3)
  192. if len(keyParams) < 2 {
  193. logger.Debug(logSender, "", "invalid api key %#v", apiKey)
  194. sendAPIResponse(w, r, errors.New("the provided api key is not valid"), "", http.StatusBadRequest)
  195. return
  196. }
  197. keyID := keyParams[0]
  198. key := keyParams[1]
  199. apiUser := ""
  200. if len(keyParams) > 2 {
  201. apiUser = keyParams[2]
  202. }
  203. k, err := dataprovider.APIKeyExists(keyID)
  204. if err != nil {
  205. logger.Debug(logSender, "invalid api key %#v: %v", apiKey, err)
  206. sendAPIResponse(w, r, errors.New("the provided api key is not valid"), "", http.StatusBadRequest)
  207. return
  208. }
  209. if err := k.Authenticate(key); err != nil {
  210. logger.Debug(logSender, "unable to authenticate api key %#v: %v", apiKey, err)
  211. sendAPIResponse(w, r, fmt.Errorf("the provided api key cannot be authenticated"), "", http.StatusUnauthorized)
  212. return
  213. }
  214. if scope == dataprovider.APIKeyScopeAdmin {
  215. if k.Admin != "" {
  216. apiUser = k.Admin
  217. }
  218. if err := authenticateAdminWithAPIKey(apiUser, keyID, tokenAuth, r); err != nil {
  219. logger.Debug(logSender, "", "unable to authenticate admin %#v associated with api key %#v: %v",
  220. apiUser, apiKey, err)
  221. sendAPIResponse(w, r, fmt.Errorf("the admin associated with the provided api key cannot be authenticated"),
  222. "", http.StatusUnauthorized)
  223. return
  224. }
  225. } else {
  226. if k.User != "" {
  227. apiUser = k.User
  228. }
  229. if err := authenticateUserWithAPIKey(apiUser, keyID, tokenAuth, r); err != nil {
  230. logger.Debug(logSender, "", "unable to authenticate user %#v associated with api key %#v: %v",
  231. apiUser, apiKey, err)
  232. code := http.StatusUnauthorized
  233. if errors.Is(err, common.ErrInternalFailure) {
  234. code = http.StatusInternalServerError
  235. }
  236. sendAPIResponse(w, r, errors.New("the user associated with the provided api key cannot be authenticated"),
  237. "", code)
  238. return
  239. }
  240. }
  241. dataprovider.UpdateAPIKeyLastUse(&k) //nolint:errcheck
  242. next.ServeHTTP(w, r)
  243. })
  244. }
  245. }
  246. func forbidAPIKeyAuthentication(next http.Handler) http.Handler {
  247. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  248. claims, err := getTokenClaims(r)
  249. if err != nil || claims.Username == "" {
  250. sendAPIResponse(w, r, err, "Invalid token claims", http.StatusBadRequest)
  251. return
  252. }
  253. if claims.APIKeyID != "" {
  254. sendAPIResponse(w, r, nil, "API key authentication is not allowed", http.StatusForbidden)
  255. return
  256. }
  257. next.ServeHTTP(w, r)
  258. })
  259. }
  260. func recoverer(next http.Handler) http.Handler {
  261. fn := func(w http.ResponseWriter, r *http.Request) {
  262. defer func() {
  263. if rvr := recover(); rvr != nil {
  264. if rvr == http.ErrAbortHandler {
  265. panic(rvr)
  266. }
  267. logEntry := middleware.GetLogEntry(r)
  268. if logEntry != nil {
  269. logEntry.Panic(rvr, debug.Stack())
  270. } else {
  271. middleware.PrintPrettyStack(rvr)
  272. }
  273. w.WriteHeader(http.StatusInternalServerError)
  274. }
  275. }()
  276. next.ServeHTTP(w, r)
  277. }
  278. return http.HandlerFunc(fn)
  279. }
  280. func authenticateAdminWithAPIKey(username, keyID string, tokenAuth *jwtauth.JWTAuth, r *http.Request) error {
  281. if username == "" {
  282. return errors.New("the provided key is not associated with any admin and no username was provided")
  283. }
  284. admin, err := dataprovider.AdminExists(username)
  285. if err != nil {
  286. return err
  287. }
  288. if !admin.Filters.AllowAPIKeyAuth {
  289. return fmt.Errorf("API key authentication disabled for admin %#v", admin.Username)
  290. }
  291. if err := admin.CanLogin(util.GetIPFromRemoteAddress(r.RemoteAddr)); err != nil {
  292. return err
  293. }
  294. c := jwtTokenClaims{
  295. Username: admin.Username,
  296. Permissions: admin.Permissions,
  297. Signature: admin.GetSignature(),
  298. APIKeyID: keyID,
  299. }
  300. resp, err := c.createTokenResponse(tokenAuth, tokenAudienceAPI)
  301. if err != nil {
  302. return err
  303. }
  304. r.Header.Set("Authorization", fmt.Sprintf("Bearer %v", resp["access_token"]))
  305. dataprovider.UpdateAdminLastLogin(&admin)
  306. return nil
  307. }
  308. func authenticateUserWithAPIKey(username, keyID string, tokenAuth *jwtauth.JWTAuth, r *http.Request) error {
  309. ipAddr := util.GetIPFromRemoteAddress(r.RemoteAddr)
  310. if username == "" {
  311. err := errors.New("the provided key is not associated with any user and no username was provided")
  312. updateLoginMetrics(&dataprovider.User{BaseUser: sdk.BaseUser{Username: username}}, ipAddr, err)
  313. return err
  314. }
  315. if err := common.Config.ExecutePostConnectHook(ipAddr, common.ProtocolHTTP); err != nil {
  316. return err
  317. }
  318. user, err := dataprovider.UserExists(username)
  319. if err != nil {
  320. updateLoginMetrics(&dataprovider.User{BaseUser: sdk.BaseUser{Username: username}}, ipAddr, err)
  321. return err
  322. }
  323. if !user.Filters.AllowAPIKeyAuth {
  324. err := fmt.Errorf("API key authentication disabled for user %#v", user.Username)
  325. updateLoginMetrics(&user, ipAddr, err)
  326. return err
  327. }
  328. if err := user.CheckLoginConditions(); err != nil {
  329. updateLoginMetrics(&user, ipAddr, err)
  330. return err
  331. }
  332. connectionID := fmt.Sprintf("%v_%v", common.ProtocolHTTP, xid.New().String())
  333. if err := checkHTTPClientUser(&user, r, connectionID); err != nil {
  334. updateLoginMetrics(&user, ipAddr, err)
  335. return err
  336. }
  337. lastLogin := util.GetTimeFromMsecSinceEpoch(user.LastLogin)
  338. diff := -time.Until(lastLogin)
  339. if diff < 0 || diff > 10*time.Minute {
  340. defer user.CloseFs() //nolint:errcheck
  341. err = user.CheckFsRoot(connectionID)
  342. if err != nil {
  343. updateLoginMetrics(&user, ipAddr, common.ErrInternalFailure)
  344. return common.ErrInternalFailure
  345. }
  346. }
  347. c := jwtTokenClaims{
  348. Username: user.Username,
  349. Permissions: user.Filters.WebClient,
  350. Signature: user.GetSignature(),
  351. APIKeyID: keyID,
  352. }
  353. resp, err := c.createTokenResponse(tokenAuth, tokenAudienceAPIUser)
  354. if err != nil {
  355. updateLoginMetrics(&user, ipAddr, common.ErrInternalFailure)
  356. return err
  357. }
  358. r.Header.Set("Authorization", fmt.Sprintf("Bearer %v", resp["access_token"]))
  359. dataprovider.UpdateLastLogin(&user)
  360. updateLoginMetrics(&user, ipAddr, nil)
  361. return nil
  362. }