Fixes #855
update OpenAPI definition, add test cases, fix lint Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
84e3132ed1
commit
7329cd804b
16 changed files with 200 additions and 63 deletions
|
@ -1,4 +1,4 @@
|
||||||
FROM golang:1.18-alpine3.15 AS builder
|
FROM golang:1.18-alpine3.16 AS builder
|
||||||
|
|
||||||
ENV GOFLAGS="-mod=readonly"
|
ENV GOFLAGS="-mod=readonly"
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -157,7 +157,7 @@ require (
|
||||||
google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 // indirect
|
google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 // indirect
|
||||||
google.golang.org/grpc v1.46.2 // indirect
|
google.golang.org/grpc v1.46.2 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // 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/square/go-jose.v2 v2.6.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|
4
go.sum
4
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/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/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/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.5 h1:zfiCO0p88Fj4f6NR6KR5WdGMQ02U8vlDnN6HuD2xv5o=
|
||||||
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
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 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
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=
|
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
|
|
@ -67,7 +67,7 @@ func updateFolder(w http.ResponseWriter, r *http.Request) {
|
||||||
currentCryptoPassphrase := folder.FsConfig.CryptConfig.Passphrase
|
currentCryptoPassphrase := folder.FsConfig.CryptConfig.Passphrase
|
||||||
currentSFTPPassword := folder.FsConfig.SFTPConfig.Password
|
currentSFTPPassword := folder.FsConfig.SFTPConfig.Password
|
||||||
currentSFTPKey := folder.FsConfig.SFTPConfig.PrivateKey
|
currentSFTPKey := folder.FsConfig.SFTPConfig.PrivateKey
|
||||||
currentSFTPKeyPassphrase := folder.FsConfig.SFTPConfig.Passphrase
|
currentSFTPKeyPassphrase := folder.FsConfig.SFTPConfig.KeyPassphrase
|
||||||
|
|
||||||
folder.FsConfig.S3Config = vfs.S3FsConfig{}
|
folder.FsConfig.S3Config = vfs.S3FsConfig{}
|
||||||
folder.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{}
|
folder.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{}
|
||||||
|
|
|
@ -72,7 +72,7 @@ func updateGroup(w http.ResponseWriter, r *http.Request) {
|
||||||
currentCryptoPassphrase := group.UserSettings.FsConfig.CryptConfig.Passphrase
|
currentCryptoPassphrase := group.UserSettings.FsConfig.CryptConfig.Passphrase
|
||||||
currentSFTPPassword := group.UserSettings.FsConfig.SFTPConfig.Password
|
currentSFTPPassword := group.UserSettings.FsConfig.SFTPConfig.Password
|
||||||
currentSFTPKey := group.UserSettings.FsConfig.SFTPConfig.PrivateKey
|
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.S3Config = vfs.S3FsConfig{}
|
||||||
group.UserSettings.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{}
|
group.UserSettings.FsConfig.AzBlobConfig = vfs.AzBlobFsConfig{}
|
||||||
|
|
|
@ -134,7 +134,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
|
||||||
currentCryptoPassphrase := user.FsConfig.CryptConfig.Passphrase
|
currentCryptoPassphrase := user.FsConfig.CryptConfig.Passphrase
|
||||||
currentSFTPPassword := user.FsConfig.SFTPConfig.Password
|
currentSFTPPassword := user.FsConfig.SFTPConfig.Password
|
||||||
currentSFTPKey := user.FsConfig.SFTPConfig.PrivateKey
|
currentSFTPKey := user.FsConfig.SFTPConfig.PrivateKey
|
||||||
currentSFTPKeyPassphrase := user.FsConfig.SFTPConfig.Passphrase
|
currentSFTPKeyPassphrase := user.FsConfig.SFTPConfig.KeyPassphrase
|
||||||
|
|
||||||
user.Permissions = make(map[string][]string)
|
user.Permissions = make(map[string][]string)
|
||||||
user.FsConfig.S3Config = vfs.S3FsConfig{}
|
user.FsConfig.S3Config = vfs.S3FsConfig{}
|
||||||
|
@ -263,8 +263,8 @@ func updateEncryptedSecrets(fsConfig *vfs.Filesystem, currentS3AccessSecret, cur
|
||||||
if fsConfig.SFTPConfig.PrivateKey.IsNotPlainAndNotEmpty() {
|
if fsConfig.SFTPConfig.PrivateKey.IsNotPlainAndNotEmpty() {
|
||||||
fsConfig.SFTPConfig.PrivateKey = currentSFTPKey
|
fsConfig.SFTPConfig.PrivateKey = currentSFTPKey
|
||||||
}
|
}
|
||||||
if fsConfig.SFTPConfig.Passphrase.IsNotPlainAndNotEmpty() {
|
if fsConfig.SFTPConfig.KeyPassphrase.IsNotPlainAndNotEmpty() {
|
||||||
fsConfig.SFTPConfig.Passphrase = currentSFTPKeyPassphrase
|
fsConfig.SFTPConfig.KeyPassphrase = currentSFTPKeyPassphrase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,6 +202,18 @@ AAAEA0E24gi8ab/XRSvJ85TGZJMe6HVmwxSG4ExPfTMwwe2n5EHjI1NnP2Yc6RrDBSJs11
|
||||||
6aKNVXcSsx4vFZQGUI3+AAAACW5pY29sYUBwMQECAwQ=
|
6aKNVXcSsx4vFZQGUI3+AAAACW5pY29sYUBwMQECAwQ=
|
||||||
-----END OPENSSH PRIVATE KEY-----`
|
-----END OPENSSH PRIVATE KEY-----`
|
||||||
sftpPkeyFingerprint = "SHA256:QVQ06XHZZbYZzqfrsZcf3Yozy2WTnqQPeLOkcJCdbP0"
|
sftpPkeyFingerprint = "SHA256:QVQ06XHZZbYZzqfrsZcf3Yozy2WTnqQPeLOkcJCdbP0"
|
||||||
|
// 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**]"
|
redactedSecret = "[**redacted**]"
|
||||||
osWindows = "windows"
|
osWindows = "windows"
|
||||||
oidcMockAddr = "127.0.0.1:11111"
|
oidcMockAddr = "127.0.0.1:11111"
|
||||||
|
@ -13136,6 +13148,58 @@ func TestWebUploadSFTP(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
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) {
|
func TestWebUploadMultipartFormReadError(t *testing.T) {
|
||||||
user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
|
user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -17198,6 +17262,7 @@ func TestWebUserSFTPFsMock(t *testing.T) {
|
||||||
user.FsConfig.SFTPConfig.Username = "sftpuser"
|
user.FsConfig.SFTPConfig.Username = "sftpuser"
|
||||||
user.FsConfig.SFTPConfig.Password = kms.NewPlainSecret("pwd")
|
user.FsConfig.SFTPConfig.Password = kms.NewPlainSecret("pwd")
|
||||||
user.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey)
|
user.FsConfig.SFTPConfig.PrivateKey = kms.NewPlainSecret(sftpPrivateKey)
|
||||||
|
user.FsConfig.SFTPConfig.KeyPassphrase = kms.NewPlainSecret(testPrivateKeyPwd)
|
||||||
user.FsConfig.SFTPConfig.Fingerprints = []string{sftpPkeyFingerprint}
|
user.FsConfig.SFTPConfig.Fingerprints = []string{sftpPkeyFingerprint}
|
||||||
user.FsConfig.SFTPConfig.Prefix = "/home/sftpuser"
|
user.FsConfig.SFTPConfig.Prefix = "/home/sftpuser"
|
||||||
user.FsConfig.SFTPConfig.DisableCouncurrentReads = true
|
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_username", user.FsConfig.SFTPConfig.Username)
|
||||||
form.Set("sftp_password", user.FsConfig.SFTPConfig.Password.GetPayload())
|
form.Set("sftp_password", user.FsConfig.SFTPConfig.Password.GetPayload())
|
||||||
form.Set("sftp_private_key", user.FsConfig.SFTPConfig.PrivateKey.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_fingerprints", user.FsConfig.SFTPConfig.Fingerprints[0])
|
||||||
form.Set("sftp_prefix", user.FsConfig.SFTPConfig.Prefix)
|
form.Set("sftp_prefix", user.FsConfig.SFTPConfig.Prefix)
|
||||||
form.Set("sftp_disable_concurrent_reads", "true")
|
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.NotEmpty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetPayload())
|
||||||
assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetKey())
|
assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetKey())
|
||||||
assert.Empty(t, updateUser.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
|
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.Prefix, user.FsConfig.SFTPConfig.Prefix)
|
||||||
assert.Equal(t, updateUser.FsConfig.SFTPConfig.Username, user.FsConfig.SFTPConfig.Username)
|
assert.Equal(t, updateUser.FsConfig.SFTPConfig.Username, user.FsConfig.SFTPConfig.Username)
|
||||||
assert.Equal(t, updateUser.FsConfig.SFTPConfig.Endpoint, user.FsConfig.SFTPConfig.Endpoint)
|
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
|
// now check that a redacted credentials are not saved
|
||||||
form.Set("sftp_password", redactedSecret+" ")
|
form.Set("sftp_password", redactedSecret+" ")
|
||||||
form.Set("sftp_private_key", redactedSecret)
|
form.Set("sftp_private_key", redactedSecret)
|
||||||
|
form.Set("sftp_key_passphrase", redactedSecret)
|
||||||
b, contentType, _ = getMultipartFormData(form, "", "")
|
b, contentType, _ = getMultipartFormData(form, "", "")
|
||||||
req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
|
req, _ = http.NewRequest(http.MethodPost, path.Join(webUserPath, user.Username), &b)
|
||||||
setJWTCookieForReq(req, webToken)
|
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.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.GetKey())
|
||||||
assert.Empty(t, lastUpdatedUser.FsConfig.SFTPConfig.PrivateKey.GetAdditionalData())
|
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)
|
req, _ = http.NewRequest(http.MethodDelete, path.Join(userPath, user.Username), nil)
|
||||||
setBearerForReq(req, apiToken)
|
setBearerForReq(req, apiToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
|
|
|
@ -1219,7 +1219,7 @@ func getSFTPConfig(r *http.Request) (vfs.SFTPFsConfig, error) {
|
||||||
config.Username = r.Form.Get("sftp_username")
|
config.Username = r.Form.Get("sftp_username")
|
||||||
config.Password = getSecretFromFormField(r, "sftp_password")
|
config.Password = getSecretFromFormField(r, "sftp_password")
|
||||||
config.PrivateKey = getSecretFromFormField(r, "sftp_private_key")
|
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")
|
fingerprintsFormValue := r.Form.Get("sftp_fingerprints")
|
||||||
config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n")
|
config.Fingerprints = getSliceFromDelimitedValues(fingerprintsFormValue, "\n")
|
||||||
config.Prefix = r.Form.Get("sftp_prefix")
|
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,
|
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.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{
|
updatedUser = getUserFromTemplate(updatedUser, userTemplateFields{
|
||||||
Username: updatedUser.Username,
|
Username: updatedUser.Username,
|
||||||
|
@ -2337,7 +2337,7 @@ func (s *httpdServer) handleWebUpdateFolderPost(w http.ResponseWriter, r *http.R
|
||||||
updatedFolder.FsConfig.SetEmptySecretsIfNil()
|
updatedFolder.FsConfig.SetEmptySecretsIfNil()
|
||||||
updateEncryptedSecrets(&updatedFolder.FsConfig, folder.FsConfig.S3Config.AccessSecret, folder.FsConfig.AzBlobConfig.AccountKey,
|
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.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)
|
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,
|
updateEncryptedSecrets(&updatedGroup.UserSettings.FsConfig, group.UserSettings.FsConfig.S3Config.AccessSecret,
|
||||||
group.UserSettings.FsConfig.AzBlobConfig.AccountKey, group.UserSettings.FsConfig.AzBlobConfig.SASURL,
|
group.UserSettings.FsConfig.AzBlobConfig.AccountKey, group.UserSettings.FsConfig.AzBlobConfig.SASURL,
|
||||||
group.UserSettings.FsConfig.GCSConfig.Credentials, group.UserSettings.FsConfig.CryptConfig.Passphrase,
|
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)
|
err = dataprovider.UpdateGroup(&updatedGroup, group.Users, claims.Username, ipAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1521,6 +1521,9 @@ func compareSFTPFsConfig(expected *vfs.Filesystem, actual *vfs.Filesystem) error
|
||||||
if err := checkEncryptedSecret(expected.SFTPConfig.PrivateKey, actual.SFTPConfig.PrivateKey); err != nil {
|
if err := checkEncryptedSecret(expected.SFTPConfig.PrivateKey, actual.SFTPConfig.PrivateKey); err != nil {
|
||||||
return fmt.Errorf("SFTPFs private key mismatch: %v", err)
|
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 {
|
||||||
if expected.SFTPConfig.Prefix != "" && actual.SFTPConfig.Prefix != "/" {
|
if expected.SFTPConfig.Prefix != "" && actual.SFTPConfig.Prefix != "/" {
|
||||||
return errors.New("SFTPFs prefix mismatch")
|
return errors.New("SFTPFs prefix mismatch")
|
||||||
|
|
|
@ -86,7 +86,7 @@ func NewEmptySecret() *Secret {
|
||||||
|
|
||||||
// NewPlainSecret stores the give payload in a plain text secret
|
// NewPlainSecret stores the give payload in a plain text secret
|
||||||
func NewPlainSecret(payload string) *Secret {
|
func NewPlainSecret(payload string) *Secret {
|
||||||
return NewSecret(sdkkms.SecretStatusPlain, payload, "", "")
|
return NewSecret(sdkkms.SecretStatusPlain, strings.TrimSpace(payload), "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize configures the KMS support
|
// Initialize configures the KMS support
|
||||||
|
|
|
@ -5035,6 +5035,8 @@ components:
|
||||||
$ref: '#/components/schemas/Secret'
|
$ref: '#/components/schemas/Secret'
|
||||||
private_key:
|
private_key:
|
||||||
$ref: '#/components/schemas/Secret'
|
$ref: '#/components/schemas/Secret'
|
||||||
|
key_passphrase:
|
||||||
|
$ref: '#/components/schemas/Secret'
|
||||||
fingerprints:
|
fingerprints:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
|
|
@ -102,6 +102,18 @@ NbbCNsVroqKlChT5wyPNGS+phi2bPARBno7WSDvshTZ7dAVEP2c9MJW0XwoSevwKlhgSdt
|
||||||
RLFFQ/5nclJSdzPBOmQouC0OBcMFSrYtMeknJ4VvueVvve5HcHFaEsaMc7ABAGaLYaBQOm
|
RLFFQ/5nclJSdzPBOmQouC0OBcMFSrYtMeknJ4VvueVvve5HcHFaEsaMc7ABAGaLYaBQOm
|
||||||
iixITGvaNZh/tjAAAACW5pY29sYUBwMQE=
|
iixITGvaNZh/tjAAAACW5pY29sYUBwMQE=
|
||||||
-----END OPENSSH PRIVATE KEY-----`
|
-----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.
|
// test CA user key.
|
||||||
// % ssh-keygen -f 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"
|
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)
|
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) {
|
func TestSFTPFsEscapeHomeDir(t *testing.T) {
|
||||||
usePubKey := true
|
usePubKey := true
|
||||||
baseUser, _, err := httpdtest.AddUser(getTestUser(usePubKey), http.StatusCreated)
|
baseUser, _, err := httpdtest.AddUser(getTestUser(usePubKey), http.StatusCreated)
|
||||||
|
|
|
@ -419,18 +419,19 @@
|
||||||
<div class="form-group row fsconfig fsconfig-sftpfs">
|
<div class="form-group row fsconfig fsconfig-sftpfs">
|
||||||
<label for="idSFTPPrivateKey" class="col-sm-2 col-form-label">Private key</label>
|
<label for="idSFTPPrivateKey" class="col-sm-2 col-form-label">Private key</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<textarea type="password" class="form-control" id="idSFTPPrivateKey" name="sftp_private_key"
|
<textarea class="form-control" id="idSFTPPrivateKey" name="sftp_private_key"
|
||||||
rows="3">{{if .SFTPConfig.PrivateKey.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.SFTPConfig.PrivateKey.GetPayload}}{{end}}</textarea>
|
rows="3">{{if .SFTPConfig.PrivateKey.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.SFTPConfig.PrivateKey.GetPayload}}{{end}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group row fsconfig fsconfig-sftpfs">
|
<div class="form-group row fsconfig fsconfig-sftpfs">
|
||||||
<label for="idSFTPPassphrase" class="col-sm-2 col-form-label">Passphrase</label>
|
<label for="idSFTPPassphrase" class="col-sm-2 col-form-label">Key Passphrase</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input type="text" class="form-control" id="idSFTPPassphrase" name="sftp_passphrase" placeholder=""
|
<input type="password" class="form-control" id="idSFTPPassphrase" name="sftp_key_passphrase" placeholder=""
|
||||||
value="{{if .SFTPConfig.Passphrase.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.SFTPConfig.Passphrase.GetPayload}}{{end}}" maxlength="255" aria-describedby="SFTPPassphraseHelpBlock">
|
value="{{if .SFTPConfig.KeyPassphrase.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.SFTPConfig.KeyPassphrase.GetPayload}}{{end}}"
|
||||||
|
aria-describedby="SFTPPassphraseHelpBlock">
|
||||||
<small id="SFTPPassphraseHelpBlock" class="form-text text-muted">
|
<small id="SFTPPassphraseHelpBlock" class="form-text text-muted">
|
||||||
A passphrase is a word or phrase that protects private key files,its used in case of encrypted private keys.
|
Passphrase used to protect your private key, if any
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -441,8 +442,7 @@
|
||||||
<textarea class="form-control" id="idSFTPFingerprints" name="sftp_fingerprints" rows="3"
|
<textarea class="form-control" id="idSFTPFingerprints" name="sftp_fingerprints" rows="3"
|
||||||
aria-describedby="SFTPFingerprintsHelpBlock">{{range .SFTPConfig.Fingerprints}}{{.}} {{end}}</textarea>
|
aria-describedby="SFTPFingerprintsHelpBlock">{{range .SFTPConfig.Fingerprints}}{{.}} {{end}}</textarea>
|
||||||
<small id="SFTPFingerprintsHelpBlock" class="form-text text-muted">
|
<small id="SFTPFingerprintsHelpBlock" class="form-text text-muted">
|
||||||
SHA256 fingerprints to validate when connecting to the external SFTP server, one per line. If
|
SHA256 fingerprints to validate when connecting to the external SFTP server, one per line. If empty any host key will be accepted: this is a security risk!
|
||||||
empty any host key will be accepted: this is a security risk!
|
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (f *Filesystem) SetEmptySecrets() {
|
||||||
f.CryptConfig.Passphrase = kms.NewEmptySecret()
|
f.CryptConfig.Passphrase = kms.NewEmptySecret()
|
||||||
f.SFTPConfig.Password = kms.NewEmptySecret()
|
f.SFTPConfig.Password = kms.NewEmptySecret()
|
||||||
f.SFTPConfig.PrivateKey = kms.NewEmptySecret()
|
f.SFTPConfig.PrivateKey = kms.NewEmptySecret()
|
||||||
f.SFTPConfig.Passphrase = kms.NewEmptySecret()
|
f.SFTPConfig.KeyPassphrase = kms.NewEmptySecret()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEmptySecretsIfNil sets the secrets to empty if nil
|
// SetEmptySecretsIfNil sets the secrets to empty if nil
|
||||||
|
@ -52,8 +52,8 @@ func (f *Filesystem) SetEmptySecretsIfNil() {
|
||||||
if f.SFTPConfig.PrivateKey == nil {
|
if f.SFTPConfig.PrivateKey == nil {
|
||||||
f.SFTPConfig.PrivateKey = kms.NewEmptySecret()
|
f.SFTPConfig.PrivateKey = kms.NewEmptySecret()
|
||||||
}
|
}
|
||||||
if f.SFTPConfig.Passphrase == nil {
|
if f.SFTPConfig.KeyPassphrase == nil {
|
||||||
f.SFTPConfig.Passphrase = kms.NewEmptySecret()
|
f.SFTPConfig.KeyPassphrase = kms.NewEmptySecret()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,15 +76,7 @@ func (f *Filesystem) SetNilSecretsIfEmpty() {
|
||||||
if f.CryptConfig.Passphrase != nil && f.CryptConfig.Passphrase.IsEmpty() {
|
if f.CryptConfig.Passphrase != nil && f.CryptConfig.Passphrase.IsEmpty() {
|
||||||
f.CryptConfig.Passphrase = nil
|
f.CryptConfig.Passphrase = nil
|
||||||
}
|
}
|
||||||
if f.SFTPConfig.Password != nil && f.SFTPConfig.Password.IsEmpty() {
|
f.SFTPConfig.setNilSecretsIfEmpty()
|
||||||
f.SFTPConfig.Password = nil
|
|
||||||
}
|
|
||||||
if f.SFTPConfig.PrivateKey != nil && f.SFTPConfig.PrivateKey.IsEmpty() {
|
|
||||||
f.SFTPConfig.PrivateKey = nil
|
|
||||||
}
|
|
||||||
if f.SFTPConfig.Passphrase != nil && f.SFTPConfig.Passphrase.IsEmpty() {
|
|
||||||
f.SFTPConfig.Passphrase = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEqual returns true if the fs is equal to other
|
// IsEqual returns true if the fs is equal to other
|
||||||
|
@ -198,7 +190,7 @@ func (f *Filesystem) HasRedactedSecret() bool {
|
||||||
if f.SFTPConfig.PrivateKey.IsRedacted() {
|
if f.SFTPConfig.PrivateKey.IsRedacted() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if f.SFTPConfig.Passphrase.IsRedacted() {
|
if f.SFTPConfig.KeyPassphrase.IsRedacted() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,7 +278,7 @@ func (f *Filesystem) GetACopy() Filesystem {
|
||||||
},
|
},
|
||||||
Password: f.SFTPConfig.Password.Clone(),
|
Password: f.SFTPConfig.Password.Clone(),
|
||||||
PrivateKey: f.SFTPConfig.PrivateKey.Clone(),
|
PrivateKey: f.SFTPConfig.PrivateKey.Clone(),
|
||||||
Passphrase: f.SFTPConfig.Passphrase.Clone(),
|
KeyPassphrase: f.SFTPConfig.KeyPassphrase.Clone(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if len(f.SFTPConfig.Fingerprints) > 0 {
|
if len(f.SFTPConfig.Fingerprints) > 0 {
|
||||||
|
|
|
@ -168,7 +168,7 @@ func (v *BaseVirtualFolder) HasRedactedSecret() bool {
|
||||||
if v.FsConfig.SFTPConfig.PrivateKey.IsRedacted() {
|
if v.FsConfig.SFTPConfig.PrivateKey.IsRedacted() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if v.FsConfig.SFTPConfig.Passphrase.IsRedacted() {
|
if v.FsConfig.SFTPConfig.KeyPassphrase.IsRedacted() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,8 @@ type SFTPFsConfig struct {
|
||||||
sdk.BaseSFTPFsConfig
|
sdk.BaseSFTPFsConfig
|
||||||
Password *kms.Secret `json:"password,omitempty"`
|
Password *kms.Secret `json:"password,omitempty"`
|
||||||
PrivateKey *kms.Secret `json:"private_key,omitempty"`
|
PrivateKey *kms.Secret `json:"private_key,omitempty"`
|
||||||
|
KeyPassphrase *kms.Secret `json:"key_passphrase,omitempty"`
|
||||||
forbiddenSelfUsernames []string `json:"-"`
|
forbiddenSelfUsernames []string `json:"-"`
|
||||||
Passphrase *kms.Secret `json:"passphrase,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HideConfidentialData hides confidential data
|
// HideConfidentialData hides confidential data
|
||||||
|
@ -52,8 +52,20 @@ func (c *SFTPFsConfig) HideConfidentialData() {
|
||||||
if c.PrivateKey != nil {
|
if c.PrivateKey != nil {
|
||||||
c.PrivateKey.Hide()
|
c.PrivateKey.Hide()
|
||||||
}
|
}
|
||||||
if c.Passphrase != nil {
|
if c.KeyPassphrase != nil {
|
||||||
c.Passphrase.Hide()
|
c.KeyPassphrase.Hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SFTPFsConfig) setNilSecretsIfEmpty() {
|
||||||
|
if c.Password != nil && c.Password.IsEmpty() {
|
||||||
|
c.Password = nil
|
||||||
|
}
|
||||||
|
if c.PrivateKey != nil && c.PrivateKey.IsEmpty() {
|
||||||
|
c.PrivateKey = nil
|
||||||
|
}
|
||||||
|
if c.KeyPassphrase != nil && c.KeyPassphrase.IsEmpty() {
|
||||||
|
c.KeyPassphrase = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +98,7 @@ func (c *SFTPFsConfig) isEqual(other *SFTPFsConfig) bool {
|
||||||
if !c.Password.IsEqual(other.Password) {
|
if !c.Password.IsEqual(other.Password) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !c.Passphrase.IsEqual(other.Passphrase) {
|
if !c.KeyPassphrase.IsEqual(other.KeyPassphrase) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return c.PrivateKey.IsEqual(other.PrivateKey)
|
return c.PrivateKey.IsEqual(other.PrivateKey)
|
||||||
|
@ -99,8 +111,8 @@ func (c *SFTPFsConfig) setEmptyCredentialsIfNil() {
|
||||||
if c.PrivateKey == nil {
|
if c.PrivateKey == nil {
|
||||||
c.PrivateKey = kms.NewEmptySecret()
|
c.PrivateKey = kms.NewEmptySecret()
|
||||||
}
|
}
|
||||||
if c.Passphrase == nil {
|
if c.KeyPassphrase == nil {
|
||||||
c.Passphrase = kms.NewEmptySecret()
|
c.KeyPassphrase = kms.NewEmptySecret()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +159,12 @@ func (c *SFTPFsConfig) validateCredentials() error {
|
||||||
if !c.PrivateKey.IsEmpty() && !c.PrivateKey.IsValidInput() {
|
if !c.PrivateKey.IsEmpty() && !c.PrivateKey.IsValidInput() {
|
||||||
return errors.New("invalid private key")
|
return errors.New("invalid private key")
|
||||||
}
|
}
|
||||||
|
if c.KeyPassphrase.IsEncrypted() && !c.KeyPassphrase.IsValid() {
|
||||||
|
return errors.New("invalid encrypted private key passphrase")
|
||||||
|
}
|
||||||
|
if !c.KeyPassphrase.IsEmpty() && !c.KeyPassphrase.IsValidInput() {
|
||||||
|
return errors.New("invalid private key passphrase")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,10 +185,10 @@ func (c *SFTPFsConfig) ValidateAndEncryptCredentials(additionalData string) erro
|
||||||
return util.NewValidationError(fmt.Sprintf("could not encrypt SFTP fs private key: %v", err))
|
return util.NewValidationError(fmt.Sprintf("could not encrypt SFTP fs private key: %v", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.Passphrase.IsPlain() {
|
if c.KeyPassphrase.IsPlain() {
|
||||||
c.Passphrase.SetAdditionalData(additionalData)
|
c.KeyPassphrase.SetAdditionalData(additionalData)
|
||||||
if err := c.Passphrase.Encrypt(); err != nil {
|
if err := c.KeyPassphrase.Encrypt(); err != nil {
|
||||||
return err
|
return util.NewValidationError(fmt.Sprintf("could not encrypt SFTP fs private key passphrase: %v", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -211,8 +229,8 @@ func NewSFTPFs(connectionID, mountPath, localTempDir string, forbiddenSelfUserna
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !config.Passphrase.IsEmpty() {
|
if !config.KeyPassphrase.IsEmpty() {
|
||||||
if err := config.Passphrase.TryDecrypt(); err != nil {
|
if err := config.KeyPassphrase.TryDecrypt(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -800,18 +818,15 @@ func (fs *SFTPFs) createConnection() error {
|
||||||
}
|
}
|
||||||
if fs.config.PrivateKey.GetPayload() != "" {
|
if fs.config.PrivateKey.GetPayload() != "" {
|
||||||
var signer ssh.Signer
|
var signer ssh.Signer
|
||||||
if fs.config.Passphrase.GetPayload() != "" {
|
if fs.config.KeyPassphrase.GetPayload() != "" {
|
||||||
signer, err = ssh.ParsePrivateKeyWithPassphrase([]byte(fs.config.PrivateKey.GetPayload()), []byte(fs.config.Passphrase.GetPayload()))
|
signer, err = ssh.ParsePrivateKeyWithPassphrase([]byte(fs.config.PrivateKey.GetPayload()),
|
||||||
if err != nil {
|
[]byte(fs.config.KeyPassphrase.GetPayload()))
|
||||||
fs.err <- err
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
signer, err = ssh.ParsePrivateKey([]byte(fs.config.PrivateKey.GetPayload()))
|
signer, err = ssh.ParsePrivateKey([]byte(fs.config.PrivateKey.GetPayload()))
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.err <- err
|
fs.err <- err
|
||||||
return err
|
return fmt.Errorf("sftpfs: unable to parse the private key: %w", err)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
clientConfig.Auth = append(clientConfig.Auth, ssh.PublicKeys(signer))
|
clientConfig.Auth = append(clientConfig.Auth, ssh.PublicKeys(signer))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue