diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 4c14d403..aa3b6029 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM golang:1.18-alpine3.15 AS builder +FROM golang:1.18-alpine3.16 AS builder ENV GOFLAGS="-mod=readonly" diff --git a/go.mod b/go.mod index 8b497380..b63d4425 100644 --- a/go.mod +++ b/go.mod @@ -157,7 +157,7 @@ require ( google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 // indirect google.golang.org/grpc v1.46.2 // indirect google.golang.org/protobuf v1.28.0 // indirect - gopkg.in/ini.v1 v1.66.4 // indirect + gopkg.in/ini.v1 v1.66.5 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index a2cda16e..f2169f3c 100644 --- a/go.sum +++ b/go.sum @@ -1257,8 +1257,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= -gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.5 h1:zfiCO0p88Fj4f6NR6KR5WdGMQ02U8vlDnN6HuD2xv5o= +gopkg.in/ini.v1 v1.66.5/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= diff --git a/httpd/api_folder.go b/httpd/api_folder.go index f2f25fa7..7c999518 100644 --- a/httpd/api_folder.go +++ b/httpd/api_folder.go @@ -67,7 +67,7 @@ func updateFolder(w http.ResponseWriter, r *http.Request) { currentCryptoPassphrase := folder.FsConfig.CryptConfig.Passphrase currentSFTPPassword := folder.FsConfig.SFTPConfig.Password currentSFTPKey := folder.FsConfig.SFTPConfig.PrivateKey - currentSFTPKeyPassphrase := folder.FsConfig.SFTPConfig.Passphrase + currentSFTPKeyPassphrase := folder.FsConfig.SFTPConfig.KeyPassphrase folder.FsConfig.S3Config = vfs.S3FsConfig{} folder.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{} diff --git a/httpd/api_group.go b/httpd/api_group.go index c619f9b4..d483b572 100644 --- a/httpd/api_group.go +++ b/httpd/api_group.go @@ -72,7 +72,7 @@ func updateGroup(w http.ResponseWriter, r *http.Request) { currentCryptoPassphrase := group.UserSettings.FsConfig.CryptConfig.Passphrase currentSFTPPassword := group.UserSettings.FsConfig.SFTPConfig.Password currentSFTPKey := group.UserSettings.FsConfig.SFTPConfig.PrivateKey - currentSFTPKeyPassphrase := group.UserSettings.FsConfig.SFTPConfig.Passphrase + currentSFTPKeyPassphrase := group.UserSettings.FsConfig.SFTPConfig.KeyPassphrase group.UserSettings.FsConfig.S3Config = vfs.S3FsConfig{} group.UserSettings.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{} diff --git a/httpd/api_user.go b/httpd/api_user.go index b278d7f1..16cac82e 100644 --- a/httpd/api_user.go +++ b/httpd/api_user.go @@ -134,7 +134,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) { currentCryptoPassphrase := user.FsConfig.CryptConfig.Passphrase currentSFTPPassword := user.FsConfig.SFTPConfig.Password currentSFTPKey := user.FsConfig.SFTPConfig.PrivateKey - currentSFTPKeyPassphrase := user.FsConfig.SFTPConfig.Passphrase + currentSFTPKeyPassphrase := user.FsConfig.SFTPConfig.KeyPassphrase user.Permissions = make(map[string][]string) user.FsConfig.S3Config = vfs.S3FsConfig{} @@ -263,8 +263,8 @@ func updateEncryptedSecrets(fsConfig *vfs.Filesystem, currentS3AccessSecret, cur if fsConfig.SFTPConfig.PrivateKey.IsNotPlainAndNotEmpty() { fsConfig.SFTPConfig.PrivateKey = currentSFTPKey } - if fsConfig.SFTPConfig.Passphrase.IsNotPlainAndNotEmpty() { - fsConfig.SFTPConfig.Passphrase = currentSFTPKeyPassphrase + if fsConfig.SFTPConfig.KeyPassphrase.IsNotPlainAndNotEmpty() { + fsConfig.SFTPConfig.KeyPassphrase = currentSFTPKeyPassphrase } } } diff --git a/httpd/httpd_test.go b/httpd/httpd_test.go index d794ad7e..85c08bf7 100644 --- a/httpd/httpd_test.go +++ b/httpd/httpd_test.go @@ -202,9 +202,21 @@ AAAEA0E24gi8ab/XRSvJ85TGZJMe6HVmwxSG4ExPfTMwwe2n5EHjI1NnP2Yc6RrDBSJs11 6aKNVXcSsx4vFZQGUI3+AAAACW5pY29sYUBwMQECAwQ= -----END OPENSSH PRIVATE KEY-----` sftpPkeyFingerprint = "SHA256:QVQ06XHZZbYZzqfrsZcf3Yozy2WTnqQPeLOkcJCdbP0" - redactedSecret = "[**redacted**]" - osWindows = "windows" - oidcMockAddr = "127.0.0.1:11111" + // password protected private key + testPrivateKeyPwd = `-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAvfwQQcs ++PyMsCLTNFcKiQAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAILqltfCL7IPuIQ2q ++8w23flfgskjIlKViEwMfjJR4mrbAAAAkHp5xgG8J1XW90M/fT59ZUQht8sZzzP17rEKlX +waYKvLzDxkPK6LFIYs55W1EX1eVt/2Maq+zQ7k2SOUmhPNknsUOlPV2gytX3uIYvXF7u2F +FTBIJuzZ+UQ14wFbraunliE9yye9DajVG1kz2cz2wVgXUbee+gp5NyFVvln+TcTxXwMsWD +qwlk5iw/jQekxThg== +-----END OPENSSH PRIVATE KEY----- +` + testPubKeyPwd = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILqltfCL7IPuIQ2q+8w23flfgskjIlKViEwMfjJR4mrb" + privateKeyPwd = "password" + redactedSecret = "[**redacted**]" + osWindows = "windows" + oidcMockAddr = "127.0.0.1:11111" ) var ( @@ -13136,6 +13148,58 @@ func TestWebUploadSFTP(t *testing.T) { assert.NoError(t, err) } +func TestWebAPISFTPPasswordProtectedPrivateKey(t *testing.T) { + u := getTestUser() + u.Password = "" + u.PublicKeys = []string{testPubKeyPwd} + localUser, _, err := httpdtest.AddUser(u, http.StatusCreated) + assert.NoError(t, err) + u = getTestSFTPUser() + u.FsConfig.SFTPConfig.Password = kms.NewEmptySecret() + u.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(testPrivateKeyPwd) + u.FsConfig.SFTPConfig.KeyPassphrase = kms.NewPlainSecret(privateKeyPwd) + u.HomeDir = filepath.Join(os.TempDir(), u.Username) + sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated) + assert.NoError(t, err) + + webToken, err := getJWTWebClientTokenFromTestServer(sftpUser.Username, defaultPassword) + assert.NoError(t, err) + req, err := http.NewRequest(http.MethodGet, webClientFilesPath, nil) + assert.NoError(t, err) + setJWTCookieForReq(req, webToken) + rr := executeRequest(req) + checkResponseCode(t, http.StatusOK, rr) + // update the user, the key must be preserved + assert.Equal(t, sdkkms.SecretStatusSecretBox, sftpUser.FsConfig.SFTPConfig.KeyPassphrase.GetStatus()) + _, _, err = httpdtest.UpdateUser(sftpUser, http.StatusOK, "") + assert.NoError(t, err) + req, err = http.NewRequest(http.MethodGet, webClientFilesPath, nil) + assert.NoError(t, err) + setJWTCookieForReq(req, webToken) + rr = executeRequest(req) + checkResponseCode(t, http.StatusOK, rr) + // using a wrong passphrase or no passphrase should fail + sftpUser.FsConfig.SFTPConfig.KeyPassphrase = kms.NewPlainSecret("wrong") + _, _, err = httpdtest.UpdateUser(sftpUser, http.StatusOK, "") + assert.NoError(t, err) + _, err = getJWTWebClientTokenFromTestServer(sftpUser.Username, defaultPassword) + assert.Error(t, err) + sftpUser.FsConfig.SFTPConfig.KeyPassphrase = kms.NewEmptySecret() + _, _, err = httpdtest.UpdateUser(sftpUser, http.StatusOK, "") + assert.NoError(t, err) + _, err = getJWTWebClientTokenFromTestServer(sftpUser.Username, defaultPassword) + assert.Error(t, err) + + _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) + assert.NoError(t, err) + _, err = httpdtest.RemoveUser(localUser, http.StatusOK) + assert.NoError(t, err) + err = os.RemoveAll(localUser.GetHomeDir()) + assert.NoError(t, err) + err = os.RemoveAll(sftpUser.GetHomeDir()) + assert.NoError(t, err) +} + func TestWebUploadMultipartFormReadError(t *testing.T) { user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated) assert.NoError(t, err) @@ -17198,6 +17262,7 @@ func TestWebUserSFTPFsMock(t *testing.T) { user.FsConfig.SFTPConfig.Username = "sftpuser" user.FsConfig.SFTPConfig.Password = kms.NewPlainSecret("pwd") user.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey) + user.FsConfig.SFTPConfig.KeyPassphrase = kms.NewPlainSecret(testPrivateKeyPwd) user.FsConfig.SFTPConfig.Fingerprints = []string{sftpPkeyFingerprint} user.FsConfig.SFTPConfig.Prefix = "/home/sftpuser" user.FsConfig.SFTPConfig.DisableCouncurrentReads = true @@ -17243,6 +17308,7 @@ func TestWebUserSFTPFsMock(t *testing.T) { form.Set("sftp_username", user.FsConfig.SFTPConfig.Username) form.Set("sftp_password", user.FsConfig.SFTPConfig.Password.GetPayload()) form.Set("sftp_private_key", user.FsConfig.SFTPConfig.PrivateKey.GetPayload()) + form.Set("sftp_key_passphrase", user.FsConfig.SFTPConfig.KeyPassphrase.GetPayload()) form.Set("sftp_fingerprints", user.FsConfig.SFTPConfig.Fingerprints[0]) form.Set("sftp_prefix", user.FsConfig.SFTPConfig.Prefix) form.Set("sftp_disable_concurrent_reads", "true") @@ -17270,6 +17336,10 @@ func TestWebUserSFTPFsMock(t *testing.T) { assert.NotEmpty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetPayload()) assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetKey()) assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, updateUser.FsConfig.SFTPConfig.KeyPassphrase.GetStatus()) + assert.NotEmpty(t, updateUser.FsConfig.SFTPConfig.KeyPassphrase.GetPayload()) + assert.Empty(t, updateUser.FsConfig.SFTPConfig.KeyPassphrase.GetKey()) + assert.Empty(t, updateUser.FsConfig.SFTPConfig.KeyPassphrase.GetAdditionalData()) assert.Equal(t, updateUser.FsConfig.SFTPConfig.Prefix, user.FsConfig.SFTPConfig.Prefix) assert.Equal(t, updateUser.FsConfig.SFTPConfig.Username, user.FsConfig.SFTPConfig.Username) assert.Equal(t, updateUser.FsConfig.SFTPConfig.Endpoint, user.FsConfig.SFTPConfig.Endpoint) @@ -17280,6 +17350,7 @@ func TestWebUserSFTPFsMock(t *testing.T) { // now check that a redacted credentials are not saved form.Set("sftp_password", redactedSecret+" ") form.Set("sftp_private_key", redactedSecret) + form.Set("sftp_key_passphrase", redactedSecret) b, contentType, _ = getMultipartFormData(form, "", "") req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b) setJWTCookieForReq(req, webToken) @@ -17301,6 +17372,10 @@ func TestWebUserSFTPFsMock(t *testing.T) { assert.Equal(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetPayload(), lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetPayload()) assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetKey()) assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData()) + assert.Equal(t, sdkkms.SecretStatusSecretBox, lastUpdatedUser.FsConfig.SFTPConfig.KeyPassphrase.GetStatus()) + assert.Equal(t, updateUser.FsConfig.SFTPConfig.KeyPassphrase.GetPayload(), lastUpdatedUser.FsConfig.SFTPConfig.KeyPassphrase.GetPayload()) + assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.KeyPassphrase.GetKey()) + assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.KeyPassphrase.GetAdditionalData()) req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil) setBearerForReq(req, apiToken) rr = executeRequest(req) diff --git a/httpd/webadmin.go b/httpd/webadmin.go index 6639ca71..5b662f52 100644 --- a/httpd/webadmin.go +++ b/httpd/webadmin.go @@ -1219,7 +1219,7 @@ func getSFTPConfig(r *http.Request) (vfs.SFTPFsConfig, error) { config.Username = r.Form.Get("sftp_username") config.Password = getSecretFromFormField(r, "sftp_password") config.PrivateKey = getSecretFromFormField(r, "sftp_private_key") - config.Passphrase = getSecretFromFormField(r, "sftp_passphrase") + config.KeyPassphrase = getSecretFromFormField(r, "sftp_key_passphrase") fingerprintsFormValue := r.Form.Get("sftp_fingerprints") config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n") config.Prefix = r.Form.Get("sftp_prefix") @@ -2203,7 +2203,7 @@ func (s *httpdServer) handleWebUpdateUserPost(w http.ResponseWriter, r *http.Req } updateEncryptedSecrets(&updatedUser.FsConfig, user.FsConfig.S3Config.AccessSecret, user.FsConfig.AzBlobConfig.AccountKey, user.FsConfig.AzBlobConfig.SASURL, user.FsConfig.GCSConfig.Credentials, user.FsConfig.CryptConfig.Passphrase, - user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey, user.FsConfig.SFTPConfig.Passphrase) + user.FsConfig.SFTPConfig.Password, user.FsConfig.SFTPConfig.PrivateKey, user.FsConfig.SFTPConfig.KeyPassphrase) updatedUser = getUserFromTemplate(updatedUser, userTemplateFields{ Username: updatedUser.Username, @@ -2337,7 +2337,7 @@ func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.R updatedFolder.FsConfig.SetEmptySecretsIfNil() updateEncryptedSecrets(&updatedFolder.FsConfig, folder.FsConfig.S3Config.AccessSecret, folder.FsConfig.AzBlobConfig.AccountKey, folder.FsConfig.AzBlobConfig.SASURL, folder.FsConfig.GCSConfig.Credentials, folder.FsConfig.CryptConfig.Passphrase, - folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey, folder.FsConfig.SFTPConfig.Passphrase) + folder.FsConfig.SFTPConfig.Password, folder.FsConfig.SFTPConfig.PrivateKey, folder.FsConfig.SFTPConfig.KeyPassphrase) updatedFolder = getFolderFromTemplate(updatedFolder, updatedFolder.Name) @@ -2501,7 +2501,8 @@ func (s *httpdServer) handleWebUpdateGroupPost(w http.ResponseWriter, r *http.Re updateEncryptedSecrets(&updatedGroup.UserSettings.FsConfig, group.UserSettings.FsConfig.S3Config.AccessSecret, group.UserSettings.FsConfig.AzBlobConfig.AccountKey, group.UserSettings.FsConfig.AzBlobConfig.SASURL, group.UserSettings.FsConfig.GCSConfig.Credentials, group.UserSettings.FsConfig.CryptConfig.Passphrase, - group.UserSettings.FsConfig.SFTPConfig.Password, group.UserSettings.FsConfig.SFTPConfig.PrivateKey, group.UserSettings.FsConfig.SFTPConfig.Passphrase) + group.UserSettings.FsConfig.SFTPConfig.Password, group.UserSettings.FsConfig.SFTPConfig.PrivateKey, + group.UserSettings.FsConfig.SFTPConfig.KeyPassphrase) err = dataprovider.UpdateGroup(&updatedGroup, group.Users, claims.Username, ipAddr) if err != nil { diff --git a/httpdtest/httpdtest.go b/httpdtest/httpdtest.go index deb5e540..7c63acaa 100644 --- a/httpdtest/httpdtest.go +++ b/httpdtest/httpdtest.go @@ -1521,6 +1521,9 @@ func compareSFTPFsConfig(expected *vfs.Filesystem, actual *vfs.Filesystem) error if err := checkEncryptedSecret(expected.SFTPConfig.PrivateKey, actual.SFTPConfig.PrivateKey); err != nil { return fmt.Errorf("SFTPFs private key mismatch: %v", err) } + if err := checkEncryptedSecret(expected.SFTPConfig.KeyPassphrase, actual.SFTPConfig.KeyPassphrase); err != nil { + return fmt.Errorf("SFTPFs private key passphrase mismatch: %v", err) + } if expected.SFTPConfig.Prefix != actual.SFTPConfig.Prefix { if expected.SFTPConfig.Prefix != "" && actual.SFTPConfig.Prefix != "/" { return errors.New("SFTPFs prefix mismatch") diff --git a/kms/kms.go b/kms/kms.go index 96db84bd..9cfd123f 100644 --- a/kms/kms.go +++ b/kms/kms.go @@ -86,7 +86,7 @@ func NewEmptySecret() *Secret { // NewPlainSecret stores the give payload in a plain text secret func NewPlainSecret(payload string) *Secret { - return NewSecret(sdkkms.SecretStatusPlain, payload, "", "") + return NewSecret(sdkkms.SecretStatusPlain, strings.TrimSpace(payload), "", "") } // Initialize configures the KMS support diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index f442f4d4..99a1a917 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -5035,6 +5035,8 @@ components: $ref: '#/components/schemas/Secret' private_key: $ref: '#/components/schemas/Secret' + key_passphrase: + $ref: '#/components/schemas/Secret' fingerprints: type: array items: diff --git a/sftpd/sftpd_test.go b/sftpd/sftpd_test.go index f276e504..73c31b87 100644 --- a/sftpd/sftpd_test.go +++ b/sftpd/sftpd_test.go @@ -102,6 +102,18 @@ NbbCNsVroqKlChT5wyPNGS+phi2bPARBno7WSDvshTZ7dAVEP2c9MJW0XwoSevwKlhgSdt RLFFQ/5nclJSdzPBOmQouC0OBcMFSrYtMeknJ4VvueVvve5HcHFaEsaMc7ABAGaLYaBQOm iixITGvaNZh/tjAAAACW5pY29sYUBwMQE= -----END OPENSSH PRIVATE KEY-----` + // password protected private key + testPrivateKeyPwd = `-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAvfwQQcs ++PyMsCLTNFcKiQAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAILqltfCL7IPuIQ2q ++8w23flfgskjIlKViEwMfjJR4mrbAAAAkHp5xgG8J1XW90M/fT59ZUQht8sZzzP17rEKlX +waYKvLzDxkPK6LFIYs55W1EX1eVt/2Maq+zQ7k2SOUmhPNknsUOlPV2gytX3uIYvXF7u2F +FTBIJuzZ+UQ14wFbraunliE9yye9DajVG1kz2cz2wVgXUbee+gp5NyFVvln+TcTxXwMsWD +qwlk5iw/jQekxThg== +-----END OPENSSH PRIVATE KEY----- +` + testPubKeyPwd = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILqltfCL7IPuIQ2q+8w23flfgskjIlKViEwMfjJR4mrb" + privateKeyPwd = "password" // test CA user key. // % ssh-keygen -f ca_user_key testCAUserKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDF5fcwZHiyixmnE6IlOZJpZhWXoh62gN+yadAA0GJ509SAEaZVLPDP8S5RsE8mUikR3wxynVshxHeqMhrkS+RlNbhSlOXDdNg94yTrq/xF8Z/PgKRInvef74k5i7bAIytza7jERzFJ/ujTEy3537T5k5EYQJ15ZQGuvzynSdv+6o99SjI4jFplyQOZ2QcYbEAmhHm5GgQlIiEFG/RlDtLksOulKZxOY3qPzP0AyQxtZJXn/5vG40aW9LTbwxCJqWlgrkFXMqAAVCbuU5YspwhiXmKt1PsldiXw23oloa4caCKN1jzbFiGuZNXEU2Ebx7JIvjQCPaUYwLjEbkRDxDqN/vmwZqBuKYiuG9Eafx+nFSQkr7QYb5b+mT+/1IFHnmeRGn38731kBqtH7tpzC/t+soRX9p2HtJM+9MYhblO2OqTSPGTlxihWUkyiRBekpAhaiHld16TsG+A3bOJHrojGcX+5g6oGarKGLAMcykL1X+rZqT993Mo6d2Z7q43MOXE= root@p1" @@ -632,6 +644,43 @@ func TestBasicSFTPFsHandling(t *testing.T) { assert.NoError(t, err) } +func TestSFTPFsPasswordProtectedPrivateKey(t *testing.T) { + usePubKey := false + u := getTestUser(true) + u.PublicKeys = []string{testPubKeyPwd} + baseUser, _, err := httpdtest.AddUser(u, http.StatusCreated) + assert.NoError(t, err) + u = getTestSFTPUser(usePubKey) + u.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(testPrivateKeyPwd) + u.FsConfig.SFTPConfig.KeyPassphrase = kms.NewPlainSecret(privateKeyPwd) + user, _, err := httpdtest.AddUser(u, http.StatusCreated) + assert.NoError(t, err) + conn, client, err := getSftpClient(user, usePubKey) + if assert.NoError(t, err) { + defer conn.Close() + defer client.Close() + err = checkBasicSFTP(client) + assert.NoError(t, err) + } + // update the user, the key must be preserved + _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") + assert.NoError(t, err) + conn, client, err = getSftpClient(user, usePubKey) + if assert.NoError(t, err) { + defer conn.Close() + defer client.Close() + err = checkBasicSFTP(client) + assert.NoError(t, err) + } + + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + _, err = httpdtest.RemoveUser(baseUser, http.StatusOK) + assert.NoError(t, err) + err = os.RemoveAll(baseUser.GetHomeDir()) + assert.NoError(t, err) +} + func TestSFTPFsEscapeHomeDir(t *testing.T) { usePubKey := true baseUser, _, err := httpdtest.AddUser(getTestUser(usePubKey), http.StatusCreated) diff --git a/templates/webadmin/fsconfig.html b/templates/webadmin/fsconfig.html index 879b4123..5a5ac279 100644 --- a/templates/webadmin/fsconfig.html +++ b/templates/webadmin/fsconfig.html @@ -419,18 +419,19 @@