mirror of
https://github.com/rclone/rclone.git
synced 2025-12-11 22:14:05 +01:00
serve sftp: Add support for public key with auth proxy - fixes #3572
This commit is contained in:
committed by
Nick Craig-Wood
parent
63128834da
commit
f2a789ea98
@@ -108,7 +108,7 @@ type Proxy struct {
|
||||
// cacheEntry is what is stored in the vfsCache
|
||||
type cacheEntry struct {
|
||||
vfs *vfs.VFS // stored VFS
|
||||
pwHash []byte // bcrypt hash of the password
|
||||
pwHash []byte // bcrypt hash of the password/publicKey
|
||||
}
|
||||
|
||||
// New creates a new proxy with the Options passed in
|
||||
@@ -162,12 +162,21 @@ func (p *Proxy) run(in map[string]string) (config configmap.Simple, err error) {
|
||||
}
|
||||
|
||||
// call runs the auth proxy and returns a cacheEntry and an error
|
||||
func (p *Proxy) call(user, pass string, passwordBytes []byte) (value interface{}, err error) {
|
||||
func (p *Proxy) call(user, auth string, isPublicKey bool) (value interface{}, err error) {
|
||||
var config configmap.Simple
|
||||
// Contact the proxy
|
||||
config, err := p.run(map[string]string{
|
||||
"user": user,
|
||||
"pass": pass,
|
||||
})
|
||||
if isPublicKey {
|
||||
config, err = p.run(map[string]string{
|
||||
"user": user,
|
||||
"public_key": auth,
|
||||
})
|
||||
} else {
|
||||
config, err = p.run(map[string]string{
|
||||
"user": user,
|
||||
"pass": auth,
|
||||
})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -208,10 +217,11 @@ func (p *Proxy) call(user, pass string, passwordBytes []byte) (value interface{}
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// The bcrypt cost is a compromise between security and speed. The password is looked up on every
|
||||
// transaction for WebDAV so we store it lightly hashed. An attacker would find it easier to go after
|
||||
// the unencrypted password in memory most likely.
|
||||
pwHash, err := bcrypt.GenerateFromPassword(passwordBytes, bcrypt.MinCost)
|
||||
pwHash, err := bcrypt.GenerateFromPassword([]byte(auth), bcrypt.MinCost)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
@@ -227,17 +237,15 @@ func (p *Proxy) call(user, pass string, passwordBytes []byte) (value interface{}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// Call runs the auth proxy with the given input, returning a *vfs.VFS
|
||||
// and the key used in the VFS cache.
|
||||
func (p *Proxy) Call(user, pass string) (VFS *vfs.VFS, vfsKey string, err error) {
|
||||
var passwordBytes = []byte(pass)
|
||||
|
||||
// Call runs the auth proxy with the username and password/public key provided
|
||||
// returning a *vfs.VFS and the key used in the VFS cache.
|
||||
func (p *Proxy) Call(user, auth string, isPublicKey bool) (VFS *vfs.VFS, vfsKey string, err error) {
|
||||
// Look in the cache first
|
||||
value, ok := p.vfsCache.GetMaybe(user)
|
||||
|
||||
// If not found then call the proxy for a fresh answer
|
||||
if !ok {
|
||||
value, err = p.call(user, pass, passwordBytes)
|
||||
value, err = p.call(user, auth, isPublicKey)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -249,14 +257,14 @@ func (p *Proxy) Call(user, pass string) (VFS *vfs.VFS, vfsKey string, err error)
|
||||
return nil, "", errors.Errorf("proxy: value is not cache entry: %#v", value)
|
||||
}
|
||||
|
||||
// Check the password is correct in the cached entry. This
|
||||
// Check the password / public key is correct in the cached entry. This
|
||||
// prevents an attack where subsequent requests for the same
|
||||
// user don't have their auth checked. It does mean that if
|
||||
// the password is changed, the user will have to wait for
|
||||
// cache expiry (5m) before trying again.
|
||||
err = bcrypt.CompareHashAndPassword(entry.pwHash, passwordBytes)
|
||||
err = bcrypt.CompareHashAndPassword(entry.pwHash, []byte(auth))
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrap(err, "proxy: incorrect password")
|
||||
return nil, "", errors.Wrap(err, "proxy: incorrect password / public key")
|
||||
}
|
||||
|
||||
return entry.vfs, user, nil
|
||||
|
||||
Reference in New Issue
Block a user