s3: fix v2 auth when using force_path_style = false
The V2 auth was failing with AWS and KS3 when used with force_path_style = false (which is the default for both providers now). The V2 Auth needed the bucket prepended onto the string that gets signed. Note that endpoint must be set when using v2 auth with AWS. The code warns about this. This was worked out by observing the behaviour of s3cmd.
This commit is contained in:
parent
a2fa1370c5
commit
c85438d34b
2 changed files with 25 additions and 4 deletions
|
@ -1523,7 +1523,7 @@ func s3Connection(opt *Options) (*s3.S3, *session.Session, error) {
|
||||||
if req.Config.Credentials == credentials.AnonymousCredentials {
|
if req.Config.Credentials == credentials.AnonymousCredentials {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sign(v.AccessKeyID, v.SecretAccessKey, req.HTTPRequest)
|
v2sign(opt, req.HTTPRequest)
|
||||||
}
|
}
|
||||||
c.Handlers.Sign.Clear()
|
c.Handlers.Sign.Clear()
|
||||||
c.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
c.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
||||||
|
|
|
@ -9,7 +9,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rclone/rclone/fs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// URL parameters that need to be added to the signature
|
// URL parameters that need to be added to the signature
|
||||||
|
@ -35,10 +38,13 @@ var s3ParamsToSign = map[string]struct{}{
|
||||||
"response-content-encoding": {},
|
"response-content-encoding": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Warn once about empty endpoint
|
||||||
|
var warnEmptyEndpointOnce sync.Once
|
||||||
|
|
||||||
// sign signs requests using v2 auth
|
// sign signs requests using v2 auth
|
||||||
//
|
//
|
||||||
// Cobbled together from goamz and aws-sdk-go
|
// Cobbled together from goamz and aws-sdk-go
|
||||||
func sign(AccessKey, SecretKey string, req *http.Request) {
|
func v2sign(opt *Options, req *http.Request) {
|
||||||
// Set date
|
// Set date
|
||||||
date := time.Now().UTC().Format(time.RFC1123)
|
date := time.Now().UTC().Format(time.RFC1123)
|
||||||
req.Header.Set("Date", date)
|
req.Header.Set("Date", date)
|
||||||
|
@ -48,6 +54,21 @@ func sign(AccessKey, SecretKey string, req *http.Request) {
|
||||||
if uri == "" {
|
if uri == "" {
|
||||||
uri = "/"
|
uri = "/"
|
||||||
}
|
}
|
||||||
|
// If not using path style then need to stick the bucket on
|
||||||
|
// the start of the requests if doing a bucket based query
|
||||||
|
if !opt.ForcePathStyle {
|
||||||
|
if opt.Endpoint == "" {
|
||||||
|
warnEmptyEndpointOnce.Do(func() {
|
||||||
|
fs.Logf(nil, "If using v2 auth with AWS and force_path_style=false, endpoint must be set in the config")
|
||||||
|
})
|
||||||
|
} else if req.URL.Host != opt.Endpoint {
|
||||||
|
// read the bucket off the start of the hostname
|
||||||
|
i := strings.IndexRune(req.URL.Host, '.')
|
||||||
|
if i >= 0 {
|
||||||
|
uri = "/" + req.URL.Host[:i] + uri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Look through headers of interest
|
// Look through headers of interest
|
||||||
var md5 string
|
var md5 string
|
||||||
|
@ -96,11 +117,11 @@ func sign(AccessKey, SecretKey string, req *http.Request) {
|
||||||
|
|
||||||
// Make signature
|
// Make signature
|
||||||
payload := req.Method + "\n" + md5 + "\n" + contentType + "\n" + date + "\n" + joinedHeadersToSign + uri
|
payload := req.Method + "\n" + md5 + "\n" + contentType + "\n" + date + "\n" + joinedHeadersToSign + uri
|
||||||
hash := hmac.New(sha1.New, []byte(SecretKey))
|
hash := hmac.New(sha1.New, []byte(opt.SecretAccessKey))
|
||||||
_, _ = hash.Write([]byte(payload))
|
_, _ = hash.Write([]byte(payload))
|
||||||
signature := make([]byte, base64.StdEncoding.EncodedLen(hash.Size()))
|
signature := make([]byte, base64.StdEncoding.EncodedLen(hash.Size()))
|
||||||
base64.StdEncoding.Encode(signature, hash.Sum(nil))
|
base64.StdEncoding.Encode(signature, hash.Sum(nil))
|
||||||
|
|
||||||
// Set signature in request
|
// Set signature in request
|
||||||
req.Header.Set("Authorization", "AWS "+AccessKey+":"+string(signature))
|
req.Header.Set("Authorization", "AWS "+opt.AccessKeyID+":"+string(signature))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue