diff --git a/awsauth.go b/awsauth.go index 9f09a82..4da456b 100644 --- a/awsauth.go +++ b/awsauth.go @@ -21,6 +21,8 @@ func Sign(req *http.Request) *http.Request { return Sign2(req) case 4: return Sign4(req) + case -1: + return SignS3(req) } return nil @@ -41,7 +43,7 @@ func Sign4(req *http.Request) *http.Request { signingKey := signingKeyV4(Keys.SecretAccessKey, meta.date, meta.region, meta.service) signature := signatureV4(signingKey, stringToSign) - req.Header.Set("Authorization", buildAuthHeader(signature, meta)) + req.Header.Set("Authorization", buildAuthHeaderV4(signature, meta)) return req } @@ -61,6 +63,11 @@ func Sign2(req *http.Request) *http.Request { return req } +func SignS3(req *http.Request) *http.Request { + // TODO + return req +} + type metadata struct { algorithm string credentialScope string diff --git a/awsauth_test.go b/awsauth_test.go index 6d1d3eb..9c4660c 100644 --- a/awsauth_test.go +++ b/awsauth_test.go @@ -15,7 +15,7 @@ func TestIntegration(t *testing.T) { Convey("A request to S3 should succeed", nil) - Convey("A request to EC2 should succeed", func() { + Convey(`A request to EC2 should succeed `, func() { req := newRequest("GET", "https://ec2.amazonaws.com", url.Values{ "Action": []string{"DescribeInstances"}, }) diff --git a/common.go b/common.go index 9ac10dd..f11dc2c 100644 --- a/common.go +++ b/common.go @@ -4,6 +4,7 @@ import ( "crypto/hmac" "crypto/sha256" "fmt" + "io/ioutil" "net/http" "net/url" "os" @@ -56,6 +57,13 @@ func hashSHA256(content string) string { return fmt.Sprintf("%x", h.Sum(nil)) } +func readAndReplaceBody(req *http.Request) string { + rawPayload, _ := ioutil.ReadAll(req.Body) + payload := string(rawPayload) + req.Body = ioutil.NopCloser(strings.NewReader(payload)) + return payload +} + func concat(delim string, str ...string) string { return strings.Join(str, delim) } diff --git a/common_test.go b/common_test.go index 89a6f78..9c7202e 100644 --- a/common_test.go +++ b/common_test.go @@ -20,7 +20,7 @@ func TestCommonFunctions(t *testing.T) { input := "This is... Sparta!!" actual := hashSHA256(input) - So(actual, ShouldEqual, expecting["Sha256Hash"]) + So(actual, ShouldEqual, "5c81a4ef1172e89b1a9d575f4cd82f4ed20ea9137e61aa7f1ab936291d24e79a") }) Convey("Given a key and contents", t, func() { diff --git a/s3.go b/s3.go new file mode 100644 index 0000000..1afd1ac --- /dev/null +++ b/s3.go @@ -0,0 +1,10 @@ +package awsauth + +import ( + "fmt" +) + +func signatureS3(stringToSign string) string { + fmt.Println("TODO") + return "" +} diff --git a/s3_test.go b/s3_test.go new file mode 100644 index 0000000..5146d01 --- /dev/null +++ b/s3_test.go @@ -0,0 +1,14 @@ +package awsauth + +import ( + //. "github.com/smartystreets/goconvey/convey" + //"net/http" + //"net/url" + "testing" + //"time" +) + +func TestSignatureS3(t *testing.T) { + // http://docs.aws.amazon.com/AmazonS3/2006-03-01/dev/RESTAuthentication.html + +} diff --git a/sign4.go b/sign4.go index 3851fd3..c522188 100644 --- a/sign4.go +++ b/sign4.go @@ -2,9 +2,7 @@ package awsauth import ( "encoding/hex" - "io/ioutil" "net/http" - "strings" ) func hashedCanonicalRequestV4(req *http.Request, meta *metadata) string { @@ -68,14 +66,7 @@ func signingKeyV4(secretKey, date, region, service string) []byte { return kSigning } -func readAndReplaceBody(req *http.Request) string { - rawPayload, _ := ioutil.ReadAll(req.Body) - payload := string(rawPayload) - req.Body = ioutil.NopCloser(strings.NewReader(payload)) - return payload -} - -func buildAuthHeader(signature string, meta *metadata) string { +func buildAuthHeaderV4(signature string, meta *metadata) string { credential := Keys.AccessKeyID + "/" + meta.credentialScope return meta.algorithm + diff --git a/sign4_test.go b/sign4_test.go index 376b921..394f35a 100644 --- a/sign4_test.go +++ b/sign4_test.go @@ -10,9 +10,9 @@ import ( func TestVersion4RequestPreparer(t *testing.T) { Convey("Given a plain request with no custom headers", t, func() { - req := plainRequest(false) + req := test_plainRequestV4(false) - expectedUnsigned := unsignedRequest(true) + expectedUnsigned := test_unsignedRequestV4(true) expectedUnsigned.Header.Set("X-Amz-Date", timestampV4()) Convey("The necessary, default headers should be appended", func() { @@ -26,14 +26,14 @@ func TestVersion4RequestPreparer(t *testing.T) { }) Convey("And a set of credentials", func() { - Keys = testCred + Keys = testCredV4 Convey("It should be signed with an Authorization header", func() { actualSigned := Sign4(req) actual := actualSigned.Header.Get("Authorization") So(actual, ShouldNotBeBlank) - So(actual, ShouldContainSubstring, "Credential="+testCred.AccessKeyID) + So(actual, ShouldContainSubstring, "Credential="+testCredV4.AccessKeyID) So(actual, ShouldContainSubstring, "SignedHeaders=") So(actual, ShouldContainSubstring, "Signature=") So(actual, ShouldContainSubstring, "AWS4") @@ -43,9 +43,9 @@ func TestVersion4RequestPreparer(t *testing.T) { Convey("Given a request with custom, necessary headers", t, func() { Convey("The custom, necessary headers must not be changed", func() { - req := unsignedRequest(true) + req := test_unsignedRequestV4(true) prepareRequestV4(req) - So(req, ShouldResemble, unsignedRequest(true)) + So(req, ShouldResemble, test_unsignedRequestV4(true)) }) }) } @@ -54,37 +54,36 @@ func TestVersion4SigningTasks(t *testing.T) { // http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html Convey("Given a bogus request and credentials from AWS documentation", t, func() { - req := unsignedRequest(true) + req := test_unsignedRequestV4(true) meta := new(metadata) Convey("(Task 1) The canonical request should be built correctly", func() { hashedCanonReq := hashedCanonicalRequestV4(req, meta) - So(hashedCanonReq, ShouldEqual, expecting["CanonicalHash"]) + So(hashedCanonReq, ShouldEqual, expectingV4["CanonicalHash"]) }) Convey("(Task 2) The string to sign should be built correctly", func() { hashedCanonReq := hashedCanonicalRequestV4(req, meta) stringToSign := stringToSignV4(req, hashedCanonReq, meta) - So(stringToSign, ShouldEqual, expecting["StringToSign"]) + So(stringToSign, ShouldEqual, expectingV4["StringToSign"]) }) Convey("(Task 3) The version 4 signed signature should be correct", func() { hashedCanonReq := hashedCanonicalRequestV4(req, meta) stringToSign := stringToSignV4(req, hashedCanonReq, meta) - signature := signatureV4(testSigningKey(), stringToSign) + signature := signatureV4(test_signingKeyV4(), stringToSign) - So(signature, ShouldEqual, expecting["SignatureV4"]) + So(signature, ShouldEqual, expectingV4["SignatureV4"]) }) }) } func TestSignature4Helpers(t *testing.T) { - Convey("The signing key should be properly generated", t, func() { expected := []byte{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} - actual := testSigningKey() + actual := test_signingKeyV4() So(actual, ShouldResemble, expected) }) @@ -95,8 +94,8 @@ func TestSignature4Helpers(t *testing.T) { credentialScope: "20110909/us-east-1/iam/aws4_request", signedHeaders: "content-type;host;x-amz-date", } - expected := expecting["AuthHeader"] + expecting["SignatureV4"] - actual := buildAuthHeader(expecting["SignatureV4"], meta) + expected := expectingV4["AuthHeader"] + expectingV4["SignatureV4"] + actual := buildAuthHeaderV4(expectingV4["SignatureV4"], meta) So(actual, ShouldEqual, expected) }) @@ -121,10 +120,10 @@ func TestSignature4Helpers(t *testing.T) { }) Convey("Given any request with a body", t, func() { - req := plainRequest(false) + req := test_plainRequestV4(false) Convey("Its body should be read and replaced without differences", func() { - expected := requestValues.Encode() + expected := requestValuesV4.Encode() actual1 := readAndReplaceBody(req) So(actual1, ShouldEqual, expected) @@ -135,9 +134,9 @@ func TestSignature4Helpers(t *testing.T) { }) } -func plainRequest(trailingSlash bool) *http.Request { +func test_plainRequestV4(trailingSlash bool) *http.Request { url := "http://iam.amazonaws.com" - body := strings.NewReader(requestValues.Encode()) + body := strings.NewReader(requestValuesV4.Encode()) if trailingSlash { url += "/" @@ -152,32 +151,31 @@ func plainRequest(trailingSlash bool) *http.Request { return req } -func unsignedRequest(trailingSlash bool) *http.Request { - req := plainRequest(trailingSlash) +func test_unsignedRequestV4(trailingSlash bool) *http.Request { + req := test_plainRequestV4(trailingSlash) req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") req.Header.Set("X-Amz-Date", "20110909T233600Z") return req } -func testSigningKey() []byte { - return signingKeyV4(testCred.SecretAccessKey, "20110909", "us-east-1", "iam") +func test_signingKeyV4() []byte { + return signingKeyV4(testCredV4.SecretAccessKey, "20110909", "us-east-1", "iam") } var ( - testCred = &Credentials{ + testCredV4 = &Credentials{ "AKIDEXAMPLE", "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", } - expecting = map[string]string{ + expectingV4 = map[string]string{ "CanonicalHash": "3511de7e95d28ecd39e9513b642aee07e54f4941150d8df8bf94b328ef7e55e2", "StringToSign": "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/iam/aws4_request\n3511de7e95d28ecd39e9513b642aee07e54f4941150d8df8bf94b328ef7e55e2", "SignatureV4": "ced6826de92d2bdeed8f846f0bf508e8559e98e4b0199114b84c54174deb456c", - "Sha256Hash": "5c81a4ef1172e89b1a9d575f4cd82f4ed20ea9137e61aa7f1ab936291d24e79a", "AuthHeader": "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=", } - requestValues = &url.Values{ + requestValuesV4 = &url.Values{ "Action": []string{"ListUsers"}, "Version": []string{"2010-05-08"}, }