OSDN Git Service

部分文字列に対するアサーションをAssert.StartsWithで行う (xUnit2009)
[opentween/open-tween.git] / OpenTween.Tests / Connection / OAuthUtilityTest.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2016 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
4 //
5 // This file is part of OpenTween.
6 //
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
10 // any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 // for more details.
16 //
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
21
22 using System;
23 using System.Collections.Generic;
24 using System.Linq;
25 using System.Security.Cryptography;
26 using System.Text;
27 using System.Threading.Tasks;
28 using Xunit;
29
30 namespace OpenTween.Connection
31 {
32     public class OAuthUtilityTest
33     {
34         [Fact]
35         public void GetOAuthParameter_Test()
36         {
37             var param = OAuthUtility.GetOAuthParameter("ConsumerKey", "Token");
38
39             Assert.Equal("ConsumerKey", param["oauth_consumer_key"]);
40             Assert.Equal("HMAC-SHA1", param["oauth_signature_method"]);
41
42             var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0);
43             var unixTimeNow = Math.Ceiling((DateTime.UtcNow - unixEpoch).TotalSeconds);
44             Assert.InRange(long.Parse(param["oauth_timestamp"]), unixTimeNow - 5, unixTimeNow);
45
46             Assert.NotEmpty(param["oauth_nonce"]);
47             Assert.Equal("1.0", param["oauth_version"]);
48             Assert.Equal("Token", param["oauth_token"]);
49         }
50
51         [Fact]
52         public void CreateSignature_Test()
53         {
54             // GET http://example.com/hoge?aaa=foo に対する署名を生成
55             // 実際の param は oauth_consumer_key などのパラメーターが加わった状態で渡される
56             var oauthSignature = OAuthUtility.CreateSignature("ConsumerSecret", "TokenSecret",
57                 "GET", new Uri("http://example.com/hoge"), new Dictionary<string, string> { ["aaa"] = "foo" });
58
59             var expectSignatureBase = "GET&http%3A%2F%2Fexample.com%2Fhoge&aaa%3Dfoo";
60             var expectSignatureKey = "ConsumerSecret&TokenSecret";
61
62             using (var hmacsha1 = new HMACSHA1(Encoding.ASCII.GetBytes(expectSignatureKey)))
63             {
64                 var expectSignature = Convert.ToBase64String(hmacsha1.ComputeHash(Encoding.ASCII.GetBytes(expectSignatureBase)));
65                 Assert.Equal(expectSignature, oauthSignature);
66             }
67         }
68
69         [Fact]
70         public void CreateSignature_NormarizeParametersTest()
71         {
72             // GET http://example.com/hoge?aaa=foo&bbb=bar に対する署名を生成
73             // 複数のパラメータが渡される場合は name 順でソートされる
74             var oauthSignature = OAuthUtility.CreateSignature("ConsumerSecret", "TokenSecret",
75                 "GET", new Uri("http://example.com/hoge"), new Dictionary<string, string> {
76                     ["bbb"] = "bar",
77                     ["aaa"] = "foo",
78                 });
79
80             var expectSignatureBase = "GET&http%3A%2F%2Fexample.com%2Fhoge&aaa%3Dfoo%26bbb%3Dbar";
81             var expectSignatureKey = "ConsumerSecret&TokenSecret";
82
83             using (var hmacsha1 = new HMACSHA1(Encoding.ASCII.GetBytes(expectSignatureKey)))
84             {
85                 var expectSignature = Convert.ToBase64String(hmacsha1.ComputeHash(Encoding.ASCII.GetBytes(expectSignatureBase)));
86                 Assert.Equal(expectSignature, oauthSignature);
87             }
88         }
89
90         [Fact]
91         public void CreateSignature_EmptyTokenSecretTest()
92         {
93             // GET http://example.com/hoge?aaa=foo に対する署名を生成
94             // リクエストトークンの発行時は tokenSecret が空の状態で署名を生成することになる
95             var oauthSignature = OAuthUtility.CreateSignature("ConsumerSecret", null,
96                 "GET", new Uri("http://example.com/hoge"), new Dictionary<string, string> { ["aaa"] = "foo" });
97
98             var expectSignatureBase = "GET&http%3A%2F%2Fexample.com%2Fhoge&aaa%3Dfoo";
99             var expectSignatureKey = "ConsumerSecret&"; // 末尾の & は除去されない
100
101             using (var hmacsha1 = new HMACSHA1(Encoding.ASCII.GetBytes(expectSignatureKey)))
102             {
103                 var expectSignature = Convert.ToBase64String(hmacsha1.ComputeHash(Encoding.ASCII.GetBytes(expectSignatureBase)));
104                 Assert.Equal(expectSignature, oauthSignature);
105             }
106         }
107
108         [Fact]
109         public void CreateAuthorization_Test()
110         {
111             var authorization = OAuthUtility.CreateAuthorization(
112                 "GET", new Uri("http://example.com/hoge"), new Dictionary<string, string> { ["aaa"] = "hoge" },
113                 "ConsumerKey", "ConsumerSecret", "AccessToken", "AccessSecret", "Realm");
114
115             Assert.StartsWith("OAuth ", authorization, StringComparison.Ordinal);
116
117             var parsedParams = authorization.Substring(6).Split(',')
118                 .Where(x => !string.IsNullOrEmpty(x))
119                 .Select(x => x.Split(new[] { '=' }, 2))
120                 .ToDictionary(x => x[0], x => x[1].Substring(1, x[1].Length - 2)); // x[1] は前後の「"」を除去する
121
122             var expectAuthzParamKeys = new[] { "realm", "oauth_consumer_key", "oauth_nonce", "oauth_signature_method",
123                 "oauth_timestamp", "oauth_token", "oauth_version", "oauth_signature" };
124             Assert.Equal(expectAuthzParamKeys, parsedParams.Keys, AnyOrderComparer<string>.Instance);
125
126             Assert.Equal("Realm", parsedParams["realm"]);
127
128             // Signature Base Strings には realm を含めない
129             var expectSignatureBase = "GET&http%3A%2F%2Fexample.com%2Fhoge&" +
130                 "aaa%3Dhoge%26" +
131                 "oauth_consumer_key%3DConsumerKey%26" +
132                 $"oauth_nonce%3D{parsedParams["oauth_nonce"]}%26" +
133                 "oauth_signature_method%3DHMAC-SHA1%26" +
134                 $"oauth_timestamp%3D{parsedParams["oauth_timestamp"]}%26" +
135                 "oauth_token%3DAccessToken%26" +
136                 "oauth_version%3D1.0";
137
138             var expectSignatureKey = "ConsumerSecret&AccessSecret";
139
140             using (var hmacsha1 = new HMACSHA1(Encoding.ASCII.GetBytes(expectSignatureKey)))
141             {
142                 var expectSignature = Convert.ToBase64String(hmacsha1.ComputeHash(Encoding.ASCII.GetBytes(expectSignatureBase)));
143                 Assert.Equal(expectSignature, Uri.UnescapeDataString(parsedParams["oauth_signature"]));
144             }
145         }
146     }
147 }