github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/backend/s3/v2sign.go (about) 1 // v2 signing 2 3 package s3 4 5 import ( 6 "crypto/hmac" 7 "crypto/sha1" 8 "encoding/base64" 9 "net/http" 10 "sort" 11 "strings" 12 "time" 13 ) 14 15 // URL parameters that need to be added to the signature 16 var s3ParamsToSign = map[string]struct{}{ 17 "acl": {}, 18 "location": {}, 19 "logging": {}, 20 "notification": {}, 21 "partNumber": {}, 22 "policy": {}, 23 "requestPayment": {}, 24 "torrent": {}, 25 "uploadId": {}, 26 "uploads": {}, 27 "versionId": {}, 28 "versioning": {}, 29 "versions": {}, 30 "response-content-type": {}, 31 "response-content-language": {}, 32 "response-expires": {}, 33 "response-cache-control": {}, 34 "response-content-disposition": {}, 35 "response-content-encoding": {}, 36 } 37 38 // sign signs requests using v2 auth 39 // 40 // Cobbled together from goamz and aws-sdk-go 41 func sign(AccessKey, SecretKey string, req *http.Request) { 42 // Set date 43 date := time.Now().UTC().Format(time.RFC1123) 44 req.Header.Set("Date", date) 45 46 // Sort out URI 47 uri := req.URL.EscapedPath() 48 if uri == "" { 49 uri = "/" 50 } 51 52 // Look through headers of interest 53 var md5 string 54 var contentType string 55 var headersToSign []string 56 for k, v := range req.Header { 57 k = strings.ToLower(k) 58 switch k { 59 case "content-md5": 60 md5 = v[0] 61 case "content-type": 62 contentType = v[0] 63 default: 64 if strings.HasPrefix(k, "x-amz-") { 65 vall := strings.Join(v, ",") 66 headersToSign = append(headersToSign, k+":"+vall) 67 } 68 } 69 } 70 // Make headers of interest into canonical string 71 var joinedHeadersToSign string 72 if len(headersToSign) > 0 { 73 sort.StringSlice(headersToSign).Sort() 74 joinedHeadersToSign = strings.Join(headersToSign, "\n") + "\n" 75 } 76 77 // Look for query parameters which need to be added to the signature 78 params := req.URL.Query() 79 var queriesToSign []string 80 for k, vs := range params { 81 if _, ok := s3ParamsToSign[k]; ok { 82 for _, v := range vs { 83 if v == "" { 84 queriesToSign = append(queriesToSign, k) 85 } else { 86 queriesToSign = append(queriesToSign, k+"="+v) 87 } 88 } 89 } 90 } 91 // Add query parameters to URI 92 if len(queriesToSign) > 0 { 93 sort.StringSlice(queriesToSign).Sort() 94 uri += "?" + strings.Join(queriesToSign, "&") 95 } 96 97 // Make signature 98 payload := req.Method + "\n" + md5 + "\n" + contentType + "\n" + date + "\n" + joinedHeadersToSign + uri 99 hash := hmac.New(sha1.New, []byte(SecretKey)) 100 _, _ = hash.Write([]byte(payload)) 101 signature := make([]byte, base64.StdEncoding.EncodedLen(hash.Size())) 102 base64.StdEncoding.Encode(signature, hash.Sum(nil)) 103 104 // Set signature in request 105 req.Header.Set("Authorization", "AWS "+AccessKey+":"+string(signature)) 106 }