config_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. package config_test
  2. import (
  3. "encoding/json"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "testing"
  9. "github.com/spf13/viper"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/drakkan/sftpgo/common"
  12. "github.com/drakkan/sftpgo/config"
  13. "github.com/drakkan/sftpgo/dataprovider"
  14. "github.com/drakkan/sftpgo/ftpd"
  15. "github.com/drakkan/sftpgo/httpclient"
  16. "github.com/drakkan/sftpgo/httpd"
  17. "github.com/drakkan/sftpgo/sftpd"
  18. "github.com/drakkan/sftpgo/utils"
  19. )
  20. const (
  21. tempConfigName = "temp"
  22. )
  23. func reset() {
  24. viper.Reset()
  25. config.Init()
  26. }
  27. func TestLoadConfigTest(t *testing.T) {
  28. reset()
  29. configDir := ".."
  30. err := config.LoadConfig(configDir, "")
  31. assert.NoError(t, err)
  32. assert.NotEqual(t, httpd.Conf{}, config.GetHTTPConfig())
  33. assert.NotEqual(t, dataprovider.Config{}, config.GetProviderConf())
  34. assert.NotEqual(t, sftpd.Configuration{}, config.GetSFTPDConfig())
  35. assert.NotEqual(t, httpclient.Config{}, config.GetHTTPConfig())
  36. confName := tempConfigName + ".json"
  37. configFilePath := filepath.Join(configDir, confName)
  38. err = config.LoadConfig(configDir, confName)
  39. assert.NoError(t, err)
  40. err = ioutil.WriteFile(configFilePath, []byte("{invalid json}"), os.ModePerm)
  41. assert.NoError(t, err)
  42. err = config.LoadConfig(configDir, confName)
  43. assert.NoError(t, err)
  44. err = ioutil.WriteFile(configFilePath, []byte("{\"sftpd\": {\"bind_port\": \"a\"}}"), os.ModePerm)
  45. assert.NoError(t, err)
  46. err = config.LoadConfig(configDir, confName)
  47. assert.Error(t, err)
  48. err = os.Remove(configFilePath)
  49. assert.NoError(t, err)
  50. }
  51. func TestEmptyBanner(t *testing.T) {
  52. reset()
  53. configDir := ".."
  54. confName := tempConfigName + ".json"
  55. configFilePath := filepath.Join(configDir, confName)
  56. err := config.LoadConfig(configDir, "")
  57. assert.NoError(t, err)
  58. sftpdConf := config.GetSFTPDConfig()
  59. sftpdConf.Banner = " "
  60. c := make(map[string]sftpd.Configuration)
  61. c["sftpd"] = sftpdConf
  62. jsonConf, _ := json.Marshal(c)
  63. err = ioutil.WriteFile(configFilePath, jsonConf, os.ModePerm)
  64. assert.NoError(t, err)
  65. err = config.LoadConfig(configDir, confName)
  66. assert.NoError(t, err)
  67. sftpdConf = config.GetSFTPDConfig()
  68. assert.NotEmpty(t, strings.TrimSpace(sftpdConf.Banner))
  69. err = os.Remove(configFilePath)
  70. assert.NoError(t, err)
  71. ftpdConf := config.GetFTPDConfig()
  72. ftpdConf.Banner = " "
  73. c1 := make(map[string]ftpd.Configuration)
  74. c1["ftpd"] = ftpdConf
  75. jsonConf, _ = json.Marshal(c1)
  76. err = ioutil.WriteFile(configFilePath, jsonConf, os.ModePerm)
  77. assert.NoError(t, err)
  78. err = config.LoadConfig(configDir, confName)
  79. assert.NoError(t, err)
  80. ftpdConf = config.GetFTPDConfig()
  81. assert.NotEmpty(t, strings.TrimSpace(ftpdConf.Banner))
  82. err = os.Remove(configFilePath)
  83. assert.NoError(t, err)
  84. }
  85. func TestInvalidUploadMode(t *testing.T) {
  86. reset()
  87. configDir := ".."
  88. confName := tempConfigName + ".json"
  89. configFilePath := filepath.Join(configDir, confName)
  90. err := config.LoadConfig(configDir, "")
  91. assert.NoError(t, err)
  92. commonConf := config.GetCommonConfig()
  93. commonConf.UploadMode = 10
  94. c := make(map[string]common.Configuration)
  95. c["common"] = commonConf
  96. jsonConf, err := json.Marshal(c)
  97. assert.NoError(t, err)
  98. err = ioutil.WriteFile(configFilePath, jsonConf, os.ModePerm)
  99. assert.NoError(t, err)
  100. err = config.LoadConfig(configDir, confName)
  101. assert.NoError(t, err)
  102. assert.Equal(t, 0, config.GetCommonConfig().UploadMode)
  103. err = os.Remove(configFilePath)
  104. assert.NoError(t, err)
  105. }
  106. func TestInvalidExternalAuthScope(t *testing.T) {
  107. reset()
  108. configDir := ".."
  109. confName := tempConfigName + ".json"
  110. configFilePath := filepath.Join(configDir, confName)
  111. err := config.LoadConfig(configDir, "")
  112. assert.NoError(t, err)
  113. providerConf := config.GetProviderConf()
  114. providerConf.ExternalAuthScope = 10
  115. c := make(map[string]dataprovider.Config)
  116. c["data_provider"] = providerConf
  117. jsonConf, err := json.Marshal(c)
  118. assert.NoError(t, err)
  119. err = ioutil.WriteFile(configFilePath, jsonConf, os.ModePerm)
  120. assert.NoError(t, err)
  121. err = config.LoadConfig(configDir, confName)
  122. assert.NoError(t, err)
  123. assert.Equal(t, 0, config.GetProviderConf().ExternalAuthScope)
  124. err = os.Remove(configFilePath)
  125. assert.NoError(t, err)
  126. }
  127. func TestInvalidCredentialsPath(t *testing.T) {
  128. reset()
  129. configDir := ".."
  130. confName := tempConfigName + ".json"
  131. configFilePath := filepath.Join(configDir, confName)
  132. err := config.LoadConfig(configDir, "")
  133. assert.NoError(t, err)
  134. providerConf := config.GetProviderConf()
  135. providerConf.CredentialsPath = ""
  136. c := make(map[string]dataprovider.Config)
  137. c["data_provider"] = providerConf
  138. jsonConf, err := json.Marshal(c)
  139. assert.NoError(t, err)
  140. err = ioutil.WriteFile(configFilePath, jsonConf, os.ModePerm)
  141. assert.NoError(t, err)
  142. err = config.LoadConfig(configDir, confName)
  143. assert.NoError(t, err)
  144. assert.Equal(t, "credentials", config.GetProviderConf().CredentialsPath)
  145. err = os.Remove(configFilePath)
  146. assert.NoError(t, err)
  147. }
  148. func TestInvalidProxyProtocol(t *testing.T) {
  149. reset()
  150. configDir := ".."
  151. confName := tempConfigName + ".json"
  152. configFilePath := filepath.Join(configDir, confName)
  153. err := config.LoadConfig(configDir, "")
  154. assert.NoError(t, err)
  155. commonConf := config.GetCommonConfig()
  156. commonConf.ProxyProtocol = 10
  157. c := make(map[string]common.Configuration)
  158. c["common"] = commonConf
  159. jsonConf, err := json.Marshal(c)
  160. assert.NoError(t, err)
  161. err = ioutil.WriteFile(configFilePath, jsonConf, os.ModePerm)
  162. assert.NoError(t, err)
  163. err = config.LoadConfig(configDir, confName)
  164. assert.NoError(t, err)
  165. assert.Equal(t, 0, config.GetCommonConfig().ProxyProtocol)
  166. err = os.Remove(configFilePath)
  167. assert.NoError(t, err)
  168. }
  169. func TestInvalidUsersBaseDir(t *testing.T) {
  170. reset()
  171. configDir := ".."
  172. confName := tempConfigName + ".json"
  173. configFilePath := filepath.Join(configDir, confName)
  174. err := config.LoadConfig(configDir, "")
  175. assert.NoError(t, err)
  176. providerConf := config.GetProviderConf()
  177. providerConf.UsersBaseDir = "."
  178. c := make(map[string]dataprovider.Config)
  179. c["data_provider"] = providerConf
  180. jsonConf, err := json.Marshal(c)
  181. assert.NoError(t, err)
  182. err = ioutil.WriteFile(configFilePath, jsonConf, os.ModePerm)
  183. assert.NoError(t, err)
  184. err = config.LoadConfig(configDir, confName)
  185. assert.NoError(t, err)
  186. assert.Empty(t, config.GetProviderConf().UsersBaseDir)
  187. err = os.Remove(configFilePath)
  188. assert.NoError(t, err)
  189. }
  190. func TestCommonParamsCompatibility(t *testing.T) {
  191. reset()
  192. configDir := ".."
  193. confName := tempConfigName + ".json"
  194. configFilePath := filepath.Join(configDir, confName)
  195. err := config.LoadConfig(configDir, "")
  196. assert.NoError(t, err)
  197. sftpdConf := config.GetSFTPDConfig()
  198. sftpdConf.IdleTimeout = 21 //nolint:staticcheck
  199. sftpdConf.Actions.Hook = "http://hook"
  200. sftpdConf.Actions.ExecuteOn = []string{"upload"}
  201. sftpdConf.SetstatMode = 1 //nolint:staticcheck
  202. sftpdConf.UploadMode = common.UploadModeAtomicWithResume //nolint:staticcheck
  203. sftpdConf.ProxyProtocol = 1 //nolint:staticcheck
  204. sftpdConf.ProxyAllowed = []string{"192.168.1.1"} //nolint:staticcheck
  205. c := make(map[string]sftpd.Configuration)
  206. c["sftpd"] = sftpdConf
  207. jsonConf, err := json.Marshal(c)
  208. assert.NoError(t, err)
  209. err = ioutil.WriteFile(configFilePath, jsonConf, os.ModePerm)
  210. assert.NoError(t, err)
  211. err = config.LoadConfig(configDir, confName)
  212. assert.NoError(t, err)
  213. commonConf := config.GetCommonConfig()
  214. assert.Equal(t, 21, commonConf.IdleTimeout)
  215. assert.Equal(t, "http://hook", commonConf.Actions.Hook)
  216. assert.Len(t, commonConf.Actions.ExecuteOn, 1)
  217. assert.True(t, utils.IsStringInSlice("upload", commonConf.Actions.ExecuteOn))
  218. assert.Equal(t, 1, commonConf.SetstatMode)
  219. assert.Equal(t, 1, commonConf.ProxyProtocol)
  220. assert.Len(t, commonConf.ProxyAllowed, 1)
  221. assert.True(t, utils.IsStringInSlice("192.168.1.1", commonConf.ProxyAllowed))
  222. err = os.Remove(configFilePath)
  223. assert.NoError(t, err)
  224. }
  225. func TestHostKeyCompatibility(t *testing.T) {
  226. reset()
  227. configDir := ".."
  228. confName := tempConfigName + ".json"
  229. configFilePath := filepath.Join(configDir, confName)
  230. err := config.LoadConfig(configDir, "")
  231. assert.NoError(t, err)
  232. sftpdConf := config.GetSFTPDConfig()
  233. sftpdConf.Keys = []sftpd.Key{ //nolint:staticcheck
  234. {
  235. PrivateKey: "rsa",
  236. },
  237. {
  238. PrivateKey: "ecdsa",
  239. },
  240. }
  241. c := make(map[string]sftpd.Configuration)
  242. c["sftpd"] = sftpdConf
  243. jsonConf, err := json.Marshal(c)
  244. assert.NoError(t, err)
  245. err = ioutil.WriteFile(configFilePath, jsonConf, os.ModePerm)
  246. assert.NoError(t, err)
  247. err = config.LoadConfig(configDir, confName)
  248. assert.NoError(t, err)
  249. sftpdConf = config.GetSFTPDConfig()
  250. assert.Equal(t, 2, len(sftpdConf.HostKeys))
  251. assert.True(t, utils.IsStringInSlice("rsa", sftpdConf.HostKeys))
  252. assert.True(t, utils.IsStringInSlice("ecdsa", sftpdConf.HostKeys))
  253. err = os.Remove(configFilePath)
  254. assert.NoError(t, err)
  255. }
  256. func TestSetGetConfig(t *testing.T) {
  257. reset()
  258. sftpdConf := config.GetSFTPDConfig()
  259. sftpdConf.MaxAuthTries = 10
  260. config.SetSFTPDConfig(sftpdConf)
  261. assert.Equal(t, sftpdConf.MaxAuthTries, config.GetSFTPDConfig().MaxAuthTries)
  262. dataProviderConf := config.GetProviderConf()
  263. dataProviderConf.Host = "test host"
  264. config.SetProviderConf(dataProviderConf)
  265. assert.Equal(t, dataProviderConf.Host, config.GetProviderConf().Host)
  266. httpdConf := config.GetHTTPDConfig()
  267. httpdConf.BindAddress = "0.0.0.0"
  268. config.SetHTTPDConfig(httpdConf)
  269. assert.Equal(t, httpdConf.BindAddress, config.GetHTTPDConfig().BindAddress)
  270. commonConf := config.GetCommonConfig()
  271. commonConf.IdleTimeout = 10
  272. config.SetCommonConfig(commonConf)
  273. assert.Equal(t, commonConf.IdleTimeout, config.GetCommonConfig().IdleTimeout)
  274. ftpdConf := config.GetFTPDConfig()
  275. ftpdConf.CertificateFile = "cert"
  276. ftpdConf.CertificateKeyFile = "key"
  277. config.SetFTPDConfig(ftpdConf)
  278. assert.Equal(t, ftpdConf.CertificateFile, config.GetFTPDConfig().CertificateFile)
  279. assert.Equal(t, ftpdConf.CertificateKeyFile, config.GetFTPDConfig().CertificateKeyFile)
  280. webDavConf := config.GetWebDAVDConfig()
  281. webDavConf.CertificateFile = "dav_cert"
  282. webDavConf.CertificateKeyFile = "dav_key"
  283. config.SetWebDAVDConfig(webDavConf)
  284. assert.Equal(t, webDavConf.CertificateFile, config.GetWebDAVDConfig().CertificateFile)
  285. assert.Equal(t, webDavConf.CertificateKeyFile, config.GetWebDAVDConfig().CertificateKeyFile)
  286. kmsConf := config.GetKMSConfig()
  287. kmsConf.Secrets.MasterKeyPath = "apath"
  288. kmsConf.Secrets.URL = "aurl"
  289. config.SetKMSConfig(kmsConf)
  290. assert.Equal(t, kmsConf.Secrets.MasterKeyPath, config.GetKMSConfig().Secrets.MasterKeyPath)
  291. assert.Equal(t, kmsConf.Secrets.URL, config.GetKMSConfig().Secrets.URL)
  292. telemetryConf := config.GetTelemetryConfig()
  293. telemetryConf.BindPort = 10001
  294. telemetryConf.BindAddress = "0.0.0.0"
  295. config.SetTelemetryConfig(telemetryConf)
  296. assert.Equal(t, telemetryConf.BindPort, config.GetTelemetryConfig().BindPort)
  297. assert.Equal(t, telemetryConf.BindAddress, config.GetTelemetryConfig().BindAddress)
  298. }
  299. func TestServiceToStart(t *testing.T) {
  300. reset()
  301. configDir := ".."
  302. err := config.LoadConfig(configDir, "")
  303. assert.NoError(t, err)
  304. assert.True(t, config.HasServicesToStart())
  305. sftpdConf := config.GetSFTPDConfig()
  306. sftpdConf.BindPort = 0
  307. config.SetSFTPDConfig(sftpdConf)
  308. assert.False(t, config.HasServicesToStart())
  309. ftpdConf := config.GetFTPDConfig()
  310. ftpdConf.BindPort = 2121
  311. config.SetFTPDConfig(ftpdConf)
  312. assert.True(t, config.HasServicesToStart())
  313. ftpdConf.BindPort = 0
  314. config.SetFTPDConfig(ftpdConf)
  315. webdavdConf := config.GetWebDAVDConfig()
  316. webdavdConf.BindPort = 9000
  317. config.SetWebDAVDConfig(webdavdConf)
  318. assert.True(t, config.HasServicesToStart())
  319. webdavdConf.BindPort = 0
  320. config.SetWebDAVDConfig(webdavdConf)
  321. assert.False(t, config.HasServicesToStart())
  322. sftpdConf.BindPort = 2022
  323. config.SetSFTPDConfig(sftpdConf)
  324. assert.True(t, config.HasServicesToStart())
  325. }
  326. func TestConfigFromEnv(t *testing.T) {
  327. reset()
  328. os.Setenv("SFTPGO_SFTPD__BIND_ADDRESS", "127.0.0.1")
  329. os.Setenv("SFTPGO_DATA_PROVIDER__PASSWORD_HASHING__ARGON2_OPTIONS__ITERATIONS", "41")
  330. os.Setenv("SFTPGO_DATA_PROVIDER__POOL_SIZE", "10")
  331. os.Setenv("SFTPGO_DATA_PROVIDER__ACTIONS__EXECUTE_ON", "add")
  332. os.Setenv("SFTPGO_KMS__SECRETS__URL", "local")
  333. os.Setenv("SFTPGO_KMS__SECRETS__MASTER_KEY_PATH", "path")
  334. t.Cleanup(func() {
  335. os.Unsetenv("SFTPGO_SFTPD__BIND_ADDRESS")
  336. os.Unsetenv("SFTPGO_DATA_PROVIDER__PASSWORD_HASHING__ARGON2_OPTIONS__ITERATIONS")
  337. os.Unsetenv("SFTPGO_DATA_PROVIDER__POOL_SIZE")
  338. os.Unsetenv("SFTPGO_DATA_PROVIDER__ACTIONS__EXECUTE_ON")
  339. os.Unsetenv("SFTPGO_KMS__SECRETS__URL")
  340. os.Unsetenv("SFTPGO_KMS__SECRETS__MASTER_KEY_PATH")
  341. })
  342. err := config.LoadConfig(".", "invalid config")
  343. assert.NoError(t, err)
  344. sftpdConfig := config.GetSFTPDConfig()
  345. assert.Equal(t, "127.0.0.1", sftpdConfig.BindAddress)
  346. dataProviderConf := config.GetProviderConf()
  347. assert.Equal(t, uint32(41), dataProviderConf.PasswordHashing.Argon2Options.Iterations)
  348. assert.Equal(t, 10, dataProviderConf.PoolSize)
  349. assert.Len(t, dataProviderConf.Actions.ExecuteOn, 1)
  350. assert.Contains(t, dataProviderConf.Actions.ExecuteOn, "add")
  351. kmsConfig := config.GetKMSConfig()
  352. assert.Equal(t, "local", kmsConfig.Secrets.URL)
  353. assert.Equal(t, "path", kmsConfig.Secrets.MasterKeyPath)
  354. }