sftpfs: cache and reuse parsed private keys
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
fef388d8cb
commit
99f47ca4e7
1 changed files with 40 additions and 38 deletions
|
@ -69,6 +69,17 @@ type SFTPFsConfig struct {
|
||||||
forbiddenSelfUsernames []string `json:"-"`
|
forbiddenSelfUsernames []string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *SFTPFsConfig) getKeySigner() (ssh.Signer, error) {
|
||||||
|
privPayload := c.PrivateKey.GetPayload()
|
||||||
|
if privPayload == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if key := c.KeyPassphrase.GetPayload(); key != "" {
|
||||||
|
return ssh.ParsePrivateKeyWithPassphrase([]byte(privPayload), []byte(key))
|
||||||
|
}
|
||||||
|
return ssh.ParsePrivateKey([]byte(privPayload))
|
||||||
|
}
|
||||||
|
|
||||||
// HideConfidentialData hides confidential data
|
// HideConfidentialData hides confidential data
|
||||||
func (c *SFTPFsConfig) HideConfidentialData() {
|
func (c *SFTPFsConfig) HideConfidentialData() {
|
||||||
if c.Password != nil {
|
if c.Password != nil {
|
||||||
|
@ -185,17 +196,11 @@ func (c *SFTPFsConfig) validate() error {
|
||||||
|
|
||||||
func (c *SFTPFsConfig) validatePrivateKey() error {
|
func (c *SFTPFsConfig) validatePrivateKey() error {
|
||||||
if c.PrivateKey.IsPlain() {
|
if c.PrivateKey.IsPlain() {
|
||||||
var signer ssh.Signer
|
signer, err := c.getKeySigner()
|
||||||
var err error
|
|
||||||
if c.KeyPassphrase.IsPlain() {
|
|
||||||
signer, err = ssh.ParsePrivateKeyWithPassphrase([]byte(c.PrivateKey.GetPayload()),
|
|
||||||
[]byte(c.KeyPassphrase.GetPayload()))
|
|
||||||
} else {
|
|
||||||
signer, err = ssh.ParsePrivateKey([]byte(c.PrivateKey.GetPayload()))
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.NewI18nError(fmt.Errorf("invalid private key: %w", err), util.I18nErrorPrivKeyInvalid)
|
return util.NewI18nError(fmt.Errorf("invalid private key: %w", err), util.I18nErrorPrivKeyInvalid)
|
||||||
}
|
}
|
||||||
|
if signer != nil {
|
||||||
if key, ok := signer.PublicKey().(ssh.CryptoPublicKey); ok {
|
if key, ok := signer.PublicKey().(ssh.CryptoPublicKey); ok {
|
||||||
cryptoKey := key.CryptoPublicKey()
|
cryptoKey := key.CryptoPublicKey()
|
||||||
if rsaKey, ok := cryptoKey.(*rsa.PublicKey); ok {
|
if rsaKey, ok := cryptoKey.(*rsa.PublicKey); ok {
|
||||||
|
@ -208,6 +213,7 @@ func (c *SFTPFsConfig) validatePrivateKey() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,15 +337,19 @@ func NewSFTPFs(connectionID, mountPath, localTempDir string, forbiddenSelfUserna
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
conn, err := sftpConnsCache.Get(&config, connectionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
config.forbiddenSelfUsernames = forbiddenSelfUsernames
|
config.forbiddenSelfUsernames = forbiddenSelfUsernames
|
||||||
sftpFs := &SFTPFs{
|
sftpFs := &SFTPFs{
|
||||||
connectionID: connectionID,
|
connectionID: connectionID,
|
||||||
mountPath: getMountPath(mountPath),
|
mountPath: getMountPath(mountPath),
|
||||||
localTempDir: localTempDir,
|
localTempDir: localTempDir,
|
||||||
config: &config,
|
config: &config,
|
||||||
conn: sftpConnsCache.Get(&config, connectionID),
|
conn: conn,
|
||||||
}
|
}
|
||||||
err := sftpFs.createConnection()
|
err = sftpFs.createConnection()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sftpFs.Close() //nolint:errcheck
|
sftpFs.Close() //nolint:errcheck
|
||||||
}
|
}
|
||||||
|
@ -910,6 +920,7 @@ type sftpConnection struct {
|
||||||
isConnected bool
|
isConnected bool
|
||||||
sessions map[string]bool
|
sessions map[string]bool
|
||||||
lastActivity time.Time
|
lastActivity time.Time
|
||||||
|
signer ssh.Signer
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSFTPConnection(config *SFTPFsConfig, sessionID string) *sftpConnection {
|
func newSFTPConnection(config *SFTPFsConfig, sessionID string) *sftpConnection {
|
||||||
|
@ -919,6 +930,7 @@ func newSFTPConnection(config *SFTPFsConfig, sessionID string) *sftpConnection {
|
||||||
isConnected: false,
|
isConnected: false,
|
||||||
sessions: map[string]bool{},
|
sessions: map[string]bool{},
|
||||||
lastActivity: time.Now().UTC(),
|
lastActivity: time.Now().UTC(),
|
||||||
|
signer: nil,
|
||||||
}
|
}
|
||||||
c.sessions[sessionID] = true
|
c.sessions[sessionID] = true
|
||||||
return c
|
return c
|
||||||
|
@ -931,17 +943,6 @@ func (c *sftpConnection) OpenConnection() error {
|
||||||
return c.openConnNoLock()
|
return c.openConnNoLock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *sftpConnection) getKeySigner() (ssh.Signer, error) {
|
|
||||||
privPayload := c.config.PrivateKey.GetPayload()
|
|
||||||
if privPayload == "" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if key := c.config.KeyPassphrase.GetPayload(); key != "" {
|
|
||||||
return ssh.ParsePrivateKeyWithPassphrase([]byte(privPayload), []byte(key))
|
|
||||||
}
|
|
||||||
return ssh.ParsePrivateKey([]byte(privPayload))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *sftpConnection) openConnNoLock() error {
|
func (c *sftpConnection) openConnNoLock() error {
|
||||||
if c.isConnected {
|
if c.isConnected {
|
||||||
logger.Debug(c.logSender, "", "reusing connection")
|
logger.Debug(c.logSender, "", "reusing connection")
|
||||||
|
@ -979,12 +980,8 @@ func (c *sftpConnection) openConnNoLock() error {
|
||||||
Timeout: 15 * time.Second,
|
Timeout: 15 * time.Second,
|
||||||
ClientVersion: fmt.Sprintf("SSH-2.0-%s", version.GetServerVersion("_", false)),
|
ClientVersion: fmt.Sprintf("SSH-2.0-%s", version.GetServerVersion("_", false)),
|
||||||
}
|
}
|
||||||
signer, err := c.getKeySigner()
|
if c.signer != nil {
|
||||||
if err != nil {
|
clientConfig.Auth = append(clientConfig.Auth, ssh.PublicKeys(c.signer))
|
||||||
return fmt.Errorf("sftpfs: unable to parse the private key: %w", err)
|
|
||||||
}
|
|
||||||
if signer != nil {
|
|
||||||
clientConfig.Auth = append(clientConfig.Auth, ssh.PublicKeys(signer))
|
|
||||||
}
|
}
|
||||||
if pwd := c.config.Password.GetPayload(); pwd != "" {
|
if pwd := c.config.Password.GetPayload(); pwd != "" {
|
||||||
clientConfig.Auth = append(clientConfig.Auth, ssh.Password(pwd))
|
clientConfig.Auth = append(clientConfig.Auth, ssh.Password(pwd))
|
||||||
|
@ -1156,7 +1153,7 @@ func newSFTPConnectionCache() *sftpConnectionsCache {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *sftpConnectionsCache) Get(config *SFTPFsConfig, sessionID string) *sftpConnection {
|
func (c *sftpConnectionsCache) Get(config *SFTPFsConfig, sessionID string) (*sftpConnection, error) {
|
||||||
partition := 0
|
partition := 0
|
||||||
key := config.getUniqueID(partition)
|
key := config.getUniqueID(partition)
|
||||||
|
|
||||||
|
@ -1172,7 +1169,7 @@ func (c *sftpConnectionsCache) Get(config *SFTPFsConfig, sessionID string) *sftp
|
||||||
"reusing connection for session ID %q, key: %d, active sessions %d, active connections: %d",
|
"reusing connection for session ID %q, key: %d, active sessions %d, active connections: %d",
|
||||||
sessionID, key, activeSessions+1, len(c.items))
|
sessionID, key, activeSessions+1, len(c.items))
|
||||||
val.AddSession(sessionID)
|
val.AddSession(sessionID)
|
||||||
return val
|
return val, nil
|
||||||
}
|
}
|
||||||
partition++
|
partition++
|
||||||
oldKey = key
|
oldKey = key
|
||||||
|
@ -1182,11 +1179,16 @@ func (c *sftpConnectionsCache) Get(config *SFTPFsConfig, sessionID string) *sftp
|
||||||
partition, activeSessions, oldKey, key)
|
partition, activeSessions, oldKey, key)
|
||||||
} else {
|
} else {
|
||||||
conn := newSFTPConnection(config, sessionID)
|
conn := newSFTPConnection(config, sessionID)
|
||||||
|
signer, err := config.getKeySigner()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("sftpfs: unable to parse the private key: %w", err)
|
||||||
|
}
|
||||||
|
conn.signer = signer
|
||||||
c.items[key] = conn
|
c.items[key] = conn
|
||||||
logger.Debug(logSenderSFTPCache, "",
|
logger.Debug(logSenderSFTPCache, "",
|
||||||
"adding new connection for session ID %q, partition: %d, key: %d, active connections: %d",
|
"adding new connection for session ID %q, partition: %d, key: %d, active connections: %d",
|
||||||
sessionID, partition, key, len(c.items))
|
sessionID, partition, key, len(c.items))
|
||||||
return conn
|
return conn, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue