OSDN Git Service

2861ef1b340be584136b8b165bec2c38301f24bd
[opentween/open-tween.git] / OpenTween / Connection / HttpConnectionOAuth.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 //           (c) 2008-2011 Moz (@syo68k)
4 //           (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 //           (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 //           (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 //           (c) 2011      spinor (@tplantd) <http://d.hatena.ne.jp/spinor/>
8 // All rights reserved.
9 // 
10 // This file is part of OpenTween.
11 // 
12 // This program is free software; you can redistribute it and/or modify it
13 // under the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 3 of the License, or (at your option)
15 // any later version.
16 // 
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 // for more details. 
21 // 
22 // You should have received a copy of the GNU General Public License along
23 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
24 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
25 // Boston, MA 02110-1301, USA.
26
27 using HttpConnection = OpenTween.HttpConnection;
28 using IHttpConnection = OpenTween.IHttpConnection;
29 using DateTime = System.DateTime;
30 using DateTimeKind = System.DateTimeKind;
31 using Random = System.Random;
32 using HttpWebRequest = System.Net.HttpWebRequest;
33 using HttpStatusCode = System.Net.HttpStatusCode;
34 using Uri = System.Uri;
35 using System.Collections.Generic; // for Dictionary<TKey, TValue>, List<T>, KeyValuePair<TKey, TValue>, SortedDictionary<TKey, TValue>
36 using CallbackDelegate = OpenTween.CallbackDelegate;
37 using StackFrame = System.Diagnostics.StackFrame;
38 using FileInfo = System.IO.FileInfo;
39 using Stream = System.IO.Stream;
40 using HttpWebResponse = System.Net.HttpWebResponse;
41 using WebException = System.Net.WebException;
42 using WebExceptionStatus = System.Net.WebExceptionStatus;
43 using Exception = System.Exception;
44 using NameValueCollection = System.Collections.Specialized.NameValueCollection;
45 using Convert = System.Convert;
46 using InvalidDataException = System.IO.InvalidDataException;
47 using UriBuilder = System.UriBuilder;
48 using Environment = System.Environment;
49 using StringBuilder = System.Text.StringBuilder;
50 using HttpRequestHeader = System.Net.HttpRequestHeader;
51 using HMACSHA1 = System.Security.Cryptography.HMACSHA1;
52 using Encoding = System.Text.Encoding;
53 using System;
54
55 namespace OpenTween
56 {
57         /// <summary>
58         /// OAuth認証を使用するHTTP通信。HMAC-SHA1固定
59         /// </summary>
60         /// <remarks>
61         /// 使用前に認証情報を設定する。認証確認を伴う場合はAuthenticate系のメソッドを、認証不要な場合はInitializeを呼ぶこと。
62         /// </remarks>
63         abstract public class HttpConnectionOAuth : HttpConnection, IHttpConnection
64         {
65                 /// <summary>
66                 /// OAuth署名のoauth_timestamp算出用基準日付(1970/1/1 00:00:00)
67                 /// </summary>
68                 private static readonly DateTime UnixEpoch = new DateTime( 1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified );
69
70                 /// <summary>
71                 /// OAuth署名のoauth_nonce算出用乱数クラス
72                 /// </summary>
73                 private static readonly Random NonceRandom = new Random();
74
75                 /// <summary>
76                 /// OAuthのアクセストークン。永続化可能(ユーザー取り消しの可能性はある)。
77                 /// </summary>
78                 private string token = "";
79
80                 /// <summary>
81                 /// OAuthの署名作成用秘密アクセストークン。永続化可能(ユーザー取り消しの可能性はある)。
82                 /// </summary>
83                 private string tokenSecret = "";
84
85                 /// <summary>
86                 /// OAuthのコンシューマー鍵
87                 /// </summary>
88                 private string consumerKey;
89
90                 /// <summary>
91                 /// OAuthの署名作成用秘密コンシューマーデータ
92                 /// </summary>
93                 protected string consumerSecret;
94
95                 /// <summary>
96                 /// 認証成功時の応答でユーザー情報を取得する場合のキー。設定しない場合は、AuthUsernameもブランクのままとなる
97                 /// </summary>
98                 private string userIdentKey = "";
99
100                 /// <summary>
101                 /// 認証成功時の応答でユーザーID情報を取得する場合のキー。設定しない場合は、AuthUserIdもブランクのままとなる
102                 /// </summary>
103                 private string userIdIdentKey = "";
104
105                 /// <summary>
106                 /// 認証完了時の応答からuserIdentKey情報に基づいて取得するユーザー情報
107                 /// </summary>
108                 private string authorizedUsername = "";
109
110                 /// <summary>
111                 /// 認証完了時の応答からuserIdentKey情報に基づいて取得するユーザー情報
112                 /// </summary>
113                 private long authorizedUserId;
114
115                 /// <summary>
116                 /// Stream用のHttpWebRequest
117                 /// </summary>
118                 private HttpWebRequest streamReq = null;
119
120                 /// <summary>
121                 /// OAuth認証で指定のURLとHTTP通信を行い、結果を返す
122                 /// </summary>
123                 /// <param name="method">HTTP通信メソッド(GET/HEAD/POST/PUT/DELETE)</param>
124                 /// <param name="requestUri">通信先URI</param>
125                 /// <param name="param">GET時のクエリ、またはPOST時のエンティティボディ</param>
126                 /// <param name="content">[OUT]HTTP応答のボディデータ</param>
127                 /// <param name="headerInfo">[IN/OUT]HTTP応答のヘッダ情報。必要なヘッダ名を事前に設定しておくこと</param>
128                 /// <param name="callback">処理終了直前に呼ばれるコールバック関数のデリゲート 不要な場合はnullを渡すこと</param>
129                 /// <returns>HTTP応答のステータスコード</returns>
130                 public HttpStatusCode GetContent( string method,
131                                                   Uri requestUri,
132                                                   Dictionary< string, string > param,
133                                                   ref string content,
134                                                   Dictionary< string, string > headerInfo,
135                                                   CallbackDelegate callback )
136                 {
137                         // 認証済かチェック
138                         if ( string.IsNullOrEmpty( token ) )
139                                 return HttpStatusCode.Unauthorized;
140
141                         HttpWebRequest webReq = this.CreateRequest( method, requestUri, param, gzip: true );
142                         // OAuth認証ヘッダを付加
143                         this.AppendOAuthInfo( webReq, param, token, tokenSecret );
144
145                         HttpStatusCode code;
146                         if ( content == null )
147                                 code = this.GetResponse( webReq, headerInfo );
148                         else
149                                 code = this.GetResponse( webReq, out content, headerInfo );
150
151                         if ( callback != null )
152                         {
153                                 StackFrame frame = new StackFrame( 1 );
154                                 callback( frame.GetMethod().Name, code, headerInfo, content );
155                         }
156                         return code;
157                 }
158
159                 /// <summary>
160                 /// バイナリアップロード
161                 /// </summary>
162                 public HttpStatusCode GetContent( string method,
163                                                   Uri requestUri,
164                                                   Dictionary< string, string > param,
165                                                   List< KeyValuePair< string, IMediaItem > > binary, 
166                                                   ref string content,
167                                                   Dictionary< string, string > headerInfo,
168                                                   CallbackDelegate callback )
169                 {
170                         // 認証済かチェック
171                         if ( string.IsNullOrEmpty( token ) )
172                                 return HttpStatusCode.Unauthorized;
173
174                         HttpWebRequest webReq = this.CreateRequest( method, requestUri, param, binary );
175                         // OAuth認証ヘッダを付加
176                         this.AppendOAuthInfo( webReq, null, token, tokenSecret );
177
178                         HttpStatusCode code;
179                         if ( content == null )
180                                 code = this.GetResponse( webReq, headerInfo );
181                         else
182                                 code = this.GetResponse( webReq, out content, headerInfo );
183
184                         if ( callback != null )
185                         {
186                                 StackFrame frame = new StackFrame( 1 );
187                                 callback( frame.GetMethod().Name, code, headerInfo, content );
188                         }
189                         return code;
190                 }
191
192                 /// <summary>
193                 /// OAuth認証で指定のURLとHTTP通信を行い、ストリームを返す
194                 /// </summary>
195                 /// <param name="method">HTTP通信メソッド(GET/HEAD/POST/PUT/DELETE)</param>
196                 /// <param name="requestUri">通信先URI</param>
197                 /// <param name="param">GET時のクエリ、またはPOST時のエンティティボディ</param>
198                 /// <param name="content">[OUT]HTTP応答のボディストリーム</param>
199                 /// <returns>HTTP応答のステータスコード</returns>
200                 public HttpStatusCode GetContent( string method,
201                                                   Uri requestUri,
202                                                   Dictionary< string, string > param,
203                                                   ref Stream content,
204                                                   string userAgent )
205                 {
206                         // 認証済かチェック
207                         if ( string.IsNullOrEmpty( token ) )
208                                 return HttpStatusCode.Unauthorized;
209
210                         this.RequestAbort();
211                         this.streamReq = this.CreateRequest( method, requestUri, param );
212                         // User-Agent指定がある場合は付加
213                         if ( !string.IsNullOrEmpty( userAgent ) )
214                                 this.streamReq.UserAgent = userAgent;
215
216                         // OAuth認証ヘッダを付加
217                         this.AppendOAuthInfo( this.streamReq, param, token, tokenSecret );
218
219                         try
220                         {
221                                 HttpWebResponse webRes = (HttpWebResponse)this.streamReq.GetResponse();
222                                 content = webRes.GetResponseStream();
223                                 return webRes.StatusCode;
224                         }
225                         catch ( WebException ex )
226                         {
227                                 if ( ex.Status == WebExceptionStatus.ProtocolError )
228                                 {
229                                         HttpWebResponse res = (HttpWebResponse)ex.Response;
230                                         return res.StatusCode;
231                                 }
232                                 throw;
233                         }
234                 }
235
236                 public void RequestAbort()
237                 {
238                         try
239                         {
240                                 if ( this.streamReq != null )
241                                 {
242                                         this.streamReq.Abort();
243                                         this.streamReq = null;
244                                 }
245                         }
246                         catch ( Exception ) {}
247                 }
248
249                 #region "認証処理"
250                 /// <summary>
251                 /// OAuth認証の開始要求(リクエストトークン取得)。PIN入力用の前段
252                 /// </summary>
253                 /// <remarks>
254                 /// 呼び出し元では戻されたurlをブラウザで開き、認証完了後PIN入力を受け付けて、リクエストトークンと共にAuthenticatePinFlowを呼び出す
255                 /// </remarks>
256                 /// <param name="requestTokenUrl">リクエストトークンの取得先URL</param>
257                 /// <param name="authorizeUrl">ブラウザで開く認証用URLのベース</param>
258                 /// <param name="requestToken">[OUT]認証要求で戻されるリクエストトークン。使い捨て</param>
259                 /// <param name="authUri">[OUT]requestUriを元に生成された認証用URL。通常はリクエストトークンをクエリとして付加したUri</param>
260                 /// <returns>取得結果真偽値</returns>
261                 public bool AuthenticatePinFlowRequest( string requestTokenUrl, string authorizeUrl, ref string requestToken, ref Uri authUri )
262                 {
263                         // PIN-based flow
264             authUri = this.GetAuthenticatePageUri( requestTokenUrl, authorizeUrl, ref requestToken );
265                         if ( authUri == null )
266                                 return false;
267                         return true;
268                 }
269
270                 /// <summary>
271                 /// OAuth認証のアクセストークン取得。PIN入力用の後段
272                 /// </summary>
273                 /// <remarks>
274                 /// 事前にAuthenticatePinFlowRequestを呼んで、ブラウザで認証後に表示されるPINを入力してもらい、その値とともに呼び出すこと
275                 /// </remarks>
276                 /// <param name="accessTokenUrl">アクセストークンの取得先URL</param>
277                 /// <param name="requestToken">AuthenticatePinFlowRequestで取得したリクエストトークン</param>
278                 /// <param name="pinCode">Webで認証後に表示されるPINコード</param>
279                 /// <returns>取得結果真偽値</returns>
280                 public HttpStatusCode AuthenticatePinFlow( string accessTokenUrl, string requestToken, string pinCode )
281                 {
282                         // PIN-based flow
283                         if ( string.IsNullOrEmpty( requestToken ) )
284                                 throw new InvalidOperationException( "Sequence error.(requestToken is blank)" );
285
286                         // アクセストークン取得
287                         string content = "";
288                         NameValueCollection accessTokenData;
289                         HttpStatusCode httpCode = this.GetOAuthToken( new Uri( accessTokenUrl ), pinCode, requestToken, null, ref content );
290                         if ( httpCode != HttpStatusCode.OK )
291                                 return httpCode;
292                         accessTokenData = base.ParseQueryString( content );
293
294                         if ( accessTokenData != null )
295                         {
296                                 this.token = accessTokenData[ "oauth_token" ];
297                                 this.tokenSecret = accessTokenData[ "oauth_token_secret" ];
298
299                                 // サービスごとの独自拡張対応
300                                 if ( !string.IsNullOrEmpty(this.userIdentKey) )
301                                         this.authorizedUsername = accessTokenData[ this.userIdentKey ];
302                                 else
303                                         this.authorizedUsername = "";
304
305                                 if ( !string.IsNullOrEmpty(this.userIdIdentKey) )
306                                 {
307                                         try
308                                         {
309                                                 this.authorizedUserId = Convert.ToInt64( accessTokenData[ this.userIdIdentKey ] );
310                                         }
311                                         catch ( Exception )
312                                         {
313                                                 this.authorizedUserId = 0;
314                                         }
315                                 }
316                                 else
317                                 {
318                                         this.authorizedUserId = 0;
319                                 }
320
321                                 if ( string.IsNullOrEmpty(token) )
322                                         throw new InvalidDataException( "Token is null." );
323                                 return HttpStatusCode.OK;
324                         }
325                         else
326                         {
327                 throw new InvalidDataException( "Return value is null." );
328                         }
329                 }
330
331         public HttpStatusCode Authenticate(Uri accessTokenUrl, string username, string password, ref string content)
332         {
333             return this.AuthenticateXAuth(accessTokenUrl, username, password, ref content);
334         }
335
336                 /// <summary>
337                 /// OAuth認証のアクセストークン取得。xAuth方式
338                 /// </summary>
339                 /// <param name="accessTokenUrl">アクセストークンの取得先URL</param>
340                 /// <param name="username">認証用ユーザー名</param>
341                 /// <param name="password">認証用パスワード</param>
342                 /// <returns>取得結果真偽値</returns>
343                 public HttpStatusCode AuthenticateXAuth( Uri accessTokenUrl, string username, string password, ref string content )
344                 {
345                         // ユーザー・パスワードチェック
346                         if ( string.IsNullOrEmpty( username ) )
347                                 throw new ArgumentException( "username is null or empty", nameof(username) );
348             if ( string.IsNullOrEmpty( password ) )
349                 throw new ArgumentException( "password is null or empty", nameof(password) );
350
351                         // xAuthの拡張パラメータ設定
352                         Dictionary< string, string > parameter = new Dictionary< string, string >();
353                         parameter.Add( "x_auth_mode", "client_auth" );
354                         parameter.Add( "x_auth_username", username );
355                         parameter.Add( "x_auth_password", password );
356
357                         // アクセストークン取得
358                         HttpStatusCode httpCode = this.GetOAuthToken( accessTokenUrl, "", "", parameter, ref content );
359                         if ( httpCode != HttpStatusCode.OK )
360                                 return httpCode;
361                         NameValueCollection accessTokenData = base.ParseQueryString( content );
362
363                         if ( accessTokenData != null )
364                         {
365                                 this.token = accessTokenData[ "oauth_token" ];
366                                 this.tokenSecret = accessTokenData[ "oauth_token_secret" ];
367
368                                 // サービスごとの独自拡張対応
369                                 if ( !string.IsNullOrEmpty(this.userIdentKey) )
370                                         this.authorizedUsername = accessTokenData[ this.userIdentKey ];
371                                 else
372                                         this.authorizedUsername = "";
373
374                                 if ( !string.IsNullOrEmpty(this.userIdIdentKey) )
375                                 {
376                                         try
377                                         {
378                         this.authorizedUserId = Convert.ToInt64( accessTokenData[ this.userIdIdentKey ] );
379                                         }
380                                         catch ( Exception )
381                                         {
382                                                 this.authorizedUserId = 0;
383                                         }
384                                 }
385                                 else
386                                 {
387                                         this.authorizedUserId = 0;
388                                 }
389
390                                 if ( string.IsNullOrEmpty(token) )
391                                         throw new InvalidDataException( "Token is null." );
392                                 return HttpStatusCode.OK;
393                         }
394                         else
395                         {
396                                 throw new InvalidDataException( "Return value is null." );
397                         }
398                 }
399
400                 /// <summary>
401                 /// OAuth認証のリクエストトークン取得。リクエストトークンと組み合わせた認証用のUriも生成する
402                 /// </summary>
403                 /// <param name="requestTokenUrl">リクエストトークンの取得先URL</param>
404                 /// <param name="authorizeUrl">ブラウザで開く認証用URLのベース</param>
405                 /// <param name="requestToken">[OUT]取得したリクエストトークン</param>
406                 /// <returns>取得結果真偽値</returns>
407                 private Uri GetAuthenticatePageUri( string requestTokenUrl, string authorizeUrl, ref string requestToken )
408                 {
409                         const string tokenKey = "oauth_token";
410
411                         // リクエストトークン取得
412                         string content = "";
413                         NameValueCollection reqTokenData;
414                         if ( this.GetOAuthToken( new Uri( requestTokenUrl ), "", "", null, ref content, callbackUrl: "oob" ) != HttpStatusCode.OK )
415                                 return null;
416                         reqTokenData = base.ParseQueryString( content );
417
418                         if ( reqTokenData != null )
419                         {
420                                 requestToken = reqTokenData[ tokenKey ];
421                                 // Uri生成
422                                 UriBuilder ub = new UriBuilder( authorizeUrl );
423                                 ub.Query = string.Format( "{0}={1}", tokenKey, requestToken );
424                                 return ub.Uri;
425                         }
426                         else
427                         {
428                                 return null;
429                         }
430                 }
431
432                 /// <summary>
433                 /// OAuth認証のトークン取得共通処理
434                 /// </summary>
435                 /// <param name="requestUri">各種トークンの取得先URL</param>
436                 /// <param name="pinCode">PINフロー時のアクセストークン取得時に設定。それ以外は空文字列</param>
437                 /// <param name="requestToken">PINフロー時のリクエストトークン取得時に設定。それ以外は空文字列</param>
438                 /// <param name="parameter">追加パラメータ。xAuthで使用</param>
439                 /// <returns>取得結果のデータ。正しく取得出来なかった場合はNothing</returns>
440                 private HttpStatusCode GetOAuthToken( Uri requestUri, string pinCode, string requestToken, Dictionary< string , string > parameter, ref string content, string callbackUrl = null )
441                 {
442                         HttpWebRequest webReq = null;
443                         // HTTPリクエスト生成。PINコードもパラメータも未指定の場合はGETメソッドで通信。それ以外はPOST
444                         if ( string.IsNullOrEmpty( pinCode ) && parameter != null )
445                                 webReq = this.CreateRequest( "GET", requestUri, null );
446                         else
447                                 webReq = this.CreateRequest( "POST", requestUri, parameter ); // ボディに追加パラメータ書き込み
448
449                         // OAuth関連パラメータ準備。追加パラメータがあれば追加
450                         Dictionary< string, string > query = new Dictionary< string, string >();
451                         if ( parameter != null )
452                                 foreach ( KeyValuePair< string, string > kvp in parameter )
453                                         query.Add( kvp.Key, kvp.Value );
454
455                         // PINコードが指定されていればパラメータに追加
456                         if ( ! string.IsNullOrEmpty( pinCode ) )
457                                 query.Add( "oauth_verifier", pinCode );
458
459                         // コールバックURLが指定されていればパラメータに追加
460                         if (!string.IsNullOrEmpty(callbackUrl))
461                                 query.Add("oauth_callback", callbackUrl);
462
463                         // OAuth関連情報をHTTPリクエストに追加
464                         this.AppendOAuthInfo( webReq, query, requestToken, "" );
465
466                         // HTTP応答取得
467                         Dictionary< string, string > header = new Dictionary< string, string >() { { "Date", "" } };
468                         HttpStatusCode responseCode = this.GetResponse( webReq, out content, header );
469                         if ( responseCode == HttpStatusCode.OK )
470                                 return responseCode;
471
472                         if ( !string.IsNullOrEmpty( header[ "Date" ] ) )
473                                 content += Environment.NewLine + "Check the Date & Time of this computer." + Environment.NewLine
474                                 + "Server:" + DateTime.Parse( header[ "Date" ] ).ToString() + "  PC:" + DateTime.Now.ToString();
475                         return responseCode;
476                 }
477                 #endregion // 認証処理
478
479                 #region "OAuth認証用ヘッダ作成・付加処理"
480                 /// <summary>
481                 /// HTTPリクエストにOAuth関連ヘッダを追加
482                 /// </summary>
483                 /// <param name="webRequest">追加対象のHTTPリクエスト</param>
484                 /// <param name="query">OAuth追加情報+クエリ or POSTデータ</param>
485                 /// <param name="token">アクセストークン、もしくはリクエストトークン。未取得なら空文字列</param>
486                 /// <param name="tokenSecret">アクセストークンシークレット。認証処理では空文字列</param>
487                 protected virtual void AppendOAuthInfo( HttpWebRequest webRequest, Dictionary< string, string > query, string token, string tokenSecret )
488                 {
489                         // OAuth共通情報取得
490                         Dictionary< string, string > parameter = this.GetOAuthParameter( token );
491                         // OAuth共通情報にquery情報を追加
492                         if ( query != null )
493                                 foreach ( KeyValuePair< string, string > item in query )
494                                         parameter.Add( item.Key, item.Value );
495                         // 署名の作成・追加
496                         parameter.Add( "oauth_signature", this.CreateSignature( tokenSecret, webRequest.Method, webRequest.RequestUri, parameter ) );
497                         // HTTPリクエストのヘッダに追加
498                         StringBuilder sb = new StringBuilder( "OAuth " );
499                         foreach ( KeyValuePair< string, string > item in parameter )
500                                 // 各種情報のうち、oauth_で始まる情報のみ、ヘッダに追加する。各情報はカンマ区切り、データはダブルクォーテーションで括る
501                                 if ( item.Key.StartsWith("oauth_") )
502                                         sb.AppendFormat( "{0}=\"{1}\",", item.Key, MyCommon.UrlEncode( item.Value ) );
503                         webRequest.Headers.Add( HttpRequestHeader.Authorization, sb.ToString() );
504                 }
505
506                 /// <summary>
507                 /// OAuthで使用する共通情報を取得する
508                 /// </summary>
509                 /// <param name="token">アクセストークン、もしくはリクエストトークン。未取得なら空文字列</param>
510                 /// <returns>OAuth情報のディクショナリ</returns>
511                 protected Dictionary< string, string > GetOAuthParameter( string token )
512                 {
513                         Dictionary< string, string > parameter = new Dictionary< string, string >();
514                         parameter.Add( "oauth_consumer_key", this.consumerKey );
515                         parameter.Add( "oauth_signature_method", "HMAC-SHA1" );
516                         parameter.Add( "oauth_timestamp", Convert.ToInt64( ( DateTime.UtcNow - HttpConnectionOAuth.UnixEpoch ).TotalSeconds ).ToString() ); // epoch秒
517                         parameter.Add( "oauth_nonce", HttpConnectionOAuth.NonceRandom.Next( 123400, 9999999 ).ToString() );
518                         parameter.Add( "oauth_version", "1.0" );
519                         if ( !string.IsNullOrEmpty( token ) )
520                                 parameter.Add( "oauth_token", token ); // トークンがあれば追加
521                         return parameter;
522                 }
523
524                 /// <summary>
525                 /// OAuth認証ヘッダの署名作成
526                 /// </summary>
527                 /// <param name="tokenSecret">アクセストークン秘密鍵</param>
528                 /// <param name="method">HTTPメソッド文字列</param>
529                 /// <param name="uri">アクセス先Uri</param>
530                 /// <param name="parameter">クエリ、もしくはPOSTデータ</param>
531                 /// <returns>署名文字列</returns>
532                 protected virtual string CreateSignature( string tokenSecret, string method, Uri uri, Dictionary< string, string > parameter )
533                 {
534                         // パラメタをソート済みディクショナリに詰替(OAuthの仕様)
535                         SortedDictionary< string, string > sorted = new SortedDictionary< string, string >( parameter );
536                         // URLエンコード済みのクエリ形式文字列に変換
537                         string paramString = MyCommon.BuildQueryString( sorted );
538                         // アクセス先URLの整形
539                         string url = string.Format( "{0}://{1}{2}", uri.Scheme, uri.Host, uri.AbsolutePath );
540                         // 署名のベース文字列生成(&区切り)。クエリ形式文字列は再エンコードする
541                         string signatureBase = string.Format( "{0}&{1}&{2}", method, MyCommon.UrlEncode( url ), MyCommon.UrlEncode( paramString ) );
542                         // 署名鍵の文字列をコンシューマー秘密鍵とアクセストークン秘密鍵から生成(&区切り。アクセストークン秘密鍵なくても&残すこと)
543                         string key = MyCommon.UrlEncode( this.consumerSecret ) + "&";
544                         if ( !string.IsNullOrEmpty( tokenSecret ) )
545                                 key += MyCommon.UrlEncode( tokenSecret );
546                         // 鍵生成&署名生成
547                         using ( HMACSHA1 hmac = new HMACSHA1( Encoding.ASCII.GetBytes( key ) ) )
548                         {
549                                 byte[] hash = hmac.ComputeHash( Encoding.ASCII.GetBytes( signatureBase ) );
550                                 return Convert.ToBase64String( hash );
551                         }
552                 }
553                 #endregion // OAuth認証用ヘッダ作成・付加処理
554
555                 /// <summary>
556                 /// 初期化。各種トークンの設定とユーザー識別情報設定
557                 /// </summary>
558                 /// <param name="consumerKey">コンシューマー鍵</param>
559                 /// <param name="consumerSecret">コンシューマー秘密鍵</param>
560                 /// <param name="accessToken">アクセストークン</param>
561                 /// <param name="accessTokenSecret">アクセストークン秘密鍵</param>
562                 /// <param name="userIdentifier">アクセストークン取得時に得られるユーザー識別情報。不要なら空文字列</param>
563                 public void Initialize( string consumerKey, string consumerSecret,
564                                         string accessToken, string accessTokenSecret,
565                                         string userIdentifier, string userIdIdentifier )
566                 {
567                         this.consumerKey = consumerKey;
568                         this.consumerSecret = consumerSecret;
569                         this.token = accessToken;
570                         this.tokenSecret = accessTokenSecret;
571                         this.userIdentKey = userIdentifier;
572                         this.userIdIdentKey = userIdIdentifier;
573                 }
574
575                 /// <summary>
576                 /// 初期化。各種トークンの設定とユーザー識別情報設定
577                 /// </summary>
578                 /// <param name="consumerKey">コンシューマー鍵</param>
579                 /// <param name="consumerSecret">コンシューマー秘密鍵</param>
580                 /// <param name="accessToken">アクセストークン</param>
581                 /// <param name="accessTokenSecret">アクセストークン秘密鍵</param>
582                 /// <param name="username">認証済みユーザー名</param>
583                 /// <param name="userIdentifier">アクセストークン取得時に得られるユーザー識別情報。不要なら空文字列</param>
584                 public void Initialize( string consumerKey, string consumerSecret,
585                                         string accessToken, string accessTokenSecret,
586                                         string username, long userId,
587                                         string userIdentifier, string userIdIdentifier )
588                 {
589                         this.Initialize( consumerKey, consumerSecret, accessToken, accessTokenSecret, userIdentifier, userIdIdentifier );
590                         this.authorizedUsername = username;
591                         this.authorizedUserId = userId;
592                 }
593
594                 /// <summary>
595                 /// アクセストークン
596                 /// </summary>
597                 public string AccessToken
598                 {
599                         get { return this.token; }
600                 }
601
602                 /// <summary>
603                 /// アクセストークン秘密鍵
604                 /// </summary>
605                 public string AccessTokenSecret
606                 {
607                         get { return this.tokenSecret; }
608                 }
609
610                 /// <summary>
611                 /// 認証済みユーザー名
612                 /// </summary>
613                 public string AuthUsername
614                 {
615                         get { return this.authorizedUsername; }
616                 }
617
618                 /// <summary>
619                 /// 認証済みユーザーId
620                 /// </summary>
621                 public long AuthUserId
622                 {
623                         get { return this.authorizedUserId; }
624                         set { this.authorizedUserId = value; }
625                 }
626         }
627 }