webclient.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. package httpd
  2. import (
  3. "errors"
  4. "fmt"
  5. "html/template"
  6. "io"
  7. "mime"
  8. "net/http"
  9. "net/url"
  10. "os"
  11. "path"
  12. "path/filepath"
  13. "strconv"
  14. "strings"
  15. "time"
  16. "github.com/rs/xid"
  17. "github.com/drakkan/sftpgo/common"
  18. "github.com/drakkan/sftpgo/dataprovider"
  19. "github.com/drakkan/sftpgo/logger"
  20. "github.com/drakkan/sftpgo/metrics"
  21. "github.com/drakkan/sftpgo/utils"
  22. "github.com/drakkan/sftpgo/version"
  23. "github.com/drakkan/sftpgo/vfs"
  24. )
  25. const (
  26. templateClientDir = "webclient"
  27. templateClientBase = "base.html"
  28. templateClientLogin = "login.html"
  29. templateClientFiles = "files.html"
  30. templateClientMessage = "message.html"
  31. templateClientCredentials = "credentials.html"
  32. pageClientFilesTitle = "My Files"
  33. pageClientCredentialsTitle = "Credentials"
  34. )
  35. // condResult is the result of an HTTP request precondition check.
  36. // See https://tools.ietf.org/html/rfc7232 section 3.
  37. type condResult int
  38. const (
  39. condNone condResult = iota
  40. condTrue
  41. condFalse
  42. )
  43. var (
  44. clientTemplates = make(map[string]*template.Template)
  45. unixEpochTime = time.Unix(0, 0)
  46. )
  47. // isZeroTime reports whether t is obviously unspecified (either zero or Unix()=0).
  48. func isZeroTime(t time.Time) bool {
  49. return t.IsZero() || t.Equal(unixEpochTime)
  50. }
  51. type baseClientPage struct {
  52. Title string
  53. CurrentURL string
  54. FilesURL string
  55. CredentialsURL string
  56. StaticURL string
  57. LogoutURL string
  58. FilesTitle string
  59. CredentialsTitle string
  60. Version string
  61. CSRFToken string
  62. LoggedUser *dataprovider.User
  63. }
  64. type dirMapping struct {
  65. DirName string
  66. Href string
  67. }
  68. type filesPage struct {
  69. baseClientPage
  70. CurrentDir string
  71. Files []os.FileInfo
  72. Error string
  73. Paths []dirMapping
  74. FormatTime func(time.Time) string
  75. GetObjectURL func(string, string) string
  76. GetSize func(int64) string
  77. IsLink func(os.FileInfo) bool
  78. }
  79. type clientMessagePage struct {
  80. baseClientPage
  81. Error string
  82. Success string
  83. }
  84. type credentialsPage struct {
  85. baseClientPage
  86. PublicKeys []string
  87. ChangePwdURL string
  88. ManageKeysURL string
  89. PwdError string
  90. KeyError string
  91. }
  92. func getFileObjectURL(baseDir, name string) string {
  93. return fmt.Sprintf("%v?path=%v", webClientFilesPath, url.QueryEscape(path.Join(baseDir, name)))
  94. }
  95. func getFileObjectModTime(t time.Time) string {
  96. if isZeroTime(t) {
  97. return ""
  98. }
  99. return t.Format("2006-01-02 15:04")
  100. }
  101. func isFileObjectLink(info os.FileInfo) bool {
  102. return info.Mode()&os.ModeSymlink != 0
  103. }
  104. func loadClientTemplates(templatesPath string) {
  105. filesPaths := []string{
  106. filepath.Join(templatesPath, templateClientDir, templateClientBase),
  107. filepath.Join(templatesPath, templateClientDir, templateClientFiles),
  108. }
  109. credentialsPaths := []string{
  110. filepath.Join(templatesPath, templateClientDir, templateClientBase),
  111. filepath.Join(templatesPath, templateClientDir, templateClientCredentials),
  112. }
  113. loginPath := []string{
  114. filepath.Join(templatesPath, templateClientDir, templateClientLogin),
  115. }
  116. messagePath := []string{
  117. filepath.Join(templatesPath, templateClientDir, templateClientBase),
  118. filepath.Join(templatesPath, templateClientDir, templateClientMessage),
  119. }
  120. filesTmpl := utils.LoadTemplate(template.ParseFiles(filesPaths...))
  121. credentialsTmpl := utils.LoadTemplate(template.ParseFiles(credentialsPaths...))
  122. loginTmpl := utils.LoadTemplate(template.ParseFiles(loginPath...))
  123. messageTmpl := utils.LoadTemplate(template.ParseFiles(messagePath...))
  124. clientTemplates[templateClientFiles] = filesTmpl
  125. clientTemplates[templateClientCredentials] = credentialsTmpl
  126. clientTemplates[templateClientLogin] = loginTmpl
  127. clientTemplates[templateClientMessage] = messageTmpl
  128. }
  129. func getBaseClientPageData(title, currentURL string, r *http.Request) baseClientPage {
  130. var csrfToken string
  131. if currentURL != "" {
  132. csrfToken = createCSRFToken()
  133. }
  134. v := version.Get()
  135. return baseClientPage{
  136. Title: title,
  137. CurrentURL: currentURL,
  138. FilesURL: webClientFilesPath,
  139. CredentialsURL: webClientCredentialsPath,
  140. StaticURL: webStaticFilesPath,
  141. LogoutURL: webClientLogoutPath,
  142. FilesTitle: pageClientFilesTitle,
  143. CredentialsTitle: pageClientCredentialsTitle,
  144. Version: fmt.Sprintf("%v-%v", v.Version, v.CommitHash),
  145. CSRFToken: csrfToken,
  146. LoggedUser: getUserFromToken(r),
  147. }
  148. }
  149. func renderClientTemplate(w http.ResponseWriter, tmplName string, data interface{}) {
  150. err := clientTemplates[tmplName].ExecuteTemplate(w, tmplName, data)
  151. if err != nil {
  152. http.Error(w, err.Error(), http.StatusInternalServerError)
  153. }
  154. }
  155. func renderClientLoginPage(w http.ResponseWriter, error string) {
  156. data := loginPage{
  157. CurrentURL: webClientLoginPath,
  158. Version: version.Get().Version,
  159. Error: error,
  160. CSRFToken: createCSRFToken(),
  161. StaticURL: webStaticFilesPath,
  162. }
  163. renderClientTemplate(w, templateClientLogin, data)
  164. }
  165. func renderClientMessagePage(w http.ResponseWriter, r *http.Request, title, body string, statusCode int, err error, message string) {
  166. var errorString string
  167. if body != "" {
  168. errorString = body + " "
  169. }
  170. if err != nil {
  171. errorString += err.Error()
  172. }
  173. data := clientMessagePage{
  174. baseClientPage: getBaseClientPageData(title, "", r),
  175. Error: errorString,
  176. Success: message,
  177. }
  178. w.WriteHeader(statusCode)
  179. renderClientTemplate(w, templateClientMessage, data)
  180. }
  181. func renderClientInternalServerErrorPage(w http.ResponseWriter, r *http.Request, err error) {
  182. renderClientMessagePage(w, r, page500Title, page500Body, http.StatusInternalServerError, err, "")
  183. }
  184. func renderClientBadRequestPage(w http.ResponseWriter, r *http.Request, err error) {
  185. renderClientMessagePage(w, r, page400Title, "", http.StatusBadRequest, err, "")
  186. }
  187. func renderClientForbiddenPage(w http.ResponseWriter, r *http.Request, body string) {
  188. renderClientMessagePage(w, r, page403Title, "", http.StatusForbidden, nil, body)
  189. }
  190. func renderClientNotFoundPage(w http.ResponseWriter, r *http.Request, err error) {
  191. renderClientMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
  192. }
  193. func renderFilesPage(w http.ResponseWriter, r *http.Request, files []os.FileInfo, dirName, error string) {
  194. data := filesPage{
  195. baseClientPage: getBaseClientPageData(pageClientFilesTitle, webClientFilesPath, r),
  196. Files: files,
  197. Error: error,
  198. CurrentDir: dirName,
  199. FormatTime: getFileObjectModTime,
  200. GetObjectURL: getFileObjectURL,
  201. GetSize: utils.ByteCountIEC,
  202. IsLink: isFileObjectLink,
  203. }
  204. paths := []dirMapping{}
  205. if dirName != "/" {
  206. paths = append(paths, dirMapping{
  207. DirName: path.Base(dirName),
  208. Href: "",
  209. })
  210. for {
  211. dirName = path.Dir(dirName)
  212. if dirName == "/" || dirName == "." {
  213. break
  214. }
  215. paths = append([]dirMapping{{
  216. DirName: path.Base(dirName),
  217. Href: getFileObjectURL("/", dirName)},
  218. }, paths...)
  219. }
  220. }
  221. data.Paths = paths
  222. renderClientTemplate(w, templateClientFiles, data)
  223. }
  224. func renderCredentialsPage(w http.ResponseWriter, r *http.Request, pwdError string, keyError string) {
  225. data := credentialsPage{
  226. baseClientPage: getBaseClientPageData(pageClientCredentialsTitle, webClientCredentialsPath, r),
  227. ChangePwdURL: webChangeClientPwdPath,
  228. ManageKeysURL: webChangeClientKeysPath,
  229. PwdError: pwdError,
  230. KeyError: keyError,
  231. }
  232. user, err := dataprovider.UserExists(data.LoggedUser.Username)
  233. if err != nil {
  234. renderClientInternalServerErrorPage(w, r, err)
  235. }
  236. data.PublicKeys = user.PublicKeys
  237. renderClientTemplate(w, templateClientCredentials, data)
  238. }
  239. func handleClientWebLogin(w http.ResponseWriter, r *http.Request) {
  240. renderClientLoginPage(w, "")
  241. }
  242. func handleWebClientLogout(w http.ResponseWriter, r *http.Request) {
  243. c := jwtTokenClaims{}
  244. c.removeCookie(w, r)
  245. http.Redirect(w, r, webClientLoginPath, http.StatusFound)
  246. }
  247. func handleClientGetFiles(w http.ResponseWriter, r *http.Request) {
  248. common.Connections.AddNetworkConnection()
  249. defer common.Connections.RemoveNetworkConnection()
  250. claims, err := getTokenClaims(r)
  251. if err != nil || claims.Username == "" {
  252. renderClientForbiddenPage(w, r, "Invalid token claims")
  253. return
  254. }
  255. if !common.Connections.IsNewConnectionAllowed() {
  256. logger.Log(logger.LevelDebug, common.ProtocolHTTP, "", "connection refused, configured limit reached")
  257. renderClientForbiddenPage(w, r, "configured connections limit reached")
  258. return
  259. }
  260. ipAddr := utils.GetIPFromRemoteAddress(r.RemoteAddr)
  261. if common.IsBanned(ipAddr) {
  262. renderClientForbiddenPage(w, r, "your IP address is banned")
  263. return
  264. }
  265. user, err := dataprovider.UserExists(claims.Username)
  266. if err != nil {
  267. renderClientInternalServerErrorPage(w, r, err)
  268. return
  269. }
  270. connID := xid.New().String()
  271. connectionID := fmt.Sprintf("%v_%v", common.ProtocolHTTP, connID)
  272. if err := checkWebClientUser(&user, r, connectionID); err != nil {
  273. renderClientForbiddenPage(w, r, err.Error())
  274. return
  275. }
  276. connection := &Connection{
  277. BaseConnection: common.NewBaseConnection(connID, common.ProtocolHTTP, user),
  278. request: r,
  279. }
  280. common.Connections.Add(connection)
  281. defer common.Connections.Remove(connection.GetID())
  282. name := "/"
  283. if _, ok := r.URL.Query()["path"]; ok {
  284. name = utils.CleanPath(r.URL.Query().Get("path"))
  285. }
  286. var info os.FileInfo
  287. if name == "/" {
  288. info = vfs.NewFileInfo(name, true, 0, time.Now(), false)
  289. } else {
  290. info, err = connection.Stat(name, 0)
  291. }
  292. if err != nil {
  293. renderFilesPage(w, r, nil, name, fmt.Sprintf("unable to stat file %#v: %v", name, err))
  294. return
  295. }
  296. if info.IsDir() {
  297. renderDirContents(w, r, connection, name)
  298. return
  299. }
  300. downloadFile(w, r, connection, name, info)
  301. }
  302. func handleClientGetCredentials(w http.ResponseWriter, r *http.Request) {
  303. renderCredentialsPage(w, r, "", "")
  304. }
  305. func handleWebClientChangePwdPost(w http.ResponseWriter, r *http.Request) {
  306. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  307. err := r.ParseForm()
  308. if err != nil {
  309. renderCredentialsPage(w, r, err.Error(), "")
  310. return
  311. }
  312. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  313. renderClientForbiddenPage(w, r, err.Error())
  314. return
  315. }
  316. err = doChangeUserPassword(r, r.Form.Get("current_password"), r.Form.Get("new_password1"),
  317. r.Form.Get("new_password2"))
  318. if err != nil {
  319. renderCredentialsPage(w, r, err.Error(), "")
  320. return
  321. }
  322. handleWebClientLogout(w, r)
  323. }
  324. func handleWebClientManageKeysPost(w http.ResponseWriter, r *http.Request) {
  325. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  326. err := r.ParseForm()
  327. if err != nil {
  328. renderCredentialsPage(w, r, "", err.Error())
  329. return
  330. }
  331. if err := verifyCSRFToken(r.Form.Get(csrfFormToken)); err != nil {
  332. renderClientForbiddenPage(w, r, err.Error())
  333. return
  334. }
  335. claims, err := getTokenClaims(r)
  336. if err != nil || claims.Username == "" {
  337. renderCredentialsPage(w, r, "", "Invalid token claims")
  338. return
  339. }
  340. user, err := dataprovider.UserExists(claims.Username)
  341. if err != nil {
  342. renderCredentialsPage(w, r, "", err.Error())
  343. return
  344. }
  345. publicKeysFormValue := r.Form.Get("public_keys")
  346. publicKeys := getSliceFromDelimitedValues(publicKeysFormValue, "\n")
  347. user.PublicKeys = publicKeys
  348. err = dataprovider.UpdateUser(&user)
  349. if err != nil {
  350. renderCredentialsPage(w, r, "", err.Error())
  351. return
  352. }
  353. renderClientMessagePage(w, r, "Public keys updated", "", http.StatusOK, nil, "Your public keys has been successfully updated")
  354. }
  355. func doChangeUserPassword(r *http.Request, currentPassword, newPassword, confirmNewPassword string) error {
  356. if currentPassword == "" || newPassword == "" || confirmNewPassword == "" {
  357. return dataprovider.NewValidationError("please provide the current password and the new one two times")
  358. }
  359. if newPassword != confirmNewPassword {
  360. return dataprovider.NewValidationError("the two password fields do not match")
  361. }
  362. if currentPassword == newPassword {
  363. return dataprovider.NewValidationError("the new password must be different from the current one")
  364. }
  365. claims, err := getTokenClaims(r)
  366. if err != nil || claims.Username == "" {
  367. return errors.New("invalid token claims")
  368. }
  369. user, err := dataprovider.CheckUserAndPass(claims.Username, currentPassword, utils.GetIPFromRemoteAddress(r.RemoteAddr),
  370. common.ProtocolHTTP)
  371. if err != nil {
  372. return dataprovider.NewValidationError("current password does not match")
  373. }
  374. user.Password = newPassword
  375. return dataprovider.UpdateUser(&user)
  376. }
  377. func renderDirContents(w http.ResponseWriter, r *http.Request, connection *Connection, name string) {
  378. contents, err := connection.ReadDir(name)
  379. if err != nil {
  380. renderFilesPage(w, r, nil, name, fmt.Sprintf("unable to get contents for directory %#v: %v", name, err))
  381. return
  382. }
  383. renderFilesPage(w, r, contents, name, "")
  384. }
  385. func downloadFile(w http.ResponseWriter, r *http.Request, connection *Connection, name string, info os.FileInfo) {
  386. var err error
  387. rangeHeader := r.Header.Get("Range")
  388. if rangeHeader != "" && checkIfRange(r, info.ModTime()) == condFalse {
  389. rangeHeader = ""
  390. }
  391. offset := int64(0)
  392. size := info.Size()
  393. responseStatus := http.StatusOK
  394. if strings.HasPrefix(rangeHeader, "bytes=") {
  395. if strings.Contains(rangeHeader, ",") {
  396. http.Error(w, fmt.Sprintf("unsupported range %#v", rangeHeader), http.StatusRequestedRangeNotSatisfiable)
  397. return
  398. }
  399. offset, size, err = parseRangeRequest(rangeHeader[6:], size)
  400. if err != nil {
  401. http.Error(w, err.Error(), http.StatusRequestedRangeNotSatisfiable)
  402. return
  403. }
  404. responseStatus = http.StatusPartialContent
  405. }
  406. reader, err := connection.getFileReader(name, offset)
  407. if err != nil {
  408. renderFilesPage(w, r, nil, name, fmt.Sprintf("unable to read file %#v: %v", name, err))
  409. return
  410. }
  411. defer reader.Close()
  412. w.Header().Set("Last-Modified", info.ModTime().UTC().Format(http.TimeFormat))
  413. if checkPreconditions(w, r, info.ModTime()) {
  414. return
  415. }
  416. ctype := mime.TypeByExtension(path.Ext(name))
  417. if ctype == "" {
  418. ctype = "application/octet-stream"
  419. }
  420. if responseStatus == http.StatusPartialContent {
  421. w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", offset, offset+size-1, info.Size()))
  422. }
  423. w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
  424. w.Header().Set("Content-Type", ctype)
  425. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%#v", path.Base(name)))
  426. w.Header().Set("Accept-Ranges", "bytes")
  427. w.WriteHeader(responseStatus)
  428. if r.Method != http.MethodHead {
  429. io.CopyN(w, reader, size) //nolint:errcheck
  430. }
  431. }
  432. func checkPreconditions(w http.ResponseWriter, r *http.Request, modtime time.Time) bool {
  433. if checkIfUnmodifiedSince(r, modtime) == condFalse {
  434. w.WriteHeader(http.StatusPreconditionFailed)
  435. return true
  436. }
  437. if checkIfModifiedSince(r, modtime) == condFalse {
  438. w.WriteHeader(http.StatusNotModified)
  439. return true
  440. }
  441. return false
  442. }
  443. func checkIfUnmodifiedSince(r *http.Request, modtime time.Time) condResult {
  444. ius := r.Header.Get("If-Unmodified-Since")
  445. if ius == "" || isZeroTime(modtime) {
  446. return condNone
  447. }
  448. t, err := http.ParseTime(ius)
  449. if err != nil {
  450. return condNone
  451. }
  452. // The Last-Modified header truncates sub-second precision so
  453. // the modtime needs to be truncated too.
  454. modtime = modtime.Truncate(time.Second)
  455. if modtime.Before(t) || modtime.Equal(t) {
  456. return condTrue
  457. }
  458. return condFalse
  459. }
  460. func checkIfModifiedSince(r *http.Request, modtime time.Time) condResult {
  461. if r.Method != http.MethodGet && r.Method != http.MethodHead {
  462. return condNone
  463. }
  464. ims := r.Header.Get("If-Modified-Since")
  465. if ims == "" || isZeroTime(modtime) {
  466. return condNone
  467. }
  468. t, err := http.ParseTime(ims)
  469. if err != nil {
  470. return condNone
  471. }
  472. // The Last-Modified header truncates sub-second precision so
  473. // the modtime needs to be truncated too.
  474. modtime = modtime.Truncate(time.Second)
  475. if modtime.Before(t) || modtime.Equal(t) {
  476. return condFalse
  477. }
  478. return condTrue
  479. }
  480. func checkIfRange(r *http.Request, modtime time.Time) condResult {
  481. if r.Method != http.MethodGet && r.Method != http.MethodHead {
  482. return condNone
  483. }
  484. ir := r.Header.Get("If-Range")
  485. if ir == "" {
  486. return condNone
  487. }
  488. if modtime.IsZero() {
  489. return condFalse
  490. }
  491. t, err := http.ParseTime(ir)
  492. if err != nil {
  493. return condFalse
  494. }
  495. if modtime.Add(60 * time.Second).Before(t) {
  496. return condTrue
  497. }
  498. return condFalse
  499. }
  500. func parseRangeRequest(bytesRange string, size int64) (int64, int64, error) {
  501. var start, end int64
  502. var err error
  503. values := strings.Split(bytesRange, "-")
  504. if values[0] == "" {
  505. start = -1
  506. } else {
  507. start, err = strconv.ParseInt(values[0], 10, 64)
  508. if err != nil {
  509. return start, size, err
  510. }
  511. }
  512. if len(values) >= 2 {
  513. if values[1] != "" {
  514. end, err = strconv.ParseInt(values[1], 10, 64)
  515. if err != nil {
  516. return start, size, err
  517. }
  518. if end >= size {
  519. end = size - 1
  520. }
  521. }
  522. }
  523. if start == -1 && end == 0 {
  524. return 0, 0, fmt.Errorf("unsupported range %#v", bytesRange)
  525. }
  526. if end > 0 {
  527. if start == -1 {
  528. // we have something like -500
  529. start = size - end
  530. size = end
  531. // this can't happen, we did end = size -1 above
  532. /*if start < 0 {
  533. return 0, 0, fmt.Errorf("unacceptable range %#v", bytesRange)
  534. }*/
  535. } else {
  536. // we have something like 500-600
  537. size = end - start + 1
  538. if size < 0 {
  539. return 0, 0, fmt.Errorf("unacceptable range %#v", bytesRange)
  540. }
  541. }
  542. return start, size, nil
  543. }
  544. /*if start == -1 {
  545. return 0, 0, fmt.Errorf("unacceptable range %#v", bytesRange)
  546. }*/
  547. // we have something like 500-
  548. size -= start
  549. if size < 0 {
  550. return 0, 0, fmt.Errorf("unacceptable range %#v", bytesRange)
  551. }
  552. return start, size, err
  553. }
  554. func updateLoginMetrics(user *dataprovider.User, ip string, err error) {
  555. metrics.AddLoginAttempt(dataprovider.LoginMethodPassword)
  556. if err != nil {
  557. logger.ConnectionFailedLog(user.Username, ip, dataprovider.LoginMethodPassword, common.ProtocolHTTP, err.Error())
  558. event := common.HostEventLoginFailed
  559. if _, ok := err.(*dataprovider.RecordNotFoundError); ok {
  560. event = common.HostEventUserNotFound
  561. }
  562. common.AddDefenderEvent(ip, event)
  563. }
  564. metrics.AddLoginResult(dataprovider.LoginMethodPassword, err)
  565. dataprovider.ExecutePostLoginHook(user, dataprovider.LoginMethodPassword, ip, common.ProtocolHTTP, err)
  566. }
  567. func checkWebClientUser(user *dataprovider.User, r *http.Request, connectionID string) error {
  568. if utils.IsStringInSlice(common.ProtocolHTTP, user.Filters.DeniedProtocols) {
  569. logger.Debug(logSender, connectionID, "cannot login user %#v, protocol HTTP is not allowed", user.Username)
  570. return fmt.Errorf("protocol HTTP is not allowed for user %#v", user.Username)
  571. }
  572. if !user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, nil) {
  573. logger.Debug(logSender, connectionID, "cannot login user %#v, password login method is not allowed", user.Username)
  574. return fmt.Errorf("login method password is not allowed for user %#v", user.Username)
  575. }
  576. if user.MaxSessions > 0 {
  577. activeSessions := common.Connections.GetActiveSessions(user.Username)
  578. if activeSessions >= user.MaxSessions {
  579. logger.Debug(logSender, connectionID, "authentication refused for user: %#v, too many open sessions: %v/%v", user.Username,
  580. activeSessions, user.MaxSessions)
  581. return fmt.Errorf("too many open sessions: %v", activeSessions)
  582. }
  583. }
  584. if !user.IsLoginFromAddrAllowed(r.RemoteAddr) {
  585. logger.Debug(logSender, connectionID, "cannot login user %#v, remote address is not allowed: %v", user.Username, r.RemoteAddr)
  586. return fmt.Errorf("login for user %#v is not allowed from this address: %v", user.Username, r.RemoteAddr)
  587. }
  588. if connAddr, ok := r.Context().Value(connAddrKey).(string); ok {
  589. if connAddr != r.RemoteAddr {
  590. connIPAddr := utils.GetIPFromRemoteAddress(connAddr)
  591. if common.IsBanned(connIPAddr) {
  592. return errors.New("your IP address is banned")
  593. }
  594. if !user.IsLoginFromAddrAllowed(connIPAddr) {
  595. return fmt.Errorf("login from IP %v is not allowed", connIPAddr)
  596. }
  597. }
  598. }
  599. return nil
  600. }