// queryV4Signprepares and runs the req request, signed with aws v4 signatures. // If resp is not nil, the XML data contained in the response // body will be unmarshalled on it. func (s3 *S3) queryV4Sign(req *request, resp interface{}) error { if req.headers == nil { req.headers = map[string][]string{} } err := s3.setBaseURL(req) if err != nil { return err } hreq, err := s3.setupHttpRequest(req) if err != nil { return err } // req.Host must be set for V4 signature calculation hreq.Host = hreq.URL.Host signer := aws.NewV4Signer(s3.Auth, "s3", s3.Region) signer.IncludeXAmzContentSha256 = true signer.Sign(hreq) _, err = s3.doHttpRequest(hreq, resp) return err }
func ExampleV4Signer() { // Get auth from env vars auth, err := aws.EnvAuth() if err != nil { fmt.Println(err) } // Create a signer with the auth, name of the service, and aws region signer := aws.NewV4Signer(auth, "dynamodb", aws.USEast) // Create a request req, err := http.NewRequest("POST", aws.USEast.DynamoDBEndpoint, strings.NewReader("sample_request")) if err != nil { fmt.Println(err) } // Date or x-amz-date header is required to sign a request req.Header.Add("Date", time.Now().UTC().Format(http.TimeFormat)) // Sign the request signer.Sign(req) // Issue signed request http.DefaultClient.Do(req) }
func (s *V4SignerSuite) TestCases(c *check.C) { signer := aws.NewV4Signer(s.auth, "host", s.region) for _, testCase := range s.cases { req, err := http.NewRequest(testCase.request.method, "http://"+testCase.request.host+testCase.request.url, strings.NewReader(testCase.request.body)) c.Assert(err, check.IsNil, check.Commentf("Testcase: %s", testCase.label)) for _, v := range testCase.request.headers { h := strings.SplitN(v, ":", 2) req.Header.Add(h[0], h[1]) } req.Header.Set("host", req.Host) t := signer.RequestTime(req) canonicalRequest := signer.CanonicalRequest(req) c.Check(canonicalRequest, check.Equals, testCase.canonicalRequest, check.Commentf("Testcase: %s", testCase.label)) stringToSign := signer.StringToSign(t, canonicalRequest) c.Check(stringToSign, check.Equals, testCase.stringToSign, check.Commentf("Testcase: %s", testCase.label)) signature := signer.Signature(t, stringToSign) c.Check(signature, check.Equals, testCase.signature, check.Commentf("Testcase: %s", testCase.label)) authorization := signer.Authorization(req.Header, t, signature) c.Check(authorization, check.Equals, testCase.authorization, check.Commentf("Testcase: %s", testCase.label)) signer.Sign(req) c.Check(req.Header.Get("Authorization"), check.Equals, testCase.authorization, check.Commentf("Testcase: %s", testCase.label)) } }
func (s *SQS) query(queueUrl string, params map[string]string, resp interface{}) (err error) { var url_ *url.URL if queueUrl != "" && len(queueUrl) > len(s.Region.SQSEndpoint) { url_, err = url.Parse(queueUrl) } else { url_, err = url.Parse(s.Region.SQSEndpoint) } if err != nil { return err } params["Version"] = "2012-11-05" hreq, err := http.NewRequest("POST", url_.String(), strings.NewReader(multimap(params).Encode())) if err != nil { return err } // respect the environmnet's proxy settings if prox_url, _ := http.ProxyFromEnvironment(hreq); prox_url != nil { hreq.URL = prox_url } hreq.Header.Set("Content-Type", "application/x-www-form-urlencoded") hreq.Header.Set("X-Amz-Date", time.Now().UTC().Format(aws.ISO8601BasicFormat)) if s.Auth.Token() != "" { hreq.Header.Set("X-Amz-Security-Token", s.Auth.Token()) } signer := aws.NewV4Signer(s.Auth, "sqs", s.Region) signer.Sign(hreq) r, err := http.DefaultClient.Do(hreq) if err != nil { return err } defer r.Body.Close() if debug { dump, _ := httputil.DumpResponse(r, true) log.Printf("DUMP:\n", string(dump)) } if r.StatusCode != 200 { return buildError(r) } err = xml.NewDecoder(r.Body).Decode(resp) io.Copy(ioutil.Discard, r.Body) return err }
func (rds *RDS) DownloadCompleteDBLogFile(id, filename string) (io.ReadCloser, error) { url := fmt.Sprintf( "%s/v13/downloadCompleteLogFile/%s/%s", rds.Region.RDSEndpoint.Endpoint, id, filename, ) hreq, err := http.NewRequest("GET", url, nil) if err != nil { if debug { log.Printf("Error http.NewRequest GET %s", url) } return nil, err } token := rds.Auth.Token() if token != "" { hreq.Header.Set("X-Amz-Security-Token", token) } hreq.Header.Set("X-Amz-Date", time.Now().UTC().Format(aws.ISO8601BasicFormat)) signer := aws.NewV4Signer(rds.Auth, "rds", rds.Region) signer.Sign(hreq) resp, err := http.DefaultClient.Do(hreq) if err != nil { if debug { log.Print("Error calling Amazon") } return nil, err } if resp.StatusCode == 200 { return resp.Body, nil } else { defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { if debug { log.Printf("Could not read response body") } return nil, err } msg := fmt.Sprintf( "Responce:\n\tStatusCode: %d\n\tBody: %s\n", resp.StatusCode, string(body), ) if debug { log.Printf(msg) } err = errors.New(msg) return nil, err } }
func (k *Kinesis) query(target string, query *Query) ([]byte, error) { data := strings.NewReader(query.String()) hreq, err := http.NewRequest("POST", k.Region.KinesisEndpoint+"/", data) if err != nil { return nil, err } hreq.Header.Set("Content-Type", "application/x-amz-json-1.1") hreq.Header.Set("X-Amz-Date", time.Now().UTC().Format(aws.ISO8601BasicFormat)) hreq.Header.Set("X-Amz-Target", target) if k.Auth.Token() != "" { hreq.Header.Set("X-Amz-Security-Token", k.Auth.Token()) } signer := aws.NewV4Signer(k.Auth, "kinesis", k.Region) signer.Sign(hreq) resp, err := http.DefaultClient.Do(hreq) if err != nil { log.Printf("kinesis: Error calling Amazon\n: %v", err) return nil, err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Printf("kinesis: Could not read response body\n") return nil, err } if debug { log.Printf("kinesis: response:\n") log.Printf("kinesis: %s", string(body)) } // "A response code of 200 indicates the operation was successful." if resp.StatusCode != 200 { err = buildError(resp, body) return nil, err } return body, nil }
func (sts *STS) query(params map[string]string, resp interface{}) error { params["Version"] = "2011-06-15" data := strings.NewReader(multimap(params).Encode()) hreq, err := http.NewRequest("POST", sts.Region.STSEndpoint+"/", data) if err != nil { return err } hreq.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value") token := sts.Auth.Token() if token != "" { hreq.Header.Set("X-Amz-Security-Token", token) } signer := aws.NewV4Signer(sts.Auth, "sts", sts.Region) signer.Sign(hreq) if debug { log.Printf("%v -> {\n", hreq) } r, err := http.DefaultClient.Do(hreq) if err != nil { log.Printf("Error calling Amazon") return err } defer r.Body.Close() if debug { dump, _ := httputil.DumpResponse(r, true) log.Printf("response:\n") log.Printf("%v\n}\n", string(dump)) } if r.StatusCode != 200 { return buildError(r) } err = xml.NewDecoder(r.Body).Decode(resp) return err }
func (k *KMS) query(requstInfo KMSAction) ([]byte, error) { b, err := json.Marshal(requstInfo) if err != nil { return nil, err } hreq, err := http.NewRequest(httpMethod, k.Region.KMSEndpoint+"/", bytes.NewBuffer(b)) if err != nil { return nil, err } hreq.Header.Set("Content-Type", contentType) hreq.Header.Set("X-Amz-Date", time.Now().UTC().Format(aws.ISO8601BasicFormat)) hreq.Header.Set("X-Amz-Target", targetPrefix+requstInfo.ActionName()) if k.Auth.Token() != "" { hreq.Header.Set("X-Amz-Security-Token", k.Auth.Token()) } //All KMS operations require Signature Version 4 //http://docs.aws.amazon.com/kms/latest/APIReference/Welcome.html signer := aws.NewV4Signer(k.Auth, serverName, k.Region) signer.Sign(hreq) r, err := http.DefaultClient.Do(hreq) if err != nil { return nil, err } body, _ := ioutil.ReadAll(r.Body) defer r.Body.Close() if r.StatusCode != 200 { return nil, buildError(body, r.StatusCode) } return body, err }
func (ec *ElastiCache) query(query string, response interface{}) error { url := ec.Region.ElastiCacheEndpoint + "/?" + query hreq, err := http.NewRequest("POST", url, nil) if err != nil { return err } hreq.Header.Set("Content-Type", "application/x-amz-json-1.0") hreq.Header.Set("X-Amz-Date", time.Now().UTC().Format(aws.ISO8601BasicFormat)) token := ec.Auth.Token() if token != "" { hreq.Header.Set("X-Amz-Security-Token", token) } signer := aws.NewV4Signer(ec.Auth, "elasticache", ec.Region) signer.Sign(hreq) resp, err := http.DefaultClient.Do(hreq) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != 200 { return buildError(resp) } b, err := ioutil.ReadAll(resp.Body) if err != nil { return err } return xml.Unmarshal(b, &response) }
// prepare sets up req to be delivered to S3. func (s3 *S3) prepare(req *request) error { // Copy so they can be mutated without affecting on retries. params := make(url.Values) headers := make(http.Header) for k, v := range req.params { params[k] = v } for k, v := range req.headers { headers[k] = v } req.params = params req.headers = headers if !req.prepared { req.prepared = true if req.method == "" { req.method = "GET" } if !strings.HasPrefix(req.path, "/") { req.path = "/" + req.path } err := s3.setBaseURL(req) if err != nil { return err } } if s3.Signature == aws.V2Signature && s3.Auth.Token() != "" { req.headers["X-Amz-Security-Token"] = []string{s3.Auth.Token()} } else if s3.Auth.Token() != "" { req.params.Set("X-Amz-Security-Token", s3.Auth.Token()) } if s3.Signature == aws.V2Signature { // Always sign again as it's not clear how far the // server has handled a previous attempt. u, err := url.Parse(req.baseurl) if err != nil { return err } signpathPartiallyEscaped := partiallyEscapedPath(req.path) if strings.IndexAny(s3.Region.S3BucketEndpoint, "${bucket}") >= 0 { signpathPartiallyEscaped = "/" + req.bucket + signpathPartiallyEscaped } req.headers["Host"] = []string{u.Host} req.headers["Date"] = []string{time.Now().In(time.UTC).Format(time.RFC1123)} sign(s3.Auth, req.method, signpathPartiallyEscaped, req.params, req.headers) } else { hreq, err := s3.setupHttpRequest(req) if err != nil { return err } hreq.Host = hreq.URL.Host signer := aws.NewV4Signer(s3.Auth, "s3", s3.Region) signer.IncludeXAmzContentSha256 = true signer.Sign(hreq) req.payload = hreq.Body if _, ok := headers["Content-Length"]; ok { req.headers["Content-Length"] = headers["Content-Length"] } } return nil }
func (s *RetrySuite) TestRetryPolicy(c *check.C) { // Save off the real endpoint, and then point it at a local proxy. endpoint := s.table.Server.Region.DynamoDBEndpoint policy := s.table.Server.RetryPolicy defer func() { s.table.Server.Region.DynamoDBEndpoint = endpoint s.table.Server.RetryPolicy = policy }() numCalls := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { numCalls++ // Fake a failure the requested amount of times. if numCalls <= s.NumCallsToFail { b, _ := json.Marshal(map[string]interface{}{ "__type": s.ErrorType, "Code": "blah", }) w.WriteHeader(s.ErrorStatusCode) io.WriteString(w, string(b)) return } // Otherwise, proxy to actual DynamoDB endpoint. We reformat the request // with the same content. body, err := ioutil.ReadAll(r.Body) if err != nil { c.Fatal(err) } newr, err := http.NewRequest("POST", endpoint+"/", strings.NewReader(string(body))) headersToKeep := map[string]bool{ "Content-Type": true, "X-Amz-Date": true, "X-Amz-Target": true, "X-Amz-Security-Token": true, } for h := range r.Header { if _, ok := headersToKeep[h]; ok { newr.Header.Set(h, r.Header.Get(h)) } } signer := aws.NewV4Signer(s.table.Server.Auth, "dynamodb", s.table.Server.Region) signer.Sign(newr) resp, err := http.DefaultClient.Do(newr) if err != nil { c.Fatal(err) } body, err = ioutil.ReadAll(resp.Body) defer resp.Body.Close() if err != nil { c.Fatal(err) } w.WriteHeader(resp.StatusCode) io.WriteString(w, string(body)) })) defer server.Close() rp := &retryPolicy{} s.table.Server.RetryPolicy = rp s.table.Server.Region.DynamoDBEndpoint = server.URL // Now make the request. k := &Key{HashKey: "NewHashKeyVal"} in := map[string]interface{}{ "Attr1": "Attr1Val", "Attr2": 12, } err := s.table.PutDocument(k, in) if s.ExpectError { if err == nil { c.Fatalf("Expected error") } } else { if err != nil { c.Fatal(err) } } if rp.numCalls != s.NumCallsToFail { c.Fatalf("Expected %d failed calls, saw %d", s.NumCallsToFail, rp.numCalls) } }
func (s *Server) queryServer(target string, query Query) ([]byte, error) { numRetries := 0 for { qs, err := query.Marshal() if err != nil { return nil, err } data := bytes.NewReader(qs) hreq, err := http.NewRequest("POST", s.Region.DynamoDBEndpoint+"/", data) if err != nil { return nil, err } hreq.Header.Set("Content-Type", "application/x-amz-json-1.0") hreq.Header.Set("X-Amz-Date", time.Now().UTC().Format(aws.ISO8601BasicFormat)) hreq.Header.Set("X-Amz-Target", target) token := s.Auth.Token() if token != "" { hreq.Header.Set("X-Amz-Security-Token", token) } signer := aws.NewV4Signer(s.Auth, "dynamodb", s.Region) signer.Sign(hreq) resp, err := http.DefaultClient.Do(hreq) if err != nil { if s.RetryPolicy.ShouldRetry(target, resp, err, numRetries) { time.Sleep(s.RetryPolicy.Delay(target, resp, err, numRetries)) numRetries++ continue } return nil, err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { if s.RetryPolicy.ShouldRetry(target, resp, err, numRetries) { time.Sleep(s.RetryPolicy.Delay(target, resp, err, numRetries)) numRetries++ continue } return nil, err } // http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ErrorHandling.html // "A response code of 200 indicates the operation was successful." if resp.StatusCode != 200 { err := buildError(resp, body) if s.RetryPolicy.ShouldRetry(target, resp, err, numRetries) { time.Sleep(s.RetryPolicy.Delay(target, resp, err, numRetries)) numRetries++ continue } return nil, err } return body, nil } }