Skip to content

Commit

Permalink
sftp - support for private key authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
balazsgrill committed Oct 26, 2024
1 parent 7f4e221 commit be7bd03
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 29 deletions.
11 changes: 8 additions & 3 deletions bindings/bindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const UseCFAPI bool = true

type BindingConfig interface {
Validate() error
ToFileSystem() (afero.Fs, error)
ToFileSystem(zerolog.Logger) (afero.Fs, error)
}

const (
Expand Down Expand Up @@ -99,8 +99,13 @@ func ReadConfigFromRegistry(key registry.Key, config any) error {
if os.IsNotExist(err) {
continue
}
if err != nil {
return err
if err == registry.ErrUnexpectedType {
// attempt to read as multi-string
values, _, err := key.GetStringsValue(tag)
if err != nil {
return err
}
value = strings.Join(values, "\n")
}
fieldvalue.SetString(value)
case reflect.Bool:
Expand Down
3 changes: 2 additions & 1 deletion bindings/proxy/client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"net/http"

"github.com/rs/zerolog"
"github.com/spf13/afero"
)

Expand Down Expand Up @@ -37,7 +38,7 @@ func (a *authenticator) RoundTrip(r *http.Request) (*http.Response, error) {
return a.delegate.RoundTrip(r)
}

func (c *Config) ToFileSystem() (afero.Fs, error) {
func (c *Config) ToFileSystem(logger zerolog.Logger) (afero.Fs, error) {
httpclient := &http.Client{}
httpclient.Transport = &authenticator{
Config: c,
Expand Down
3 changes: 2 additions & 1 deletion bindings/s3/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/balazsgrill/potatodrive/bindings/utils"
s3 "github.com/fclairamb/afero-s3"
"github.com/rs/zerolog"
"github.com/spf13/afero"
)

Expand Down Expand Up @@ -39,7 +40,7 @@ func (c *Config) Validate() error {
return nil
}

func (c *Config) ToFileSystem() (afero.Fs, error) {
func (c *Config) ToFileSystem(logger zerolog.Logger) (afero.Fs, error) {
sess, err := session.NewSession(&aws.Config{
Region: aws.String(c.Region),
Endpoint: aws.String(c.Endpoint),
Expand Down
64 changes: 51 additions & 13 deletions bindings/sftp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ import (

"github.com/balazsgrill/potatodrive/bindings/utils"
sftpclient "github.com/pkg/sftp"
"github.com/rs/zerolog"
"github.com/spf13/afero"
"github.com/spf13/afero/sftpfs"
"golang.org/x/crypto/ssh"
)

type Config struct {
User string `flag:"user,User name" reg:"User"`
Password string `flag:"password,Password" reg:"Password"`
Host string `flag:"host,Host:port" reg:"Host"`
Basepath string `flag:"basepath,Base path on remote server" reg:"Basepath"`
User string `flag:"user,User name" reg:"User"`
Password string `flag:"password,Password" reg:"Password"`
PrivateKey string `flag:"privatekey,PrivateKey" reg:"PrivateKey"`
Host string `flag:"host,Host:port" reg:"Host"`
Basepath string `flag:"basepath,Base path on remote server" reg:"Basepath"`
}

func (c *Config) Validate() error {
Expand All @@ -24,18 +26,50 @@ func (c *Config) Validate() error {
if c.User == "" {
return errors.New("user is mandatory")
}
if c.Password == "" {
return errors.New("password is mandatory")
if c.Password == "" && c.PrivateKey == "" {
return errors.New("password or private key is mandatory")
}
return nil
}

func (c *Config) Connect(onDisconnect func(error)) (afero.Fs, error) {
func (c *Config) authFromKey() (ssh.AuthMethod, error) {
key, err := ssh.ParseRawPrivateKey([]byte(c.PrivateKey))
if err != nil {
return nil, err
}
signer, err := ssh.NewSignerFromKey(key)
if err != nil {
return nil, err
}
return ssh.PublicKeys(signer), nil
}

type configWithLogger struct {
Config
Logger zerolog.Logger
}

func (c *configWithLogger) Connect(onDisconnect func(error)) (afero.Fs, error) {
var authmetods []ssh.AuthMethod
if c.Password != "" {
authmetods = append(authmetods, ssh.Password(c.Password))
}
if c.PrivateKey != "" {
auth, err := c.authFromKey()
if err != nil {
c.Logger.Error().Err(err).Msg("SSH key auth failed")
} else {
authmetods = append(authmetods, auth)
}
}

if len(authmetods) == 0 {
return nil, errors.New("no valid authentication method is defined")
}

config := ssh.ClientConfig{
User: c.User,
Auth: []ssh.AuthMethod{
ssh.Password(c.Password),
},
User: c.User,
Auth: authmetods,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
conn, err := ssh.Dial("tcp", c.Host, &config)
Expand All @@ -58,10 +92,14 @@ func (c *Config) Connect(onDisconnect func(error)) (afero.Fs, error) {
return sftpfs.New(client), nil
}

func (c *Config) ToFileSystem() (afero.Fs, error) {
func (c *Config) ToFileSystem(logger zerolog.Logger) (afero.Fs, error) {
var remote afero.Fs
cwithlogger := &configWithLogger{
Config: *c,
Logger: logger,
}
remote = &utils.ConnectingFs{
Connect: c.Connect,
Connect: cwithlogger.Connect,
}
if c.Basepath != "" {
remote = utils.NewBasePathFs(remote, c.Basepath)
Expand Down
16 changes: 10 additions & 6 deletions cmd/main/mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,30 @@ func initLogger() (string, zerolog.Logger, io.Closer) {
func startInstance(parentkey registry.Key, keyname string, context bindings.InstanceContext) (io.Closer, error) {
key, err := registry.OpenKey(parentkey, keyname, registry.QUERY_VALUE)
if err != nil {
context.Logger.Printf("Open key: %v", err)
context.Logger.Error().Msgf("Open key: %v", err)
return nil, err
}

var basec bindings.BaseConfig
err = bindings.ReadConfigFromRegistry(key, &basec)
if err != nil {
context.Logger.Printf("Get base config: %v", err)
context.Logger.Error().Msgf("Get base config: %v", err)
return nil, err
}
config := bindings.CreateConfigByType(basec.Type)
bindings.ReadConfigFromRegistry(key, config)
err = bindings.ReadConfigFromRegistry(key, config)
if err != nil {
context.Logger.Error().Msgf("Read config: %v", err)
return nil, err
}
err = config.Validate()
if err != nil {
context.Logger.Printf("Validate config: %v", err)
context.Logger.Error().Msgf("Validate config: %v", err)
return nil, err
}
fs, err := config.ToFileSystem()
fs, err := config.ToFileSystem(context.Logger)
if err != nil {
context.Logger.Printf("Create file system: %v", err)
context.Logger.Error().Msgf("Create file system: %v", err)
return nil, err
}

Expand Down
9 changes: 5 additions & 4 deletions test/minio/minio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ func setup(t *testing.T) *testInstance {
}

func (instance *testInstance) start(t *testing.T) {
instancecontext := bindings.InstanceContext{
Logger: zerolog.New(zerolog.NewTestWriter(t)),
}
config := s3.Config{
Endpoint: "localhost:9000",
Region: "us-east-1", // default region
Expand All @@ -83,13 +86,11 @@ func (instance *testInstance) start(t *testing.T) {
KeySecret: MINIO_SECRET_KEY,
UseSSL: false,
}
fs, err := config.ToFileSystem()
fs, err := config.ToFileSystem(instancecontext.Logger)
if err != nil {
t.Fatal(err)
}
instancecontext := bindings.InstanceContext{
Logger: zerolog.New(zerolog.NewTestWriter(t)),
}

uid := uuid.NewMD5(uuid.UUID{}, []byte("test"))
gid := core.BytesToGuid(uid[:])
err = filesystem.RegisterRootPathSimple(*gid, instance.fsdir)
Expand Down
4 changes: 3 additions & 1 deletion test/proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import (

"github.com/balazsgrill/potatodrive/bindings/proxy/client"
"github.com/balazsgrill/potatodrive/bindings/proxy/server"
"github.com/rs/zerolog"
"github.com/spf13/afero"
)

func TestProxyConnection(t *testing.T) {
logger := zerolog.New(zerolog.NewTestWriter(t))
fs := afero.NewMemMapFs()
mux := http.NewServeMux()
mux.HandleFunc("/", server.Handler(fs))
Expand All @@ -25,7 +27,7 @@ func TestProxyConnection(t *testing.T) {
KeyId: "",
KeySecret: "",
}
fs2, err := clientconifg.ToFileSystem()
fs2, err := clientconifg.ToFileSystem(logger)
if err != nil {
t.Fatal(err)
}
Expand Down

0 comments on commit be7bd03

Please sign in to comment.