diff --git a/backend/s3/s3.go b/backend/s3/s3.go index d3694cc2c..4cbf6fa0f 100644 --- a/backend/s3/s3.go +++ b/backend/s3/s3.go @@ -1523,7 +1523,7 @@ func s3Connection(opt *Options) (*s3.S3, *session.Session, error) { if req.Config.Credentials == credentials.AnonymousCredentials { return } - sign(v.AccessKeyID, v.SecretAccessKey, req.HTTPRequest) + v2sign(opt, req.HTTPRequest) } c.Handlers.Sign.Clear() c.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler) diff --git a/backend/s3/v2sign.go b/backend/s3/v2sign.go index 2c22378e3..d6e638431 100644 --- a/backend/s3/v2sign.go +++ b/backend/s3/v2sign.go @@ -9,7 +9,10 @@ import ( "net/http" "sort" "strings" + "sync" "time" + + "github.com/rclone/rclone/fs" ) // URL parameters that need to be added to the signature @@ -35,10 +38,13 @@ var s3ParamsToSign = map[string]struct{}{ "response-content-encoding": {}, } +// Warn once about empty endpoint +var warnEmptyEndpointOnce sync.Once + // sign signs requests using v2 auth // // 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 date := time.Now().UTC().Format(time.RFC1123) req.Header.Set("Date", date) @@ -48,6 +54,21 @@ func sign(AccessKey, SecretKey string, req *http.Request) { if 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 var md5 string @@ -96,11 +117,11 @@ func sign(AccessKey, SecretKey string, req *http.Request) { // Make signature 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)) signature := make([]byte, base64.StdEncoding.EncodedLen(hash.Size())) base64.StdEncoding.Encode(signature, hash.Sum(nil)) // Set signature in request - req.Header.Set("Authorization", "AWS "+AccessKey+":"+string(signature)) + req.Header.Set("Authorization", "AWS "+opt.AccessKeyID+":"+string(signature)) }