diff --git a/api/api_test.go b/api/api_test.go index 5de07c07..bbd19ea4 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -52,7 +52,7 @@ func TestMain(m *testing.M) { configDir := ".." logfilePath := filepath.Join(configDir, "sftpgo_api_test.log") confName := "sftpgo.conf" - logger.InitLogger(logfilePath, zerolog.DebugLevel) + logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel) configFilePath := filepath.Join(configDir, confName) config.LoadConfig(configFilePath) providerConf := config.GetProviderConf() @@ -630,11 +630,11 @@ func waitTCPListening(address string) { for { conn, err := net.Dial("tcp", address) if err != nil { - fmt.Printf("tcp server %v not listening: %v\n", address, err) + logger.WarnToConsole("tcp server %v not listening: %v\n", address, err) time.Sleep(100 * time.Millisecond) continue } - fmt.Printf("tcp server %v now listening\n", address) + logger.InfoToConsole("tcp server %v now listening\n", address) defer conn.Close() break } diff --git a/api/api_utils.go b/api/api_utils.go index d3e7a539..5873215b 100644 --- a/api/api_utils.go +++ b/api/api_utils.go @@ -12,6 +12,7 @@ import ( "time" "github.com/drakkan/sftpgo/dataprovider" + "github.com/drakkan/sftpgo/logger" "github.com/drakkan/sftpgo/sftpd" "github.com/drakkan/sftpgo/utils" "github.com/go-chi/render" @@ -186,7 +187,7 @@ func checkResponse(actual int, expected int, resp *http.Response) error { if expected != http.StatusOK && resp != nil { b, err := ioutil.ReadAll(resp.Body) if err == nil { - fmt.Printf("request: %v, response body: %v", resp.Request.URL, string(b)) + logger.InfoToConsole("request: %v, response body: %v", resp.Request.URL, string(b)) } } return nil diff --git a/sftpd/server.go b/sftpd/server.go index a72a4d0e..06d88024 100644 --- a/sftpd/server.go +++ b/sftpd/server.go @@ -54,7 +54,6 @@ func (c Configuration) Initialize(configDir string) error { logger.Warn(logSender, "error reading umask, please fix your config file: %v", err) logger.WarnToConsole("error reading umask, please fix your config file: %v", err) } - actions = c.Actions serverConfig := &ssh.ServerConfig{ NoClientAuth: false, MaxAuthTries: c.MaxAuthTries, @@ -106,6 +105,7 @@ func (c Configuration) Initialize(configDir string) error { return err } + actions = c.Actions logger.Info(logSender, "server listener registered address: %v", listener.Addr().String()) if c.IdleTimeout > 0 { startIdleTimer(time.Duration(c.IdleTimeout) * time.Minute) diff --git a/sftpd/sftpd_test.go b/sftpd/sftpd_test.go index 7870513f..d73a1bd1 100644 --- a/sftpd/sftpd_test.go +++ b/sftpd/sftpd_test.go @@ -29,12 +29,13 @@ import ( ) const ( - logSender = "sftpdTesting" - sftpServerAddr = "127.0.0.1:2022" - defaultUsername = "test_user_sftp" - defaultPassword = "test_password" - testPubKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1" - testPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- + logSender = "sftpdTesting" + sftpServerAddr = "127.0.0.1:2022" + defaultUsername = "test_user_sftp" + defaultPassword = "test_password" + testPubKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1" + testInvalidPublicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCd60+/j+y8f0tLftihWV1YN9RSahMI9btQMDIMqts/jeNbD8jgoogM3nhF7KxfcaMKURuD47KC4Ey6iAJUJ0sWkSNNxOcIYuvA+5MlspfZDsa8Ag76Fe1vyz72WeHMHMeh/hwFo2TeIeIXg480T1VI6mzfDrVp2GzUx0SS0dMsQBjftXkuVR8YOiOwMCAH2a//M1OrvV7d/NBk6kBN0WnuIBb2jKm15PAA7+jQQG7tzwk2HedNH3jeL5GH31xkSRwlBczRK0xsCQXehAlx6cT/e/s44iJcJTHfpPKoSk6UAhPJYe7Z1QnuoawY9P9jQaxpyeImBZxxUEowhjpj2avBxKdRGBVK8R7EL8tSOeLbhdyWe5Mwc1+foEbq9Zz5j5Kd+hn3Wm1UnsGCrXUUUoZp1jnlNl0NakCto+5KmqnT9cHxaY+ix2RLUWAZyVFlRq71OYux1UHJnEJPiEI1/tr4jFBSL46qhQZv/TfpkfVW8FLz0lErfqu0gQEZnNHr3Fc= nicola@p1" + testPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn NhAAAAAwEAAQAAAYEAtN449A/nY5O6cSH/9Doa8a3ISU0WZJaHydTaCLuO+dkqtNpnV5mq zFbKidXAI1eSwVctw9ReVOl1uK6aZF3lbXdOD8W9PXobR9KUUT2qBx5QC4ibfAqDKWymDA @@ -72,19 +73,19 @@ NbbCNsVroqKlChT5wyPNGS+phi2bPARBno7WSDvshTZ7dAVEP2c9MJW0XwoSevwKlhgSdt RLFFQ/5nclJSdzPBOmQouC0OBcMFSrYtMeknJ4VvueVvve5HcHFaEsaMc7ABAGaLYaBQOm iixITGvaNZh/tjAAAACW5pY29sYUBwMQE= -----END OPENSSH PRIVATE KEY-----` + configDir = ".." + confName = "sftpgo.conf" ) var ( - allPerms = []string{dataprovider.PermAny} - homeBasePath string + allPerms = []string{dataprovider.PermAny} + homeBasePath string + configFilePath = filepath.Join(configDir, confName) ) func TestMain(m *testing.M) { - configDir := ".." logfilePath := filepath.Join(configDir, "sftpgo_sftpd_test.log") - confName := "sftpgo.conf" - logger.InitLogger(logfilePath, zerolog.DebugLevel) - configFilePath := filepath.Join(configDir, confName) + logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel) config.LoadConfig(configFilePath) providerConf := config.GetProviderConf() @@ -101,7 +102,7 @@ func TestMain(m *testing.M) { homeBasePath = "C:\\" } else { homeBasePath = "/tmp" - sftpdConf.Actions.ExecuteOn = []string{"download", "upload", "delete"} + sftpdConf.Actions.ExecuteOn = []string{"download", "upload", "rename"} sftpdConf.Actions.Command = "/bin/true" sftpdConf.Actions.HTTPNotificationURL = "http://127.0.0.1:8080/" } @@ -138,6 +139,16 @@ func TestMain(m *testing.M) { os.Exit(exitCode) } +func TestInitialization(t *testing.T) { + config.LoadConfig(configFilePath) + sftpdConf := config.GetSFTPDConfig() + sftpdConf.Umask = "invalid umask" + err := sftpdConf.Initialize(configDir) + if err == nil { + t.Errorf("Inizialize must fail, a SFTP server should be already running") + } +} + func TestBasicSFTPHandling(t *testing.T) { usePubKey := false user, err := api.AddUser(getTestUser(usePubKey), http.StatusOK) @@ -450,26 +461,50 @@ func TestHomeSpecialChars(t *testing.T) { } } -func TestLoginPubKey(t *testing.T) { - usePubKey := true - user, err := api.AddUser(getTestUser(usePubKey), http.StatusOK) +func TestLogin(t *testing.T) { + u := getTestUser(false) + u.PublicKey = testPubKey + user, err := api.AddUser(u, http.StatusOK) if err != nil { t.Errorf("unable to add user: %v", err) } - client, err := getSftpClient(user, usePubKey) + client, err := getSftpClient(user, false) if err != nil { t.Errorf("unable to create sftp client: %v", err) } else { defer client.Close() _, err := client.Getwd() if err != nil { - t.Errorf("unable to get working dir: %v", err) + t.Errorf("sftp client with valid password must work") } - _, err = client.ReadDir(".") + } + client, err = getSftpClient(user, true) + if err != nil { + t.Errorf("unable to create sftp client: %v", err) + } else { + defer client.Close() + _, err := client.Getwd() if err != nil { - t.Errorf("unable to read remote dir: %v", err) + t.Errorf("sftp client with valid public key must work") } } + user.Password = "invalid password" + client, err = getSftpClient(user, false) + if err == nil { + t.Errorf("login with invalid password must fail") + defer client.Close() + } + user.PublicKey = testInvalidPublicKey + user.Password = "" + _, err = api.UpdateUser(user, http.StatusOK) + if err != nil { + t.Errorf("unable to update user: %v", err) + } + client, err = getSftpClient(user, true) + if err == nil { + t.Errorf("login with invalid public key must fail") + defer client.Close() + } err = api.RemoveUser(user, http.StatusOK) if err != nil { t.Errorf("unable to remove user: %v", err) @@ -580,16 +615,16 @@ func TestQuotaFileReplace(t *testing.T) { if err != nil { t.Errorf("unable to add user: %v", err) } + testFileSize := int64(65535) + testFileName := "test_file.dat" + testFilePath := filepath.Join(homeBasePath, testFileName) client, err := getSftpClient(user, usePubKey) if err != nil { t.Errorf("unable to create sftp client: %v", err) } else { defer client.Close() - testFileSize := int64(65535) expectedQuotaSize := user.UsedQuotaSize + testFileSize expectedQuotaFiles := user.UsedQuotaFiles + 1 - testFileName := "test_file.dat" - testFilePath := filepath.Join(homeBasePath, testFileName) err = createTestFile(testFilePath, testFileSize) if err != nil { t.Errorf("unable to create test file: %v", err) @@ -623,6 +658,21 @@ func TestQuotaFileReplace(t *testing.T) { if expectedQuotaSize != user.UsedQuotaSize { t.Errorf("quota size does not match, expected: %v, actual: %v", expectedQuotaSize, user.UsedQuotaSize) } + } + // now set a quota size restriction and upload the same fail, upload should fail for space limit exceeded + user.QuotaSize = testFileSize - 1 + user, err = api.UpdateUser(user, http.StatusOK) + if err != nil { + t.Errorf("error updating user: %v", err) + } + client, err = getSftpClient(user, usePubKey) + if err != nil { + t.Errorf("unable to create sftp client: %v", err) + } else { + err = sftpUploadFile(testFilePath, testFileName, testFileSize, client) + if err == nil { + t.Errorf("quota size exceeded, file upload must fail") + } err = client.Remove(testFileName) if err != nil { t.Errorf("error removing uploaded file: %v", err) @@ -1094,11 +1144,11 @@ func waitTCPListening(address string) { for { conn, err := net.Dial("tcp", address) if err != nil { - fmt.Printf("tcp server %v not listening: %v\n", address, err) + logger.WarnToConsole("tcp server %v not listening: %v\n", address, err) time.Sleep(100 * time.Millisecond) continue } - fmt.Printf("tcp server %v now listening\n", address) + logger.InfoToConsole("tcp server %v now listening\n", address) defer conn.Close() break } @@ -1148,10 +1198,21 @@ func doSSH(user dataprovider.User, usePubKey bool) error { return err } +func modifyConf(sftpdConf sftpd.Configuration) { + if runtime.GOOS == "windows" { + homeBasePath = "C:\\" + } else { + homeBasePath = "/tmp" + sftpdConf.Actions.ExecuteOn = []string{"download", "upload", "rename"} + sftpdConf.Actions.Command = "/bin/true" + sftpdConf.Actions.HTTPNotificationURL = "http://127.0.0.1:8080/" + } +} + func getSftpClient(user dataprovider.User, usePubKey bool) (*sftp.Client, error) { var sftpClient *sftp.Client config := &ssh.ClientConfig{ - User: defaultUsername, + User: user.Username, HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }, @@ -1163,7 +1224,11 @@ func getSftpClient(user dataprovider.User, usePubKey bool) (*sftp.Client, error) } config.Auth = []ssh.AuthMethod{ssh.PublicKeys(key)} } else { - config.Auth = []ssh.AuthMethod{ssh.Password(defaultPassword)} + if len(user.Password) > 0 { + config.Auth = []ssh.AuthMethod{ssh.Password(user.Password)} + } else { + config.Auth = []ssh.AuthMethod{ssh.Password(defaultPassword)} + } } conn, err := ssh.Dial("tcp", sftpServerAddr, config) if err != nil {