package storage // Copyright 2017 Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import ( "encoding/base64" "net/http" chk "gopkg.in/check.v1" ) type AuthorizationSuite struct{} var _ = chk.Suite(&AuthorizationSuite{}) func (a *AuthorizationSuite) Test_addAuthorizationHeader(c *chk.C) { cli, err := NewBasicClient(dummyStorageAccount, dummyMiniStorageKey) c.Assert(err, chk.IsNil) cli.UseSharedKeyLite = true tableCli := cli.GetTableService() headers := map[string]string{ "Accept-Charset": "UTF-8", headerContentType: "application/json", headerXmsDate: "Wed, 23 Sep 2015 16:40:05 GMT", headerContentLength: "0", headerXmsVersion: "2015-02-21", "Accept": "application/json;odata=nometadata", } url := "https://golangrocksonazure.table.core.windows.net/tquery()" headers, err = tableCli.client.addAuthorizationHeader("", url, headers, tableCli.auth) c.Assert(err, chk.IsNil) c.Assert(headers[headerAuthorization], chk.Equals, "SharedKeyLite golangrocksonazure:NusXSFXAvHqr6EQNXnZZ50CvU1sX0iP/FFDHehnixLc=") } func (a *AuthorizationSuite) Test_getSharedKey(c *chk.C) { // Shared Key Lite for Tables cli, err := NewBasicClient(dummyStorageAccount, dummyMiniStorageKey) c.Assert(err, chk.IsNil) headers := map[string]string{ "Accept-Charset": "UTF-8", headerContentType: "application/json", headerXmsDate: "Wed, 23 Sep 2015 16:40:05 GMT", headerContentLength: "0", headerXmsVersion: "2015-02-21", "Accept": "application/json;odata=nometadata", } url := "https://golangrocksonazure.table.core.windows.net/tquery()" key, err := cli.getSharedKey("", url, headers, sharedKeyLiteForTable) c.Assert(err, chk.IsNil) c.Assert(key, chk.Equals, "SharedKeyLite golangrocksonazure:NusXSFXAvHqr6EQNXnZZ50CvU1sX0iP/FFDHehnixLc=") } func (a *AuthorizationSuite) Test_buildCanonicalizedResource(c *chk.C) { cli, err := NewBasicClient(dummyStorageAccount, dummyMiniStorageKey) c.Assert(err, chk.IsNil) type test struct { url string auth authentication expected string sas bool } tests := []test{ // Shared Key {"https://golangrocksonazure.blob.core.windows.net/path?a=b&c=d", sharedKey, "/golangrocksonazure/path\na:b\nc:d", false}, {"https://golangrocksonazure.blob.core.windows.net/?comp=list", sharedKey, "/golangrocksonazure/\ncomp:list", false}, {"https://golangrocksonazure.blob.core.windows.net/cnt/blob", sharedKey, "/golangrocksonazure/cnt/blob", false}, {"https://golangrocksonazure.blob.core.windows.net/cnt/bl ob", sharedKey, "/golangrocksonazure/cnt/bl%20ob", false}, {"https://golangrocksonazure.blob.core.windows.net/c nt/blob", sharedKey, "/golangrocksonazure/c%20nt/blob", false}, {"https://golangrocksonazure.blob.core.windows.net/cnt/blob%3F%23%5B%5D%21$&%27%28%29%2A blob", sharedKey, "/golangrocksonazure/cnt/blob%3F%23%5B%5D%21$&%27%28%29%2A%20blob", false}, {"https://golangrocksonazure.blob.core.windows.net/cnt/blob-._~:,@;+=blob", sharedKey, "/golangrocksonazure/cnt/blob-._~:,@;+=blob", false}, {"https://golangrocksonazure.blob.core.windows.net/c nt/blob-._~:%3F%23%5B%5D@%21$&%27%28%29%2A,;+=/blob", sharedKey, "/golangrocksonazure/c%20nt/blob-._~:%3F%23%5B%5D@%21$&%27%28%29%2A,;+=/blob", false}, // Shared Key Lite for Table {"https://golangrocksonazure.table.core.windows.net/mytable", sharedKeyLiteForTable, "/golangrocksonazure/mytable", false}, {"https://golangrocksonazure.table.core.windows.net/mytable?comp=acl", sharedKeyLiteForTable, "/golangrocksonazure/mytable?comp=acl", false}, {"https://golangrocksonazure.table.core.windows.net/mytable?comp=acl&timeout=10", sharedKeyForTable, "/golangrocksonazure/mytable?comp=acl", false}, {"https://golangrocksonazure.table.core.windows.net/mytable(PartitionKey='pkey',RowKey='rowkey%3D')", sharedKeyForTable, "/golangrocksonazure/mytable(PartitionKey='pkey',RowKey='rowkey%3D')", false}, // Canonicalized Resource with SAS {"https://golangrocksonazure.blob.core.windows.net/cnt/blob", sharedKey, "/golangrocksonazure/cnt/blob", true}, } for _, t := range tests { out, err := cli.buildCanonicalizedResource(t.url, t.auth, t.sas) c.Assert(err, chk.IsNil) c.Assert(out, chk.Equals, t.expected) } eCli, err := NewEmulatorClient() c.Assert(err, chk.IsNil) eTests := []test{ {"http://127.0.0.1:10000/devstoreaccount1/cnt/blob", sharedKey, "/devstoreaccount1/cnt/blob", true}, {"http://127.0.0.1:10000/devstoreaccount1/cnt/blob", sharedKey, "/devstoreaccount1/devstoreaccount1/cnt/blob", false}, } for _, t := range eTests { out, err := eCli.buildCanonicalizedResource(t.url, t.auth, t.sas) c.Assert(err, chk.IsNil) c.Assert(out, chk.Equals, t.expected) } } func (a *AuthorizationSuite) Test_buildCanonicalizedString(c *chk.C) { var tests = []struct { verb string headers map[string]string canonicalizedResource string auth authentication out string }{ { // Shared Key verb: http.MethodGet, headers: map[string]string{ headerXmsDate: "Sun, 11 Oct 2009 21:49:13 GMT", headerXmsVersion: "2009-09-19", }, canonicalizedResource: "/myaccount/ mycontainer\ncomp:metadata\nrestype:container\ntimeout:20", auth: sharedKey, out: "GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Sun, 11 Oct 2009 21:49:13 GMT\nx-ms-version:2009-09-19\n/myaccount/ mycontainer\ncomp:metadata\nrestype:container\ntimeout:20", }, { // Shared Key for Tables verb: http.MethodPut, headers: map[string]string{ headerContentType: "text/plain; charset=UTF-8", headerDate: "Sun, 11 Oct 2009 19:52:39 GMT", }, canonicalizedResource: "/testaccount1/Tables", auth: sharedKeyForTable, out: "PUT\n\ntext/plain; charset=UTF-8\nSun, 11 Oct 2009 19:52:39 GMT\n/testaccount1/Tables", }, { // Shared Key Lite verb: http.MethodPut, headers: map[string]string{ headerContentType: "text/plain; charset=UTF-8", headerXmsDate: "Sun, 20 Sep 2009 20:36:40 GMT", "x-ms-meta-m1": "v1", "x-ms-meta-m2": "v2", }, canonicalizedResource: "/testaccount1/mycontainer/hello.txt", auth: sharedKeyLite, out: "PUT\n\ntext/plain; charset=UTF-8\n\nx-ms-date:Sun, 20 Sep 2009 20:36:40 GMT\nx-ms-meta-m1:v1\nx-ms-meta-m2:v2\n/testaccount1/mycontainer/hello.txt", }, { // Shared Key Lite for Tables verb: "", headers: map[string]string{ headerDate: "Sun, 11 Oct 2009 19:52:39 GMT", }, canonicalizedResource: "/testaccount1/Tables", auth: sharedKeyLiteForTable, out: "Sun, 11 Oct 2009 19:52:39 GMT\n/testaccount1/Tables", }, } for _, t := range tests { canonicalizedString, err := buildCanonicalizedString(t.verb, t.headers, t.canonicalizedResource, t.auth) c.Assert(err, chk.IsNil) c.Assert(canonicalizedString, chk.Equals, t.out) } } func (a *AuthorizationSuite) Test_buildCanonicalizedHeader(c *chk.C) { type test struct { headers map[string]string expected string } tests := []test{ {map[string]string{}, ""}, {map[string]string{ "x-ms-lol": "rofl"}, "x-ms-lol:rofl"}, {map[string]string{ "lol:": "rofl"}, ""}, {map[string]string{ "lol:": "rofl", "x-ms-lol": "rofl"}, "x-ms-lol:rofl"}, {map[string]string{ "x-ms-version": "9999-99-99", "x-ms-blob-type": "BlockBlob"}, "x-ms-blob-type:BlockBlob\nx-ms-version:9999-99-99"}} for _, i := range tests { c.Assert(buildCanonicalizedHeader(i.headers), chk.Equals, i.expected) } } func (a *AuthorizationSuite) Test_createAuthorizationHeader(c *chk.C) { cli, err := NewBasicClient(dummyStorageAccount, base64.StdEncoding.EncodeToString([]byte("bar"))) c.Assert(err, chk.IsNil) canonicalizedString := `foobarzoo` c.Assert(cli.createAuthorizationHeader(canonicalizedString, sharedKey), chk.Equals, `SharedKey golangrocksonazure:h5U0ATVX6SpbFX1H6GNuxIMeXXCILLoIvhflPtuQZ30=`) c.Assert(cli.createAuthorizationHeader(canonicalizedString, sharedKeyLite), chk.Equals, `SharedKeyLite golangrocksonazure:h5U0ATVX6SpbFX1H6GNuxIMeXXCILLoIvhflPtuQZ30=`) } func (a *AuthorizationSuite) Test_allSharedKeys(c *chk.C) { cli := getBasicClient(c) rec := cli.appendRecorder(c) defer rec.Stop() blobCli := cli.GetBlobService() tableCli := cli.GetTableService() cnt1 := blobCli.GetContainerReference(containerName(c, "1")) cnt2 := blobCli.GetContainerReference(containerName(c, "2")) // Shared Key c.Assert(blobCli.auth, chk.Equals, sharedKey) c.Assert(cnt1.Create(nil), chk.IsNil) c.Assert(cnt1.Delete(nil), chk.IsNil) // Shared Key for Tables c.Assert(tableCli.auth, chk.Equals, sharedKeyForTable) table1 := tableCli.GetTableReference(tableName(c, "1")) c.Assert(table1.tsc.auth, chk.Equals, sharedKeyForTable) c.Assert(table1.Create(30, EmptyPayload, nil), chk.IsNil) c.Assert(table1.Delete(30, nil), chk.IsNil) // Change to Lite cli.UseSharedKeyLite = true blobCli = cli.GetBlobService() tableCli = cli.GetTableService() // Shared Key Lite c.Assert(blobCli.auth, chk.Equals, sharedKeyLite) c.Assert(cnt2.Create(nil), chk.IsNil) c.Assert(cnt2.Delete(nil), chk.IsNil) // Shared Key Lite for Tables tableCli = cli.GetTableService() c.Assert(tableCli.auth, chk.Equals, sharedKeyLiteForTable) table2 := tableCli.GetTableReference(tableName(c, "2")) c.Assert(table2.tsc.auth, chk.Equals, sharedKeyLiteForTable) c.Assert(table2.Create(30, EmptyPayload, nil), chk.IsNil) c.Assert(table2.Delete(30, nil), chk.IsNil) }