MSDN にある程度記述があるのですが、読んでいてもいまいちピンとこないというかさっぱりわかりませんw 色々と web 上の資料やサンプルコードを探しているうちに、海外サイトで丁度良いサンプルソースがあったのでこれを VB 用に移植したものを紹介します。
1: Protected Overridable Function CreateAuthStrings(ByVal wq As WebRequest) As String
2: Dim headerStrings As New System.Text.StringBuilder
3:
4: headerStrings.Append(wq.Method + ControlChars.Lf) 'HTTP Verb
5: headerStrings.Append(ControlChars.Lf) 'Content-Encoding
6: headerStrings.Append(ControlChars.Lf) 'Content-Language
7: headerStrings.Append(ControlChars.Lf) 'Content-Length
8: headerStrings.Append(ControlChars.Lf) 'Content-MD5
9: headerStrings.Append(wq.ContentType + ControlChars.Lf) 'Content-Type
10:
11: headerStrings.Append(ControlChars.Lf) 'Date
12: headerStrings.Append(ControlChars.Lf) 'If-Modified-Since
13: headerStrings.Append(ControlChars.Lf) 'If-Match
14: headerStrings.Append(ControlChars.Lf) 'If-None-Match
15: headerStrings.Append(ControlChars.Lf) 'If-Unmodified-Since
16: headerStrings.Append(ControlChars.Lf) 'Range
17:
18: 'CanonicalizedHeaders
19: headerStrings.Append(GetCanonicalizedHeaders(wq))
20: 'CanonicalizedResource
21: headerStrings.Append(GetCanonicalizedResource(wq.RequestUri, Me.Account))
22:
23: ' UTF8 -> Byte -> Base64
24: Dim headerUTF8 = System.Text.Encoding.UTF8.GetBytes(headerStrings.ToString())
25: Dim skey = Convert.FromBase64String(Me.SharedKey)
26: Using hmacSHA256 As New System.Security.Cryptography.HMACSHA256(skey)
27: Return Convert.ToBase64String(hmacSHA256.ComputeHash(headerUTF8))
28: End Using
29:
30: End Function
まず SharedKey を組み立てるのに必要な要素ですが、リクエストのヘッダに設定される各値、リクエスト先の Uri アドレス、ストレージのアカウント名などが必要です。上記サンプルソースは後日公開予定のストレージ関係アクティビティの一部ですが、大まかなイメージはつかめると思います。
この中で最も困っていたのが CanonicalizedHeaders と CanonicalizedResource です。CanonicalizedHeaders はリクエストヘッダに設定されている一部の値を編集したもので、CanonicalizedResource はリクエスト Uri (パラメータを含む)を編集したものとなります。まずCanonicalizedHeaders を作成するロジックは次のような形になります。
1: Private Function GetCanonicalizedHeaders(ByVal request As HttpWebRequest) As String
2: Dim headerList As New List(Of String)
3: Dim result As New StringBuilder()
4: 'x-ms- で始まるヘッダの抽出
5: For Each headValue As String In request.Headers.Keys
6: If headValue.ToLowerInvariant().StartsWith("x-ms-", StringComparison.Ordinal) Then
7: headerList.Add(headValue.ToLowerInvariant())
8: End If
9: Next headValue
10: headerList.Sort()
11: '抽出したヘッダの編集
12: For Each headValue In headerList
13: Dim builder As New StringBuilder(headValue)
14: Dim separateChar As String = ":"
15: For Each str4 In GetHeaderValues(request.Headers, headValue)
16: builder.Append(separateChar)
17: builder.Append(str4.Replace(ControlChars.CrLf, String.Empty))
18: separateChar = ","
19: Next str4
20: result.Append(builder.ToString())
21: result.Append(ControlChars.Lf)
22: Next headValue
23:
24: Return result.ToString()
25: End Function
26:
27: Private Function GetHeaderValues(ByVal headers As WebHeaderCollection, ByVal headerName As String) As List(Of String)
28: 'ヘッダ値の抽出
29: Dim list As New List(Of String)
30: Dim values As String() = headers.GetValues(headerName)
31: If Not values Is Nothing Then
32: For Each str As String In values
33: list.Add(str.TrimStart(New Char() {}))
34: Next str
35: End If
36: Return list
37: End Function
この中で \n と記載されている部分ですが、これは Windows 上における改行 ( CR-LF ) ではなく LF となりますので、 ControlChars.LF でプログラム中は処理する必要があります。x-ms-date:Fri, 20 May 2011 10:32:11 GMT\nx-ms-version:2009-09-19\n
もう一つの CanonicalizedResource を編集するロジックは次のようになります。
1: Private Function GetCanonicalizedResource(ByVal address As Uri, ByVal accountName As String) As String
2: Dim resultbuilder As New StringBuilder("/")
3: resultbuilder.Append(accountName)
4: resultbuilder.Append(address.AbsolutePath)
5:
6: Dim str As New CanonicalizedString(resultbuilder.ToString())
7: Dim values = System.Web.HttpUtility.ParseQueryString(address.Query)
8: Dim values2 As New WebHeaderCollection
9: For Each str2 As String In values.Keys
10: Dim list As New ArrayList(values.GetValues(str2))
11: list.Sort()
12: Dim builder2 As New StringBuilder()
13: For Each obj2 As Object In list
14: If builder2.Length > 0 Then
15: builder2.Append(",")
16: End If
17: builder2.Append(obj2.ToString())
18: Next obj2
19: If (str2 Is Nothing) Then
20: values2.Add(str2, builder2.ToString())
21: Else
22: values2.Add(str2.ToLowerInvariant(), builder2.ToString())
23: End If
24: Next str2
25:
26: Dim list2 As New ArrayList(values2.AllKeys)
27: list2.Sort()
28: For Each str3 As String In list2
29: Dim builder3 As New StringBuilder(String.Empty)
30: builder3.Append(str3)
31: builder3.Append(":")
32: builder3.Append(values2(str3))
33: str.AppendCanonicalizedElement(builder3.ToString())
34: Next str3
35:
36: Return str.Value
37: End Function
38:
39: Friend Class CanonicalizedString
40: ' Fields
41: Private canonicalizedString_Renamed As New StringBuilder()
42:
43: ' Methods
44: Friend Sub New(ByVal initialElement As String)
45: Me.canonicalizedString_Renamed.Append(initialElement)
46: End Sub
47:
48: Friend Sub AppendCanonicalizedElement(ByVal element As String)
49: Me.canonicalizedString_Renamed.Append(ControlChars.Lf)
50: Me.canonicalizedString_Renamed.Append(element)
51: End Sub
52:
53: ' Properties
54: Friend ReadOnly Property Value() As String
55: Get
56: Return Me.canonicalizedString_Renamed.ToString()
57: End Get
58: End Property
59: End Class
このようにして編集した結果を SHA256 アルゴリズムにて暗号化したものが SharedKey 値となります。なお SharedKeyLite という SharedKey を少しばかり簡易にしたものがありますが、行われている処理自体は全く同一で、CanonicalizedHeaders にて対象となるヘッダの数が減るだけだったりします。http://{アカウント名}.blob.core.windows.net/?comp=list↓
/{アカウント名}/\ncomp:list
0 件のコメント:
コメントを投稿