-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move SSH related code to client package
- Loading branch information
1 parent
177004b
commit 6dbdc5a
Showing
7 changed files
with
233 additions
and
183 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package client | ||
|
||
import ( | ||
"encoding/base64" | ||
"fmt" | ||
|
||
"github.com/arunvelsriram/sftp-exporter/pkg/constants/viperkeys" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/viper" | ||
"golang.org/x/crypto/ssh" | ||
) | ||
|
||
func parsePrivateKey(key, keyPassphrase []byte) (parsedKey ssh.Signer, err error) { | ||
if len(keyPassphrase) > 0 { | ||
log.Debug("key has passphrase") | ||
parsedKey, err = ssh.ParsePrivateKeyWithPassphrase(key, keyPassphrase) | ||
if err != nil { | ||
log.Error("failed to parse key with passphrase") | ||
return nil, err | ||
} | ||
return parsedKey, err | ||
} | ||
|
||
log.Debug("key has no passphrase") | ||
parsedKey, err = ssh.ParsePrivateKey(key) | ||
if err != nil { | ||
log.Error("failed to parse key") | ||
return nil, err | ||
} | ||
return parsedKey, err | ||
} | ||
|
||
func sshAuthMethods() ([]ssh.AuthMethod, error) { | ||
password := viper.GetString(viperkeys.SFTPPassword) | ||
encodedKey := viper.GetString(viperkeys.SFTPKey) | ||
key, err := base64.StdEncoding.DecodeString(encodedKey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
keyPassphrase := []byte(viper.GetString(viperkeys.SFTPKeyPassphrase)) | ||
|
||
if len(password) > 0 && len(key) > 0 { | ||
log.Debug("key and password are provided") | ||
parsedKey, err := parsePrivateKey(key, keyPassphrase) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return []ssh.AuthMethod{ | ||
ssh.PublicKeys(parsedKey), | ||
ssh.Password(password), | ||
}, nil | ||
|
||
} else if len(password) > 0 { | ||
log.Debug("password is provided") | ||
return []ssh.AuthMethod{ | ||
ssh.Password(password), | ||
}, nil | ||
} else if len(key) > 0 { | ||
log.Debug("key is provided") | ||
parsedKey, err := parsePrivateKey(key, keyPassphrase) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return []ssh.AuthMethod{ | ||
ssh.PublicKeys(parsedKey), | ||
}, nil | ||
} | ||
|
||
log.Debug("both password and key are not provided") | ||
return nil, fmt.Errorf("failed to determine the SSH authentication methods to use") | ||
} | ||
|
||
func NewSSHClient() (*ssh.Client, error) { | ||
addr := fmt.Sprintf("%s:%d", viper.GetString(viperkeys.SFTPHost), viper.GetInt(viperkeys.SFTPPort)) | ||
auth, err := sshAuthMethods() | ||
if err != nil { | ||
return nil, err | ||
} | ||
clientConfig := &ssh.ClientConfig{ | ||
User: viper.GetString(viperkeys.SFTPUser), | ||
Auth: auth, | ||
HostKeyCallback: ssh.InsecureIgnoreHostKey(), | ||
} | ||
return ssh.Dial("tcp", addr, clientConfig) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package client | ||
|
||
import ( | ||
"encoding/base64" | ||
"fmt" | ||
"reflect" | ||
"runtime" | ||
"testing" | ||
|
||
"github.com/arunvelsriram/sftp-exporter/pkg/constants/viperkeys" | ||
"github.com/arunvelsriram/sftp-exporter/pkg/internal/mocks" | ||
"github.com/spf13/viper" | ||
"github.com/stretchr/testify/assert" | ||
"golang.org/x/crypto/ssh" | ||
) | ||
|
||
func TestSSHAuthMethods(t *testing.T) { | ||
tests := []struct { | ||
desc string | ||
password string | ||
key string | ||
keyPassphrase string | ||
authMethods []ssh.AuthMethod | ||
err error | ||
}{ | ||
{ | ||
desc: "should return error when key with invalid encoding is provided", | ||
password: "", | ||
key: "key-invalid-encoded", | ||
keyPassphrase: "", | ||
authMethods: nil, | ||
err: base64.CorruptInputError(3), | ||
}, | ||
{ | ||
desc: "should return auth methods when password and key are given", | ||
password: "password", | ||
key: mocks.EncodedSSHKeyWithoutPassphrase(), | ||
keyPassphrase: "", | ||
authMethods: []ssh.AuthMethod{ssh.PublicKeys(), ssh.Password("password")}, | ||
err: nil, | ||
}, | ||
{ | ||
desc: "should get auth method when password is given", | ||
password: "password", | ||
key: "", | ||
keyPassphrase: "", | ||
authMethods: []ssh.AuthMethod{ssh.Password("password")}, | ||
err: nil, | ||
}, | ||
{ | ||
desc: "should return auth method when key is given", | ||
password: "", | ||
key: mocks.EncodedSSHKeyWithoutPassphrase(), | ||
keyPassphrase: "", | ||
authMethods: []ssh.AuthMethod{ssh.PublicKeys()}, | ||
err: nil, | ||
}, | ||
{ | ||
desc: "should return error when both password and key are empty", | ||
password: "", | ||
key: "", | ||
keyPassphrase: "", | ||
authMethods: nil, | ||
err: fmt.Errorf("failed to determine the SSH authentication methods to use"), | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(test.desc, func(t *testing.T) { | ||
viper.Set(viperkeys.SFTPPassword, test.password) | ||
viper.Set(viperkeys.SFTPKey, test.key) | ||
viper.Set(viperkeys.SFTPKeyPassphrase, test.keyPassphrase) | ||
|
||
authMethods, err := sshAuthMethods() | ||
|
||
assert.Len(t, authMethods, len(test.authMethods)) | ||
for i, expectedAuthMethod := range test.authMethods { | ||
expected := runtime.FuncForPC(reflect.ValueOf(expectedAuthMethod).Pointer()).Name() | ||
actual := runtime.FuncForPC(reflect.ValueOf(authMethods[i]).Pointer()).Name() | ||
assert.Equal(t, expected, actual) | ||
} | ||
assert.Equal(t, test.err, err) | ||
}) | ||
} | ||
} | ||
|
||
func TestParsePrivateKey(t *testing.T) { | ||
tests := []struct { | ||
desc string | ||
key []byte | ||
keyPassphrase []byte | ||
err error | ||
}{ | ||
{ | ||
desc: "should parse key", | ||
key: mocks.SSHKeyWithoutPassphrase(), | ||
keyPassphrase: []byte{}, | ||
err: nil, | ||
}, | ||
{ | ||
desc: "should parse encrypted key", | ||
key: mocks.SSHKeyWithPassphrase(), | ||
keyPassphrase: []byte(mocks.KeyPassphrase), | ||
err: nil, | ||
}, | ||
{ | ||
desc: "should return when invalid key is given", | ||
key: []byte("invalid-key"), | ||
keyPassphrase: []byte(""), | ||
err: fmt.Errorf("ssh: no key found"), | ||
}, | ||
{ | ||
desc: "should return error when wrong passphrase is given", | ||
key: mocks.SSHKeyWithPassphrase(), | ||
keyPassphrase: []byte("invalid-passphrase"), | ||
err: fmt.Errorf("x509: decryption password incorrect"), | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(test.desc, func(t *testing.T) { | ||
_, err := parsePrivateKey(test.key, test.keyPassphrase) | ||
|
||
assert.Equal(t, test.err, err) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.