Merge lp:~cox-katherine-e/goamz/lp1319475.v4.signature.support into lp:goamz

Proposed by Katherine Cox-Buday
Status: Merged
Approved by: Martin Packman
Approved revision: 51
Merged at revision: 49
Proposed branch: lp:~cox-katherine-e/goamz/lp1319475.v4.signature.support
Merge into: lp:goamz
Diff against target: 1347 lines (+668/-177)
31 files modified
aws/attempt_test.go (+1/-1)
aws/aws.go (+10/-0)
aws/aws_test.go (+1/-1)
aws/sign.go (+366/-0)
aws/sign_test.go (+227/-0)
ec2/ec2.go (+19/-15)
ec2/ec2_test.go (+2/-18)
ec2/ec2i_test.go (+1/-1)
ec2/ec2t_test.go (+2/-2)
ec2/export_test.go (+0/-5)
ec2/networkinterfaces_test.go (+1/-1)
ec2/privateips_test.go (+1/-1)
ec2/sign.go (+0/-42)
ec2/sign_test.go (+0/-68)
ec2/subnets_test.go (+1/-1)
ec2/vpc_test.go (+1/-1)
exp/mturk/mturk_test.go (+1/-1)
exp/mturk/sign_test.go (+1/-1)
exp/sdb/sdb_test.go (+2/-2)
exp/sdb/sign_test.go (+1/-1)
exp/sns/sns_test.go (+2/-2)
iam/iam_test.go (+2/-2)
iam/iami_test.go (+1/-1)
iam/iamt_test.go (+2/-2)
s3/multi_test.go (+1/-1)
s3/s3_test.go (+2/-2)
s3/s3i_test.go (+1/-1)
s3/s3t_test.go (+2/-1)
s3/sign_test.go (+1/-1)
testutil/http.go (+15/-1)
testutil/suite.go (+1/-1)
To merge this branch: bzr merge lp:~cox-katherine-e/goamz/lp1319475.v4.signature.support
Reviewer Review Type Date Requested Status
Martin Packman (community) Approve
Review via email: mp+230401@code.launchpad.net

Description of the change

In order to keep the change as least impactful as possible, all regions will continue utilizing the v2 signing process except for China. China will utilize the new v4 signing methodology. Attaching the signature to the region also keeps the public APIs the same.

Although not tested on a live China instance, tests were performed on the sample requests provided by Amazon, of which the significant ones are passing (significant being the tests which test the signing process and not whether we can parse an HTTP request). The new version was also tested on a live EC2 instance with the v2 signing process to ensure there were no regressions. This gives us a high degree of confidence that the v4 signatures are passing.

Note many files have changes simply from switching over to gpkg.in for gocheck.

Also note that the v2 signature has been moved to aws/sign.go which accounts for a large amount of the diff.

To post a comment you must log in.
50. By Katherine Cox-Buday <kate@washu>

Added documentation to the public methods.

51. By Katherine Cox-Buday <kate@washu>

Corrected bug when path-segment was empty. Added test for this.

Revision history for this message
Martin Packman (gz) wrote :

Looks good to me.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'aws/attempt_test.go'
2--- aws/attempt_test.go 2013-02-01 19:38:47 +0000
3+++ aws/attempt_test.go 2014-08-12 16:51:05 +0000
4@@ -2,7 +2,7 @@
5
6 import (
7 "launchpad.net/goamz/aws"
8- . "launchpad.net/gocheck"
9+ . "gopkg.in/check.v1"
10 "time"
11 )
12
13
14=== modified file 'aws/aws.go'
15--- aws/aws.go 2014-07-08 15:42:26 +0000
16+++ aws/aws.go 2014-08-12 16:51:05 +0000
17@@ -27,6 +27,7 @@
18 SNSEndpoint string
19 SQSEndpoint string
20 IAMEndpoint string
21+ Sign Signer // Method which will be used to sign requests.
22 }
23
24 var USEast = Region{
25@@ -40,6 +41,7 @@
26 "https://sns.us-east-1.amazonaws.com",
27 "https://sqs.us-east-1.amazonaws.com",
28 "https://iam.amazonaws.com",
29+ SignV2,
30 }
31
32 var USWest = Region{
33@@ -53,6 +55,7 @@
34 "https://sns.us-west-1.amazonaws.com",
35 "https://sqs.us-west-1.amazonaws.com",
36 "https://iam.amazonaws.com",
37+ SignV2,
38 }
39
40 var USWest2 = Region{
41@@ -66,6 +69,7 @@
42 "https://sns.us-west-2.amazonaws.com",
43 "https://sqs.us-west-2.amazonaws.com",
44 "https://iam.amazonaws.com",
45+ SignV2,
46 }
47
48 var EUWest = Region{
49@@ -79,6 +83,7 @@
50 "https://sns.eu-west-1.amazonaws.com",
51 "https://sqs.eu-west-1.amazonaws.com",
52 "https://iam.amazonaws.com",
53+ SignV2,
54 }
55
56 var APSoutheast = Region{
57@@ -92,6 +97,7 @@
58 "https://sns.ap-southeast-1.amazonaws.com",
59 "https://sqs.ap-southeast-1.amazonaws.com",
60 "https://iam.amazonaws.com",
61+ SignV2,
62 }
63
64 var APSoutheast2 = Region{
65@@ -105,6 +111,7 @@
66 "https://sns.ap-southeast-2.amazonaws.com",
67 "https://sqs.ap-southeast-2.amazonaws.com",
68 "https://iam.amazonaws.com",
69+ SignV2,
70 }
71
72 var APNortheast = Region{
73@@ -118,6 +125,7 @@
74 "https://sns.ap-northeast-1.amazonaws.com",
75 "https://sqs.ap-northeast-1.amazonaws.com",
76 "https://iam.amazonaws.com",
77+ SignV2,
78 }
79
80 var SAEast = Region{
81@@ -131,6 +139,7 @@
82 "https://sns.sa-east-1.amazonaws.com",
83 "https://sqs.sa-east-1.amazonaws.com",
84 "https://iam.amazonaws.com",
85+ SignV2,
86 }
87
88 var CNNorth = Region{
89@@ -144,6 +153,7 @@
90 "https://sns.cn-north-1.amazonaws.com.cn",
91 "https://sqs.cn-north-1.amazonaws.com.cn",
92 "https://iam.amazonaws.com.cn",
93+ SignV4Factory("cn-north-1"),
94 }
95
96 var Regions = map[string]Region{
97
98=== modified file 'aws/aws_test.go'
99--- aws/aws_test.go 2013-05-23 01:06:45 +0000
100+++ aws/aws_test.go 2014-08-12 16:51:05 +0000
101@@ -2,7 +2,7 @@
102
103 import (
104 "launchpad.net/goamz/aws"
105- . "launchpad.net/gocheck"
106+ . "gopkg.in/check.v1"
107 "os"
108 "strings"
109 "testing"
110
111=== added file 'aws/sign.go'
112--- aws/sign.go 1970-01-01 00:00:00 +0000
113+++ aws/sign.go 2014-08-12 16:51:05 +0000
114@@ -0,0 +1,366 @@
115+package aws
116+
117+import (
118+ "bytes"
119+ "crypto/hmac"
120+ "crypto/sha256"
121+ "encoding/base64"
122+ "fmt"
123+ "io"
124+ "io/ioutil"
125+ "net/http"
126+ "net/url"
127+ "sort"
128+ "strings"
129+ "time"
130+)
131+
132+type Signer func(*http.Request, Auth) error
133+
134+// Ensure our signers meet the interface
135+var _ Signer = SignV2
136+var _ Signer = SignV4Factory("")
137+
138+type hasher func([]byte) string
139+
140+const (
141+ ISO8601BasicFormat = "20060102T150405Z"
142+ ISO8601BasicFormatShort = "20060102"
143+)
144+
145+// SignV2 signs an HTTP request utilizing version 2 of the AWS
146+// signature, and the given credentials.
147+func SignV2(req *http.Request, auth Auth) (err error) {
148+
149+ queryVals := req.URL.Query()
150+ queryVals.Set("AWSAccessKeyId", auth.AccessKey)
151+ queryVals.Set("SignatureVersion", "2")
152+ queryVals.Set("SignatureMethod", "HmacSHA256")
153+
154+ queryStr, err := canonicalQueryString(queryVals)
155+ if err != nil {
156+ return err
157+ }
158+
159+ // The algorithm states that if the path is empty, to just use a "/".
160+ path := req.URL.Path
161+ if path == "" {
162+ path = "/"
163+ }
164+
165+ payload := new(bytes.Buffer)
166+ if err := errorCollector(
167+ fprintfWrapper(payload, "%s\n", requestMethodVerb(req.Method)),
168+ fprintfWrapper(payload, "%s\n", req.Host),
169+ fprintfWrapper(payload, "%s\n", path),
170+ fprintfWrapper(payload, "%s", queryStr),
171+ ); err != nil {
172+ return err
173+ }
174+
175+ hash := hmac.New(sha256.New, []byte(auth.SecretKey))
176+ hash.Write(payload.Bytes())
177+ signature := make([]byte, base64.StdEncoding.EncodedLen(hash.Size()))
178+ base64.StdEncoding.Encode(signature, hash.Sum(nil))
179+
180+ queryVals.Set("Signature", string(signature))
181+ req.URL.RawQuery = queryVals.Encode()
182+
183+ return nil
184+}
185+
186+// SignV4Factory returns a version 4 Signer which will utilize the
187+// given region name.
188+func SignV4Factory(regionName string) Signer {
189+ return func(req *http.Request, auth Auth) error {
190+ return SignV4(req, auth, regionName)
191+ }
192+}
193+
194+// SignV4 signs an HTTP request utilizing version 4 of the AWS
195+// signature, and the given credentials.
196+func SignV4(req *http.Request, auth Auth, regionName string) (err error) {
197+
198+ var reqTime time.Time
199+ if reqTime, err = requestTime(req); err != nil {
200+ return err
201+ }
202+
203+ svcName := inferServiceName(req.URL)
204+ credScope := credentialScope(reqTime, regionName, svcName)
205+
206+ // There are several places in the algorithm that call for
207+ // processing the headers sorted by name.
208+ sortedHdrNames := sortHeaderNames(req.Header)
209+
210+ var canonReqHash string
211+ if _, canonReqHash, err = canonicalRequest(req, sortedHdrNames, sha256Hasher); err != nil {
212+ return err
213+ }
214+
215+ var strToSign string
216+ if strToSign, err = stringToSign(reqTime, canonReqHash, credScope); err != nil {
217+ return err
218+ }
219+
220+ key := signingKey(reqTime, auth.SecretKey, regionName, svcName)
221+ signature := fmt.Sprintf("%x", hmacHasher(key, strToSign))
222+
223+ var authHdrVal string
224+ if authHdrVal, err = authHeaderString(
225+ req.Header,
226+ auth.AccessKey,
227+ signature,
228+ credScope,
229+ sortedHdrNames,
230+ ); err != nil {
231+ return err
232+ }
233+
234+ req.Header.Set("Authorization", authHdrVal)
235+
236+ return nil
237+}
238+
239+// Task 1: Create a Canonical Request.
240+// Returns the canonical request, and its hash.
241+func canonicalRequest(
242+ req *http.Request,
243+ sortedHdrNames []string,
244+ hasher hasher,
245+) (canReq, canReqHash string, err error) {
246+
247+ var canHdr string
248+ if canHdr, err = canonicalHeaders(sortedHdrNames, req.Header); err != nil {
249+ return
250+ }
251+
252+ var payHash string
253+ if payHash, err = payloadHash(req, hasher); err != nil {
254+ return
255+ }
256+
257+ var queryStr string
258+ if queryStr, err = canonicalQueryString(req.URL.Query()); err != nil {
259+ return
260+ }
261+
262+ c := new(bytes.Buffer)
263+ if err := errorCollector(
264+ fprintfWrapper(c, "%s\n", requestMethodVerb(req.Method)),
265+ fprintfWrapper(c, "%s\n", req.URL.RequestURI()),
266+ fprintfWrapper(c, "%s\n", queryStr),
267+ fprintfWrapper(c, "%s\n", canHdr),
268+ fprintfWrapper(c, "%s\n", strings.Join(sortedHdrNames, ";")),
269+ fprintfWrapper(c, "%s", payHash),
270+ ); err != nil {
271+ return "", "", err
272+ }
273+
274+ canReq = c.String()
275+ return canReq, hasher([]byte(canReq)), nil
276+}
277+
278+// Task 2: Create a string to Sign
279+// Returns a string in the defined format to sign for the authorization header.
280+func stringToSign(
281+ t time.Time,
282+ canonReqHash string,
283+ credScope string,
284+) (string, error) {
285+ w := new(bytes.Buffer)
286+ if err := errorCollector(
287+ fprintfWrapper(w, "AWS4-HMAC-SHA256\n"),
288+ fprintfWrapper(w, "%s\n", t.Format(ISO8601BasicFormat)),
289+ fprintfWrapper(w, "%s\n", credScope),
290+ fprintfWrapper(w, "%s", canonReqHash),
291+ ); err != nil {
292+ return "", err
293+ }
294+
295+ return w.String(), nil
296+}
297+
298+// Task 3: Calculate the Signature
299+// Returns a derived signing key.
300+func signingKey(t time.Time, secretKey, regionName, svcName string) []byte {
301+
302+ kSecret := secretKey
303+ kDate := hmacHasher([]byte("AWS4"+kSecret), t.Format(ISO8601BasicFormatShort))
304+ kRegion := hmacHasher(kDate, regionName)
305+ kService := hmacHasher(kRegion, svcName)
306+ kSigning := hmacHasher(kService, "aws4_request")
307+
308+ return kSigning
309+}
310+
311+// Task 4: Add the Signing Information to the Request
312+// Returns a string to be placed in the Authorization header for the request.
313+func authHeaderString(
314+ header http.Header,
315+ accessKey,
316+ signature string,
317+ credScope string,
318+ sortedHeaderNames []string,
319+) (string, error) {
320+ w := new(bytes.Buffer)
321+ if err := errorCollector(
322+ fprintfWrapper(w, "AWS4-HMAC-SHA256 "),
323+ fprintfWrapper(w, "Credential=%s/%s, ", accessKey, credScope),
324+ fprintfWrapper(w, "SignedHeaders=%s, ", strings.Join(sortedHeaderNames, ";")),
325+ fprintfWrapper(w, "Signature=%s", signature),
326+ ); err != nil {
327+ return "", err
328+ }
329+
330+ return w.String(), nil
331+}
332+
333+func canonicalQueryString(queryVals url.Values) (string, error) {
334+
335+ // AWS dictates that we use %20 for encoding spaces rather than +.
336+ // All significant +s should already be encoded into their
337+ // hexadecimal equivalents before doing the string replace.
338+ return strings.Replace(queryVals.Encode(), "+", "%20", -1), nil
339+}
340+
341+func canonicalHeaders(sortedHeaderNames []string, hdr http.Header) (string, error) {
342+ buffer := new(bytes.Buffer)
343+
344+ for _, hName := range sortedHeaderNames {
345+ canonHdrKey := http.CanonicalHeaderKey(hName)
346+ sortedHdrVals := hdr[canonHdrKey]
347+ sort.Strings(sortedHdrVals)
348+ hdrVals := strings.Join(sortedHdrVals, ",")
349+ if _, err := fmt.Fprintf(buffer, "%s:%s\n", hName, hdrVals); err != nil {
350+ return "", err
351+ }
352+ }
353+
354+ return buffer.String(), nil
355+}
356+
357+// Returns a SHA256 checksum of the request body. Represented as a
358+// lowercase hexadecimal string.
359+func payloadHash(req *http.Request, hasher hasher) (string, error) {
360+ if b, err := ioutil.ReadAll(req.Body); err != nil {
361+ return "", err
362+ } else {
363+ req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
364+ return hasher(b), nil
365+ }
366+}
367+
368+// Retrieve the header names, lower-case them, and sort them.
369+func sortHeaderNames(header http.Header) []string {
370+
371+ var sortedNames []string
372+ for hName, _ := range header {
373+ sortedNames = append(sortedNames, strings.ToLower(hName))
374+ }
375+
376+ sort.Strings(sortedNames)
377+
378+ return sortedNames
379+}
380+
381+func hmacHasher(key []byte, value string) []byte {
382+ h := hmac.New(sha256.New, key)
383+ h.Write([]byte(value))
384+ return h.Sum(nil)
385+}
386+
387+func inferServiceName(url *url.URL) string {
388+ return strings.Split(url.Host, ".")[0]
389+}
390+
391+func sha256Hasher(payload []byte) string {
392+ return fmt.Sprintf("%x", sha256.Sum256(payload))
393+}
394+
395+func credentialScope(t time.Time, regionName, svcName string) string {
396+ return fmt.Sprintf(
397+ "%s/%s/%s/aws4_request",
398+ t.Format(ISO8601BasicFormatShort),
399+ regionName,
400+ svcName,
401+ )
402+}
403+
404+// We do a lot of fmt.Fprintfs in this package. Create a higher-order
405+// function to elide the bytes written return value so we can submit
406+// these calls to an error collector.
407+func fprintfWrapper(w io.Writer, format string, vals ...interface{}) func() error {
408+ return func() error {
409+ _, err := fmt.Fprintf(w, format, vals...)
410+ return err
411+ }
412+}
413+
414+// Poor man's maybe monad.
415+func errorCollector(writers ...func() error) error {
416+ for _, writer := range writers {
417+ if err := writer(); err != nil {
418+ return err
419+ }
420+ }
421+
422+ return nil
423+}
424+
425+// Time formats to try. We want to do everything we can to accept all
426+// time formats, but ultimately we may fail. In the package scope so
427+// it doesn't get initialized for every request.
428+var timeFormats = []string{
429+ time.RFC822,
430+ ISO8601BasicFormat,
431+ time.RFC1123,
432+ time.ANSIC,
433+ time.UnixDate,
434+ time.RubyDate,
435+ time.RFC822Z,
436+ time.RFC850,
437+ time.RFC1123Z,
438+ time.RFC3339,
439+ time.RFC3339Nano,
440+ time.Kitchen,
441+}
442+
443+// Retrieve the request time from the request. We will attempt to
444+// parse whatever we find, but we will not make up a request date for
445+// the user (i.e.: Magic!).
446+func requestTime(req *http.Request) (time.Time, error) {
447+
448+ // Get a date header.
449+ var date string
450+ if date = req.Header.Get("x-amz-date"); date == "" {
451+ if date = req.Header.Get("date"); date == "" {
452+ return time.Time{}, fmt.Errorf(`Could not retrieve a request date. Please provide one in either "x-amz-date", or "date".`)
453+ }
454+ }
455+
456+ // Start attempting to parse
457+ for _, format := range timeFormats {
458+ if parsedTime, err := time.Parse(format, date); err == nil {
459+ return parsedTime, nil
460+ }
461+ }
462+
463+ return time.Time{}, fmt.Errorf(
464+ "Could not parse the given date. Please utilize on of the following formats: %s",
465+ strings.Join(timeFormats, ","),
466+ )
467+}
468+
469+// http.Request's Method member returns the entire method. Derive the
470+// verb.
471+func requestMethodVerb(rawMethod string) (verb string) {
472+ verbPlus := strings.SplitN(rawMethod, " ", 2)
473+ switch {
474+ case len(verbPlus) == 0: // Per docs, Method will be empty if it's GET.
475+ verb = "GET"
476+ default:
477+ verb = verbPlus[0]
478+ }
479+ return verb
480+}
481
482=== added file 'aws/sign_test.go'
483--- aws/sign_test.go 1970-01-01 00:00:00 +0000
484+++ aws/sign_test.go 2014-08-12 16:51:05 +0000
485@@ -0,0 +1,227 @@
486+package aws
487+
488+import (
489+ "bytes"
490+ "fmt"
491+ . "gopkg.in/check.v1"
492+ "net/http"
493+ "time"
494+)
495+
496+var _ = Suite(&SigningSuite{})
497+
498+type SigningSuite struct{}
499+
500+// EC2 ReST authentication docs: http://goo.gl/fQmAN
501+var testAuth = Auth{"user", "secret"}
502+
503+func (s *SigningSuite) TestV4StringToSign(c *C) {
504+
505+ mockTime, err := time.Parse(time.RFC3339, "2011-09-09T23:36:00Z")
506+ c.Assert(err, IsNil)
507+ stringToSign, err := stringToSign(
508+ mockTime,
509+ "3511de7e95d28ecd39e9513b642aee07e54f4941150d8df8bf94b328ef7e55e2",
510+ "20110909/us-east-1/iam/aws4_request",
511+ )
512+ c.Assert(err, IsNil)
513+
514+ const expected = `AWS4-HMAC-SHA256
515+20110909T233600Z
516+20110909/us-east-1/iam/aws4_request
517+3511de7e95d28ecd39e9513b642aee07e54f4941150d8df8bf94b328ef7e55e2`
518+ c.Assert(stringToSign, Equals, expected)
519+}
520+
521+func (s *SigningSuite) TestV4CanonicalRequest(c *C) {
522+
523+ body := new(bytes.Buffer)
524+ _, err := fmt.Fprint(body, "Action=ListUsers&Version=2010-05-08")
525+ c.Assert(err, IsNil)
526+
527+ req, err := http.NewRequest("POST", "https://iam.amazonaws.com", body)
528+ c.Assert(err, IsNil)
529+
530+ req.Header.Add("content-type", "application/x-www-form-urlencoded; charset=utf-8")
531+ req.Header.Add("host", req.URL.Host)
532+ req.Header.Add("x-amz-date", "20110909T233600Z")
533+
534+ canonReq, canonReqHash, err := canonicalRequest(
535+ req,
536+ []string{"content-type", "host", "x-amz-date"},
537+ sha256Hasher,
538+ )
539+ c.Assert(err, IsNil)
540+
541+ const expected = `POST
542+/
543+
544+content-type:application/x-www-form-urlencoded; charset=utf-8
545+host:iam.amazonaws.com
546+x-amz-date:20110909T233600Z
547+
548+content-type;host;x-amz-date
549+b6359072c78d70ebee1e81adcbab4f01bf2c23245fa365ef83fe8f1f955085e2`
550+
551+ c.Assert(canonReq, Equals, expected)
552+ c.Assert(canonReqHash, Equals, "3511de7e95d28ecd39e9513b642aee07e54f4941150d8df8bf94b328ef7e55e2")
553+}
554+
555+func (s *SigningSuite) TestV4SigningKey(c *C) {
556+ mockTime, err := time.Parse(time.RFC3339, "2011-09-09T23:36:00Z")
557+ c.Assert(err, IsNil)
558+ c.Assert(
559+ fmt.Sprintf("%v", signingKey(mockTime, testAuth.SecretKey, USEast.Name, "iam")),
560+ Equals,
561+ "[152 241 216 137 254 196 244 66 26 220 82 43 171 12 225 248 46 105 41 194 98 237 21 229 169 76 144 239 209 227 176 231]")
562+}
563+
564+func (s *SigningSuite) TestV4BasicSignatureV4(c *C) {
565+
566+ body := new(bytes.Buffer)
567+
568+ req, err := http.NewRequest("POST / http/1.1", "https://host.foo.com", body)
569+ c.Assert(err, IsNil)
570+
571+ req.Header.Add("Host", req.URL.Host)
572+ req.Header.Add("Date", "Mon, 09 Sep 2011 23:36:00 GMT")
573+
574+ testAuth = Auth{
575+ AccessKey: "AKIDEXAMPLE",
576+ SecretKey: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
577+ }
578+ err = SignV4(req, testAuth, USEast.Name)
579+ c.Assert(err, IsNil)
580+
581+ c.Assert(req.Header.Get("Authorization"), Equals, `AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726`)
582+}
583+
584+//
585+// v2 Tests
586+//
587+
588+func (s *SigningSuite) TestV2BasicSignature(c *C) {
589+ req, err := http.NewRequest("GET", "http://localhost/path", nil)
590+ c.Assert(err, IsNil)
591+
592+ SignV2(req, testAuth)
593+
594+ query := req.URL.Query()
595+
596+ c.Assert(query.Get("SignatureVersion"), Equals, "2")
597+ c.Assert(query.Get("SignatureMethod"), Equals, "HmacSHA256")
598+ expected := "6lSe5QyXum0jMVc7cOUz32/52ZnL7N5RyKRk/09yiK4="
599+ c.Assert(query.Get("Signature"), Equals, expected)
600+}
601+
602+func (s *SigningSuite) TestV2ParamSignature(c *C) {
603+
604+ req, err := http.NewRequest("GET", "http://localhost/path", nil)
605+ c.Assert(err, IsNil)
606+
607+ query := req.URL.Query()
608+ for i := 1; i <= 3; i++ {
609+ query.Add(fmt.Sprintf("param%d", i), fmt.Sprintf("value%d", i))
610+ }
611+ req.URL.RawQuery = query.Encode()
612+
613+ SignV2(req, testAuth)
614+
615+ expected := "XWOR4+0lmK8bD8CGDGZ4kfuSPbb2JibLJiCl/OPu1oU="
616+ c.Assert(req.URL.Query().Get("Signature"), Equals, expected)
617+}
618+
619+func (s *SigningSuite) TestV2ManyParams(c *C) {
620+
621+ req, err := http.NewRequest("GET", "http://localhost/path", nil)
622+ c.Assert(err, IsNil)
623+
624+ query := req.URL.Query()
625+ orderedVals := []int{10, 2, 3, 4, 5, 6, 7, 8, 9, 1}
626+ for i, val := range orderedVals {
627+ query.Add(fmt.Sprintf("param%d", i+1), fmt.Sprintf("value%d", val))
628+ }
629+ req.URL.RawQuery = query.Encode()
630+
631+ SignV2(req, testAuth)
632+
633+ expected := "di0sjxIvezUgQ1SIL6i+C/H8lL+U0CQ9frLIak8jkVg="
634+ c.Assert(req.URL.Query().Get("Signature"), Equals, expected)
635+}
636+
637+func (s *SigningSuite) TestV2Escaping(c *C) {
638+
639+ req, err := http.NewRequest("GET", "http://localhost/path", nil)
640+ c.Assert(err, IsNil)
641+
642+ query := req.URL.Query()
643+ query.Add("Nonce", "+ +")
644+ req.URL.RawQuery = query.Encode()
645+
646+ err = SignV2(req, testAuth)
647+ c.Assert(err, IsNil)
648+
649+ query = req.URL.Query()
650+ c.Assert(query.Get("Nonce"), Equals, "+ +")
651+
652+ expected := "bqffDELReIqwjg/W0DnsnVUmfLK4wXVLO4/LuG+1VFA="
653+ c.Assert(query.Get("Signature"), Equals, expected)
654+}
655+
656+func (s *SigningSuite) TestV2SignatureExample1(c *C) {
657+
658+ req, err := http.NewRequest("GET", "http://sdb.amazonaws.com/", nil)
659+ c.Assert(err, IsNil)
660+
661+ query := req.URL.Query()
662+ query.Add("Timestamp", "2009-02-01T12:53:20+00:00")
663+ query.Add("Version", "2007-11-07")
664+ query.Add("Action", "ListDomains")
665+ req.URL.RawQuery = query.Encode()
666+
667+ SignV2(req, Auth{"access", "secret"})
668+
669+ expected := "okj96/5ucWBSc1uR2zXVfm6mDHtgfNv657rRtt/aunQ="
670+ c.Assert(req.URL.Query().Get("Signature"), Equals, expected)
671+}
672+
673+// Tests example from:
674+// http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
675+// Specifically, good for testing case when URL does not contain a /
676+func (s *SigningSuite) TestV2SignatureTutorialExample(c *C) {
677+
678+ req, err := http.NewRequest("GET", "https://elasticmapreduce.amazonaws.com/", nil)
679+ c.Assert(err, IsNil)
680+
681+ query := req.URL.Query()
682+ query.Add("Timestamp", "2011-10-03T15:19:30")
683+ query.Add("Version", "2009-03-31")
684+ query.Add("Action", "DescribeJobFlows")
685+ req.URL.RawQuery = query.Encode()
686+
687+ testAuth := Auth{"AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}
688+ err = SignV2(req, testAuth)
689+ c.Assert(err, IsNil)
690+ c.Assert(req.URL.Query().Get("Signature"), Equals, "i91nKc4PWAt0JJIdXwz9HxZCJDdiy6cf/Mj6vPxyYIs=")
691+}
692+
693+// https://bugs.launchpad.net/goamz/+bug/1022749
694+func (s *SigningSuite) TestSignatureWithEndpointPath(c *C) {
695+
696+ req, err := http.NewRequest("GET", "http://localhost:4444/services/Cloud", nil)
697+ c.Assert(err, IsNil)
698+
699+ queryStr := req.URL.Query()
700+ queryStr.Add("Action", "RebootInstances")
701+ queryStr.Add("Version", "2011-12-15")
702+ queryStr.Add("InstanceId.1", "i-10a64379")
703+ queryStr.Add("Timestamp", time.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC).In(time.UTC).Format(time.RFC3339))
704+ req.URL.RawQuery = queryStr.Encode()
705+
706+ err = SignV2(req, Auth{"abc", "123"})
707+ c.Assert(err, IsNil)
708+ c.Assert(req.URL.Query().Get("Signature"), Equals, "gdG/vEm+c6ehhhfkrJy3+wuVzw/rzKR42TYelMwti7M=")
709+ err = req.ParseForm()
710+ c.Assert(err, IsNil)
711+ c.Assert(req.Form["Signature"], DeepEquals, []string{"gdG/vEm+c6ehhhfkrJy3+wuVzw/rzKR42TYelMwti7M="})
712+}
713
714=== modified file 'ec2/ec2.go'
715--- ec2/ec2.go 2014-05-30 09:43:41 +0000
716+++ ec2/ec2.go 2014-08-12 16:51:05 +0000
717@@ -21,6 +21,7 @@
718 "strconv"
719 "time"
720
721+ "encoding/base64"
722 "launchpad.net/goamz/aws"
723 )
724
725@@ -126,21 +127,25 @@
726
727 var timeNow = time.Now
728
729+// resp = response structure that will get inflated by XML unmarshaling.
730 func (ec2 *EC2) query(params map[string]string, resp interface{}) error {
731- params["Timestamp"] = timeNow().In(time.UTC).Format(time.RFC3339)
732- endpoint, err := url.Parse(ec2.Region.EC2Endpoint)
733+
734+ req, err := http.NewRequest("GET", ec2.Region.EC2Endpoint, nil)
735 if err != nil {
736 return err
737 }
738- if endpoint.Path == "" {
739- endpoint.Path = "/"
740- }
741- sign(ec2.Auth, "GET", endpoint.Path, params, endpoint.Host)
742- endpoint.RawQuery = multimap(params).Encode()
743- if debug {
744- log.Printf("get { %v } -> {\n", endpoint.String())
745- }
746- r, err := http.Get(endpoint.String())
747+
748+ // Add the params passed in to the query string
749+ query := req.URL.Query()
750+ for varName, varVal := range params {
751+ query.Add(varName, varVal)
752+ }
753+ query.Add("Timestamp", timeNow().In(time.UTC).Format(time.RFC3339))
754+ req.URL.RawQuery = query.Encode()
755+
756+ ec2.Region.Sign(req, ec2.Auth)
757+
758+ r, err := http.DefaultClient.Do(req)
759 if err != nil {
760 return err
761 }
762@@ -154,8 +159,7 @@
763 if r.StatusCode != 200 {
764 return buildError(r)
765 }
766- err = xml.NewDecoder(r.Body).Decode(resp)
767- return err
768+ return xml.NewDecoder(r.Body).Decode(resp)
769 }
770
771 func multimap(p map[string]string) url.Values {
772@@ -349,8 +353,8 @@
773 params["RamdiskId"] = options.RamdiskId
774 }
775 if options.UserData != nil {
776- userData := make([]byte, b64.EncodedLen(len(options.UserData)))
777- b64.Encode(userData, options.UserData)
778+ userData := make([]byte, base64.StdEncoding.EncodedLen(len(options.UserData)))
779+ base64.StdEncoding.Encode(userData, options.UserData)
780 params["UserData"] = string(userData)
781 }
782 if options.AvailZone != "" {
783
784=== modified file 'ec2/ec2_test.go'
785--- ec2/ec2_test.go 2014-05-30 09:43:41 +0000
786+++ ec2/ec2_test.go 2014-08-12 16:51:05 +0000
787@@ -6,7 +6,7 @@
788 "launchpad.net/goamz/aws"
789 "launchpad.net/goamz/ec2"
790 "launchpad.net/goamz/testutil"
791- . "launchpad.net/gocheck"
792+ . "gopkg.in/check.v1"
793 )
794
795 func Test(t *testing.T) {
796@@ -24,7 +24,7 @@
797 func (s *S) SetUpSuite(c *C) {
798 testServer.Start()
799 auth := aws.Auth{"abc", "123"}
800- s.ec2 = ec2.New(auth, aws.Region{EC2Endpoint: testServer.URL})
801+ s.ec2 = ec2.New(auth, aws.Region{EC2Endpoint: testServer.URL, Sign: aws.SignV2})
802 }
803
804 func (s *S) TearDownSuite(c *C) {
805@@ -791,22 +791,6 @@
806 c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
807 }
808
809-func (s *S) TestSignatureWithEndpointPath(c *C) {
810- ec2.FakeTime(true)
811- defer ec2.FakeTime(false)
812-
813- testServer.Response(200, nil, RebootInstancesExample)
814-
815- // https://bugs.launchpad.net/goamz/+bug/1022749
816- ec2 := ec2.New(s.ec2.Auth, aws.Region{EC2Endpoint: testServer.URL + "/services/Cloud"})
817-
818- _, err := ec2.RebootInstances("i-10a64379")
819- c.Assert(err, IsNil)
820-
821- req := testServer.WaitRequest()
822- c.Assert(req.Form["Signature"], DeepEquals, []string{"gdG/vEm+c6ehhhfkrJy3+wuVzw/rzKR42TYelMwti7M="})
823-}
824-
825 func (s *S) TestAvailabilityZonesExample1(c *C) {
826 testServer.Response(200, nil, DescribeAvailabilityZonesExample1)
827
828
829=== modified file 'ec2/ec2i_test.go'
830--- ec2/ec2i_test.go 2014-05-21 13:52:28 +0000
831+++ ec2/ec2i_test.go 2014-08-12 16:51:05 +0000
832@@ -7,7 +7,7 @@
833 "launchpad.net/goamz/aws"
834 "launchpad.net/goamz/ec2"
835 "launchpad.net/goamz/testutil"
836- . "launchpad.net/gocheck"
837+ . "gopkg.in/check.v1"
838 )
839
840 // AmazonServer represents an Amazon EC2 server.
841
842=== modified file 'ec2/ec2t_test.go'
843--- ec2/ec2t_test.go 2014-05-30 09:43:41 +0000
844+++ ec2/ec2t_test.go 2014-08-12 16:51:05 +0000
845@@ -11,7 +11,7 @@
846 "launchpad.net/goamz/ec2"
847 "launchpad.net/goamz/ec2/ec2test"
848 "launchpad.net/goamz/testutil"
849- . "launchpad.net/gocheck"
850+ . "gopkg.in/check.v1"
851 )
852
853 // LocalServer represents a local ec2test fake server.
854@@ -33,7 +33,7 @@
855 })
856
857 s.srv = srv
858- s.region = aws.Region{EC2Endpoint: srv.URL()}
859+ s.region = aws.Region{EC2Endpoint: srv.URL(), Sign: aws.SignV2}
860 }
861
862 // LocalServerSuite defines tests that will run
863
864=== modified file 'ec2/export_test.go'
865--- ec2/export_test.go 2014-02-12 17:04:23 +0000
866+++ ec2/export_test.go 2014-08-12 16:51:05 +0000
867@@ -1,14 +1,9 @@
868 package ec2
869
870 import (
871- "launchpad.net/goamz/aws"
872 "time"
873 )
874
875-func Sign(auth aws.Auth, method, path string, params map[string]string, host string) {
876- sign(auth, method, path, params, host)
877-}
878-
879 func fixedTime() time.Time {
880 return time.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC)
881 }
882
883=== modified file 'ec2/networkinterfaces_test.go'
884--- ec2/networkinterfaces_test.go 2014-02-12 17:29:13 +0000
885+++ ec2/networkinterfaces_test.go 2014-08-12 16:51:05 +0000
886@@ -11,7 +11,7 @@
887 import (
888 "launchpad.net/goamz/aws"
889 "launchpad.net/goamz/ec2"
890- . "launchpad.net/gocheck"
891+ . "gopkg.in/check.v1"
892 "time"
893 )
894
895
896=== modified file 'ec2/privateips_test.go'
897--- ec2/privateips_test.go 2014-05-27 11:43:56 +0000
898+++ ec2/privateips_test.go 2014-08-12 16:51:05 +0000
899@@ -14,7 +14,7 @@
900
901 "launchpad.net/goamz/aws"
902 "launchpad.net/goamz/ec2"
903- . "launchpad.net/gocheck"
904+ . "gopkg.in/check.v1"
905 )
906
907 // Private IP tests with example responses
908
909=== removed file 'ec2/sign.go'
910--- ec2/sign.go 2013-05-23 01:06:45 +0000
911+++ ec2/sign.go 1970-01-01 00:00:00 +0000
912@@ -1,42 +0,0 @@
913-package ec2
914-
915-import (
916- "crypto/hmac"
917- "crypto/sha256"
918- "encoding/base64"
919- "launchpad.net/goamz/aws"
920- "sort"
921- "strings"
922-)
923-
924-// ----------------------------------------------------------------------------
925-// EC2 signing (http://goo.gl/fQmAN)
926-
927-var b64 = base64.StdEncoding
928-
929-func sign(auth aws.Auth, method, path string, params map[string]string, host string) {
930- params["AWSAccessKeyId"] = auth.AccessKey
931- params["SignatureVersion"] = "2"
932- params["SignatureMethod"] = "HmacSHA256"
933-
934- // AWS specifies that the parameters in a signed request must
935- // be provided in the natural order of the keys. This is distinct
936- // from the natural order of the encoded value of key=value.
937- // Percent and equals affect the sorting order.
938- var keys, sarray []string
939- for k, _ := range params {
940- keys = append(keys, k)
941- }
942- sort.Strings(keys)
943- for _, k := range keys {
944- sarray = append(sarray, aws.Encode(k)+"="+aws.Encode(params[k]))
945- }
946- joined := strings.Join(sarray, "&")
947- payload := method + "\n" + host + "\n" + path + "\n" + joined
948- hash := hmac.New(sha256.New, []byte(auth.SecretKey))
949- hash.Write([]byte(payload))
950- signature := make([]byte, b64.EncodedLen(hash.Size()))
951- b64.Encode(signature, hash.Sum(nil))
952-
953- params["Signature"] = string(signature)
954-}
955
956=== removed file 'ec2/sign_test.go'
957--- ec2/sign_test.go 2012-10-18 01:02:48 +0000
958+++ ec2/sign_test.go 1970-01-01 00:00:00 +0000
959@@ -1,68 +0,0 @@
960-package ec2_test
961-
962-import (
963- "launchpad.net/goamz/aws"
964- "launchpad.net/goamz/ec2"
965- . "launchpad.net/gocheck"
966-)
967-
968-// EC2 ReST authentication docs: http://goo.gl/fQmAN
969-
970-var testAuth = aws.Auth{"user", "secret"}
971-
972-func (s *S) TestBasicSignature(c *C) {
973- params := map[string]string{}
974- ec2.Sign(testAuth, "GET", "/path", params, "localhost")
975- c.Assert(params["SignatureVersion"], Equals, "2")
976- c.Assert(params["SignatureMethod"], Equals, "HmacSHA256")
977- expected := "6lSe5QyXum0jMVc7cOUz32/52ZnL7N5RyKRk/09yiK4="
978- c.Assert(params["Signature"], Equals, expected)
979-}
980-
981-func (s *S) TestParamSignature(c *C) {
982- params := map[string]string{
983- "param1": "value1",
984- "param2": "value2",
985- "param3": "value3",
986- }
987- ec2.Sign(testAuth, "GET", "/path", params, "localhost")
988- expected := "XWOR4+0lmK8bD8CGDGZ4kfuSPbb2JibLJiCl/OPu1oU="
989- c.Assert(params["Signature"], Equals, expected)
990-}
991-
992-func (s *S) TestManyParams(c *C) {
993- params := map[string]string{
994- "param1": "value10",
995- "param2": "value2",
996- "param3": "value3",
997- "param4": "value4",
998- "param5": "value5",
999- "param6": "value6",
1000- "param7": "value7",
1001- "param8": "value8",
1002- "param9": "value9",
1003- "param10": "value1",
1004- }
1005- ec2.Sign(testAuth, "GET", "/path", params, "localhost")
1006- expected := "di0sjxIvezUgQ1SIL6i+C/H8lL+U0CQ9frLIak8jkVg="
1007- c.Assert(params["Signature"], Equals, expected)
1008-}
1009-
1010-func (s *S) TestEscaping(c *C) {
1011- params := map[string]string{"Nonce": "+ +"}
1012- ec2.Sign(testAuth, "GET", "/path", params, "localhost")
1013- c.Assert(params["Nonce"], Equals, "+ +")
1014- expected := "bqffDELReIqwjg/W0DnsnVUmfLK4wXVLO4/LuG+1VFA="
1015- c.Assert(params["Signature"], Equals, expected)
1016-}
1017-
1018-func (s *S) TestSignatureExample1(c *C) {
1019- params := map[string]string{
1020- "Timestamp": "2009-02-01T12:53:20+00:00",
1021- "Version": "2007-11-07",
1022- "Action": "ListDomains",
1023- }
1024- ec2.Sign(aws.Auth{"access", "secret"}, "GET", "/", params, "sdb.amazonaws.com")
1025- expected := "okj96/5ucWBSc1uR2zXVfm6mDHtgfNv657rRtt/aunQ="
1026- c.Assert(params["Signature"], Equals, expected)
1027-}
1028
1029=== modified file 'ec2/subnets_test.go'
1030--- ec2/subnets_test.go 2014-02-12 16:38:47 +0000
1031+++ ec2/subnets_test.go 2014-08-12 16:51:05 +0000
1032@@ -11,7 +11,7 @@
1033 import (
1034 "launchpad.net/goamz/aws"
1035 "launchpad.net/goamz/ec2"
1036- . "launchpad.net/gocheck"
1037+ . "gopkg.in/check.v1"
1038 "time"
1039 )
1040
1041
1042=== modified file 'ec2/vpc_test.go'
1043--- ec2/vpc_test.go 2014-02-12 13:58:45 +0000
1044+++ ec2/vpc_test.go 2014-08-12 16:51:05 +0000
1045@@ -11,7 +11,7 @@
1046 import (
1047 "launchpad.net/goamz/aws"
1048 "launchpad.net/goamz/ec2"
1049- . "launchpad.net/gocheck"
1050+ . "gopkg.in/check.v1"
1051 "time"
1052 )
1053
1054
1055=== modified file 'exp/mturk/mturk_test.go'
1056--- exp/mturk/mturk_test.go 2013-05-23 02:56:41 +0000
1057+++ exp/mturk/mturk_test.go 2014-08-12 16:51:05 +0000
1058@@ -4,7 +4,7 @@
1059 "launchpad.net/goamz/aws"
1060 "launchpad.net/goamz/exp/mturk"
1061 "launchpad.net/goamz/testutil"
1062- . "launchpad.net/gocheck"
1063+ . "gopkg.in/check.v1"
1064 "net/url"
1065 "testing"
1066 )
1067
1068=== modified file 'exp/mturk/sign_test.go'
1069--- exp/mturk/sign_test.go 2012-05-03 17:12:28 +0000
1070+++ exp/mturk/sign_test.go 2014-08-12 16:51:05 +0000
1071@@ -3,7 +3,7 @@
1072 import (
1073 "launchpad.net/goamz/aws"
1074 "launchpad.net/goamz/exp/mturk"
1075- . "launchpad.net/gocheck"
1076+ . "gopkg.in/check.v1"
1077 )
1078
1079 // Mechanical Turk REST authentication docs: http://goo.gl/wrzfn
1080
1081=== modified file 'exp/sdb/sdb_test.go'
1082--- exp/sdb/sdb_test.go 2013-05-23 02:56:41 +0000
1083+++ exp/sdb/sdb_test.go 2014-08-12 16:51:05 +0000
1084@@ -4,7 +4,7 @@
1085 "launchpad.net/goamz/aws"
1086 "launchpad.net/goamz/exp/sdb"
1087 "launchpad.net/goamz/testutil"
1088- . "launchpad.net/gocheck"
1089+ . "gopkg.in/check.v1"
1090 "testing"
1091 )
1092
1093@@ -23,7 +23,7 @@
1094 func (s *S) SetUpSuite(c *C) {
1095 testServer.Start()
1096 auth := aws.Auth{"abc", "123"}
1097- s.sdb = sdb.New(auth, aws.Region{SDBEndpoint: testServer.URL})
1098+ s.sdb = sdb.New(auth, aws.Region{SDBEndpoint: testServer.URL, Sign: aws.SignV2})
1099 }
1100
1101 func (s *S) TearDownSuite(c *C) {
1102
1103=== modified file 'exp/sdb/sign_test.go'
1104--- exp/sdb/sign_test.go 2012-03-09 15:34:56 +0000
1105+++ exp/sdb/sign_test.go 2014-08-12 16:51:05 +0000
1106@@ -3,7 +3,7 @@
1107 import (
1108 "launchpad.net/goamz/aws"
1109 "launchpad.net/goamz/exp/sdb"
1110- . "launchpad.net/gocheck"
1111+ . "gopkg.in/check.v1"
1112 )
1113
1114 // SimpleDB ReST authentication docs: http://goo.gl/CaY81
1115
1116=== modified file 'exp/sns/sns_test.go'
1117--- exp/sns/sns_test.go 2013-05-23 02:56:41 +0000
1118+++ exp/sns/sns_test.go 2014-08-12 16:51:05 +0000
1119@@ -4,7 +4,7 @@
1120 "launchpad.net/goamz/aws"
1121 "launchpad.net/goamz/exp/sns"
1122 "launchpad.net/goamz/testutil"
1123- . "launchpad.net/gocheck"
1124+ . "gopkg.in/check.v1"
1125 "testing"
1126 )
1127
1128@@ -23,7 +23,7 @@
1129 func (s *S) SetUpSuite(c *C) {
1130 testServer.Start()
1131 auth := aws.Auth{"abc", "123"}
1132- s.sns = sns.New(auth, aws.Region{SNSEndpoint: testServer.URL})
1133+ s.sns = sns.New(auth, aws.Region{SNSEndpoint: testServer.URL, Sign: aws.SignV2})
1134 }
1135
1136 func (s *S) TearDownSuite(c *C) {
1137
1138=== modified file 'iam/iam_test.go'
1139--- iam/iam_test.go 2013-05-23 02:56:41 +0000
1140+++ iam/iam_test.go 2014-08-12 16:51:05 +0000
1141@@ -4,7 +4,7 @@
1142 "launchpad.net/goamz/aws"
1143 "launchpad.net/goamz/iam"
1144 "launchpad.net/goamz/testutil"
1145- . "launchpad.net/gocheck"
1146+ . "gopkg.in/check.v1"
1147 "strings"
1148 "testing"
1149 )
1150@@ -24,7 +24,7 @@
1151 func (s *S) SetUpSuite(c *C) {
1152 testServer.Start()
1153 auth := aws.Auth{"abc", "123"}
1154- s.iam = iam.New(auth, aws.Region{IAMEndpoint: testServer.URL})
1155+ s.iam = iam.New(auth, aws.Region{IAMEndpoint: testServer.URL, Sign: aws.SignV2})
1156 }
1157
1158 func (s *S) TearDownSuite(c *C) {
1159
1160=== modified file 'iam/iami_test.go'
1161--- iam/iami_test.go 2013-03-02 02:11:38 +0000
1162+++ iam/iami_test.go 2014-08-12 16:51:05 +0000
1163@@ -4,7 +4,7 @@
1164 "launchpad.net/goamz/aws"
1165 "launchpad.net/goamz/iam"
1166 "launchpad.net/goamz/testutil"
1167- . "launchpad.net/gocheck"
1168+ . "gopkg.in/check.v1"
1169 "net/url"
1170 )
1171
1172
1173=== modified file 'iam/iamt_test.go'
1174--- iam/iamt_test.go 2012-10-10 21:18:36 +0000
1175+++ iam/iamt_test.go 2014-08-12 16:51:05 +0000
1176@@ -4,7 +4,7 @@
1177 "launchpad.net/goamz/aws"
1178 "launchpad.net/goamz/iam"
1179 "launchpad.net/goamz/iam/iamtest"
1180- . "launchpad.net/gocheck"
1181+ . "gopkg.in/check.v1"
1182 )
1183
1184 // LocalServer represents a local ec2test fake server.
1185@@ -20,7 +20,7 @@
1186 c.Assert(srv, NotNil)
1187
1188 s.srv = srv
1189- s.region = aws.Region{IAMEndpoint: srv.URL()}
1190+ s.region = aws.Region{IAMEndpoint: srv.URL(), Sign: aws.SignV2}
1191 }
1192
1193 // LocalServerSuite defines tests that will run
1194
1195=== modified file 's3/multi_test.go'
1196--- s3/multi_test.go 2013-08-15 13:18:02 +0000
1197+++ s3/multi_test.go 2014-08-12 16:51:05 +0000
1198@@ -5,7 +5,7 @@
1199 "io"
1200 "io/ioutil"
1201 "launchpad.net/goamz/s3"
1202- . "launchpad.net/gocheck"
1203+ . "gopkg.in/check.v1"
1204 "strings"
1205 )
1206
1207
1208=== modified file 's3/s3_test.go'
1209--- s3/s3_test.go 2013-08-15 13:18:02 +0000
1210+++ s3/s3_test.go 2014-08-12 16:51:05 +0000
1211@@ -9,7 +9,7 @@
1212 "launchpad.net/goamz/aws"
1213 "launchpad.net/goamz/s3"
1214 "launchpad.net/goamz/testutil"
1215- . "launchpad.net/gocheck"
1216+ . "gopkg.in/check.v1"
1217 "time"
1218 )
1219
1220@@ -28,7 +28,7 @@
1221 func (s *S) SetUpSuite(c *C) {
1222 testServer.Start()
1223 auth := aws.Auth{"abc", "123"}
1224- s.s3 = s3.New(auth, aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL})
1225+ s.s3 = s3.New(auth, aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL, Sign: aws.SignV2})
1226 }
1227
1228 func (s *S) TearDownSuite(c *C) {
1229
1230=== modified file 's3/s3i_test.go'
1231--- s3/s3i_test.go 2013-02-13 12:20:38 +0000
1232+++ s3/s3i_test.go 2014-08-12 16:51:05 +0000
1233@@ -11,7 +11,7 @@
1234 "launchpad.net/goamz/aws"
1235 "launchpad.net/goamz/s3"
1236 "launchpad.net/goamz/testutil"
1237- . "launchpad.net/gocheck"
1238+ . "gopkg.in/check.v1"
1239 "net"
1240 "sort"
1241 "time"
1242
1243=== modified file 's3/s3t_test.go'
1244--- s3/s3t_test.go 2013-02-01 05:55:19 +0000
1245+++ s3/s3t_test.go 2014-08-12 16:51:05 +0000
1246@@ -4,7 +4,7 @@
1247 "launchpad.net/goamz/aws"
1248 "launchpad.net/goamz/s3"
1249 "launchpad.net/goamz/s3/s3test"
1250- . "launchpad.net/gocheck"
1251+ . "gopkg.in/check.v1"
1252 )
1253
1254 type LocalServer struct {
1255@@ -24,6 +24,7 @@
1256 Name: "faux-region-1",
1257 S3Endpoint: srv.URL(),
1258 S3LocationConstraint: true, // s3test server requires a LocationConstraint
1259+ Sign: aws.SignV2,
1260 }
1261 }
1262
1263
1264=== modified file 's3/sign_test.go'
1265--- s3/sign_test.go 2012-07-16 00:36:17 +0000
1266+++ s3/sign_test.go 2014-08-12 16:51:05 +0000
1267@@ -3,7 +3,7 @@
1268 import (
1269 "launchpad.net/goamz/aws"
1270 "launchpad.net/goamz/s3"
1271- . "launchpad.net/gocheck"
1272+ . "gopkg.in/check.v1"
1273 )
1274
1275 // S3 ReST authentication docs: http://goo.gl/G1LrK
1276
1277=== modified file 'testutil/http.go'
1278--- testutil/http.go 2013-05-23 03:13:02 +0000
1279+++ testutil/http.go 2014-08-12 16:51:05 +0000
1280@@ -4,6 +4,7 @@
1281 "bytes"
1282 "fmt"
1283 "io/ioutil"
1284+ "log"
1285 "net"
1286 "net/http"
1287 "net/url"
1288@@ -27,7 +28,12 @@
1289 }
1290
1291 func NewHTTPServer() *HTTPServer {
1292- return &HTTPServer{URL: "http://localhost:4444", Timeout: 5 * time.Second}
1293+ s := &HTTPServer{
1294+ URL: "http://localhost:0",
1295+ Timeout: 5 * time.Second,
1296+ }
1297+
1298+ return s
1299 }
1300
1301 type ResponseFunc func(path string) Response
1302@@ -43,10 +49,16 @@
1303 if err != nil {
1304 panic(err)
1305 }
1306+
1307 s.listener, err = net.Listen("tcp", u.Host)
1308 if err != nil {
1309 panic(err)
1310 }
1311+
1312+ // The OS has found an open port; reset the URL to reflect the
1313+ // actual port.
1314+ s.URL = fmt.Sprintf("http://%s", s.listener.Addr().String())
1315+ log.Printf("Listening on %v\n", s.URL)
1316 go http.Serve(s.listener, s)
1317
1318 s.Response(203, nil, "")
1319@@ -56,6 +68,7 @@
1320 if err == nil && resp.StatusCode == 203 {
1321 break
1322 }
1323+ log.Printf("Waiting on addr: %s\n", s.URL)
1324 time.Sleep(1e8)
1325 }
1326 s.WaitRequest() // Consume dummy request.
1327@@ -70,6 +83,7 @@
1328 panic(err)
1329 }
1330 s.listener = nil
1331+ s.started = false
1332 }
1333
1334 // Flush discards all pending requests and responses.
1335
1336=== modified file 'testutil/suite.go'
1337--- testutil/suite.go 2013-01-31 14:52:05 +0000
1338+++ testutil/suite.go 2014-08-12 16:51:05 +0000
1339@@ -3,7 +3,7 @@
1340 import (
1341 "flag"
1342 "launchpad.net/goamz/aws"
1343- . "launchpad.net/gocheck"
1344+ . "gopkg.in/check.v1"
1345 )
1346
1347 // Amazon must be used by all tested packages to determine whether to

Subscribers

People subscribed via source and target branches