~ubuntu-branches/ubuntu/lucid/tomboy/lucid-proposed

« back to all changes in this revision

Viewing changes to Tomboy/Addins/WebSyncService/OAuth/Base.cs

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2009-09-22 11:56:36 UTC
  • mfrom: (1.3.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20090922115636-2vw47jv5ki4z59ob
Tags: 1.0.0-0ubuntu1
* New upstream release: (LP: #434384)
  - Fix crash when showing Search from panel applet.
  - Redirect complete applet output to ~/.config/tomboy/tomboy-panel.log.
  - Every patch contributor goes in the About dialog now.
  - Add Underline add-in to Windows/Mac builds.
  - WebSync fixes on Windows.
  - Translation updates

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// OAuthBase.cs
3
 
//  
4
 
// Author:
5
 
//       Bojan Rajkovic <bojanr@brandeis.edu>
6
 
//       Shannon Whitley <swhitley@whitleymedia.com>
7
 
//       Eran Sandler <http://eran.sandler.co.il/>
8
 
//       Sandy Armstrong <sanfordarmstrong@gmail.com>
9
 
// 
10
 
// Copyright (c) 2009 Bojan Rajkovic
11
 
// 
12
 
// Permission is hereby granted, free of charge, to any person obtaining a copy
13
 
// of this software and associated documentation files (the "Software"), to deal
14
 
// in the Software without restriction, including without limitation the rights
15
 
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 
// copies of the Software, and to permit persons to whom the Software is
17
 
// furnished to do so, subject to the following conditions:
18
 
//
19
 
// The above copyright notice and this permission notice shall be included in
20
 
// all copies or substantial portions of the Software.
21
 
//
22
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28
 
// THE SOFTWARE.
29
 
using OAuth;
30
 
 
31
 
using System;
32
 
using System.Collections.Generic;
33
 
using System.Linq;
34
 
using System.Security.Cryptography;
35
 
using System.Text;
36
 
using System.Web;
37
 
 
38
 
namespace OAuth
39
 
{
40
 
        /// <summary>
41
 
        /// Provides a base class for OAuth authentication and signing.
42
 
        /// </summary>
43
 
        public class Base
44
 
        {
45
 
                class LoggerAdapter
46
 
                {
47
 
                        public void LogDebug (string format, params object[] objects)
48
 
                        {
49
 
                                if (Debugging)
50
 
                                        Tomboy.Logger.Debug (format, objects);
51
 
                        }
52
 
        
53
 
                        public bool Debugging { get; set; }
54
 
                }
55
 
 
56
 
                private readonly LoggerAdapter log = new LoggerAdapter ();
57
 
                private bool debugging;
58
 
 
59
 
                public bool Debugging
60
 
                {
61
 
                        get { return debugging; }
62
 
                        set { debugging = value; log.Debugging = value; }
63
 
                }
64
 
 
65
 
                private const string OAuthVersion = "1.0";
66
 
 
67
 
                //
68
 
                // List of know and used oauth parameters' names
69
 
                //
70
 
                private const string OAuthConsumerKeyKey = "oauth_consumer_key";
71
 
                private const string OAuthCallbackKey = "oauth_callback";
72
 
                private const string OAuthVersionKey = "oauth_version";
73
 
                private const string OAuthSignatureMethodKey = "oauth_signature_method";
74
 
                private const string OAuthSignatureKey = "oauth_signature";
75
 
                private const string OAuthTimestampKey = "oauth_timestamp";
76
 
                private const string OAuthNonceKey = "oauth_nonce";
77
 
                private const string OAuthTokenKey = "oauth_token";
78
 
                private const string OAuthTokenSecretKey = "oauth_token_secret";
79
 
                private const string OAuthVerifierKey = "oauth_verifier";
80
 
 
81
 
                private const string HMACSHA1SignatureType = "HMAC-SHA1";
82
 
                private const string PlainTextSignatureType = "PLAINTEXT";
83
 
                private const string RSASHA1SignatureType = "RSA-SHA1";
84
 
 
85
 
                private Random random = new Random ();
86
 
 
87
 
                private string unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
88
 
 
89
 
                /// <summary>
90
 
                /// Helper function to compute a hash value.
91
 
                /// </summary>
92
 
                /// <param name="hashAlgorithm">
93
 
                ///     The hashing algoirhtm used. If that algorithm needs some initialization, like HMAC and its derivatives,
94
 
                ///     they should be initialized prior to passing it to this function.
95
 
                /// </param>
96
 
                /// <param name="data">The data to hash.</param>
97
 
                /// <returns>A Base64 string of the hash value.</returns>
98
 
                private string ComputeHash (HashAlgorithm hashAlgorithm, string data)
99
 
                {
100
 
                        log.LogDebug ("Computing hash for data {0}", data);
101
 
 
102
 
                        if (hashAlgorithm == null) throw new ArgumentNullException ("hashAlgorithm");
103
 
                        if (string.IsNullOrEmpty (data)) throw new ArgumentNullException ("data");
104
 
 
105
 
                        byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes (data);
106
 
                        byte[] hashBytes = hashAlgorithm.ComputeHash (dataBuffer);
107
 
 
108
 
                        return Convert.ToBase64String (hashBytes);
109
 
                }
110
 
 
111
 
                /// <summary>
112
 
                /// URL encodes a string using OAuth's encoding scheme (slightly different from HttpUtility's UrlEncode).
113
 
                /// </summary>
114
 
                /// <param name="value">The string to URL encode.</param>
115
 
                /// <returns>An URL encoded string.</returns>
116
 
                private string UrlEncode (string value)
117
 
                {
118
 
                        log.LogDebug ("URL encoding value.");
119
 
                        var result = new StringBuilder ();
120
 
 
121
 
                        foreach (char symbol in value) {
122
 
                                if (unreservedChars.IndexOf(symbol) != -1) result.Append(symbol);
123
 
                                else result.Append('%' + String.Format("{0:X2}", (int)symbol));
124
 
                        }
125
 
 
126
 
                        return result.ToString();
127
 
                }
128
 
 
129
 
                /// <summary>
130
 
                /// Internal function to cut out all non oauth query string parameters.
131
 
                /// </summary>
132
 
                /// <param name="parameters">The query string part of the URL.</param>
133
 
                /// <returns>A list of QueryParameter each containing the parameter name and value.</returns>
134
 
                private IEnumerable<IQueryParameter<string>> GetQueryParameters (string parameters)
135
 
                {
136
 
                        log.LogDebug ("Creating list of parameters from parameter string {0}", parameters);
137
 
 
138
 
                        return CreateQueryParametersIterator (parameters);
139
 
                }
140
 
 
141
 
                private IEnumerable<IQueryParameter<string>> CreateQueryParametersIterator (string parameters)
142
 
                {
143
 
                        if (parameters == null) throw new ArgumentNullException ("parameters");
144
 
                        var parameterDictionary = HttpUtility.ParseQueryString (parameters).ToDictionary ();
145
 
 
146
 
                        foreach (var kvp in parameterDictionary)
147
 
                                yield return new QueryParameter<string> (kvp.Key, kvp.Value, s => string.IsNullOrEmpty (s));
148
 
                }
149
 
 
150
 
                /// <summary>
151
 
                /// Generate the signature base that is used to produce the signature
152
 
                /// </summary>
153
 
                /// <param name="url">The full URL that needs to be signed including its non OAuth URL parameters.</param>
154
 
                /// <param name="consumerKey">The consumer key.</param>
155
 
                /// <param name="token">The token, if available. If not available pass null or an empty string.</param>
156
 
                /// <param name="tokenSecret">The token secret, if available. If not available pass null or an empty string.</param>
157
 
                /// <param name="verifier">The callback verifier, if available. If not available pass null or an empty string.</param>
158
 
                /// <param name="httpMethod">The HTTP method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)</param>
159
 
                /// <param name="signatureType">The signature type. To use the default values use <see cref="SignatureType">SignatureType</see>.</param>
160
 
                /// <returns>The signature base.</returns>
161
 
                private string GenerateSignatureBase (Uri url, string consumerKey, string token, string tokenSecret, string verifier,
162
 
                        RequestMethod method, TimeSpan timeStamp, string nonce, SignatureType signatureType, out string normalizedUrl,
163
 
                        out List<IQueryParameter<string>> parameters)
164
 
                {
165
 
                        log.LogDebug ("Generating signature base for OAuth request.");
166
 
 
167
 
                        token = token ?? string.Empty;
168
 
                        tokenSecret = tokenSecret ?? string.Empty;
169
 
                        verifier = verifier ?? String.Empty;
170
 
 
171
 
                        if (consumerKey == null) throw new ArgumentNullException ("consumerKey");
172
 
 
173
 
                        log.LogDebug ("URL: {0}", url.Query);
174
 
 
175
 
                        var signatureString = string.Empty;
176
 
 
177
 
                        switch (signatureType) {
178
 
                                case SignatureType.HMACSHA1:
179
 
                                        signatureString = "HMAC-SHA1";
180
 
                                        break;
181
 
                                case SignatureType.RSASHA1:
182
 
                                        signatureString = "RSA-SHA1";
183
 
                                        break;
184
 
                                case SignatureType.PLAINTEXT:
185
 
                                        signatureString = SignatureType.PLAINTEXT.ToString ();
186
 
                                        break;
187
 
                        }
188
 
 
189
 
                        parameters = GetQueryParameters (url.Query).Concat (new List<IQueryParameter<string>> {
190
 
                                new QueryParameter<string> (OAuthVersionKey, OAuthVersion, s => string.IsNullOrEmpty (s)),
191
 
                                new QueryParameter<string> (OAuthTimestampKey, ((long)timeStamp.TotalSeconds).ToString (), s => string.IsNullOrEmpty (s)),
192
 
                                new QueryParameter<string> (OAuthSignatureMethodKey, signatureString, s => string.IsNullOrEmpty (s)),
193
 
                                new QueryParameter<string> (OAuthNonceKey, nonce, s => string.IsNullOrEmpty (s)),
194
 
                                new QueryParameter<string> (OAuthConsumerKeyKey, consumerKey, s => string.IsNullOrEmpty (s))
195
 
                        }).ToList ();
196
 
 
197
 
                        if (!string.IsNullOrEmpty (token)) parameters.Add (new QueryParameter<string> (OAuthTokenKey, token, s => string.IsNullOrEmpty (s)));
198
 
                        if (!string.IsNullOrEmpty (verifier)) parameters.Add (new QueryParameter<string> (OAuthVerifierKey, verifier, s => string.IsNullOrEmpty (s)));
199
 
 
200
 
                        log.LogDebug ("Normalizing URL for signature.");
201
 
 
202
 
                        normalizedUrl = string.Format ("{0}://{1}", url.Scheme, url.Host);
203
 
                        if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) normalizedUrl += ":" + url.Port;
204
 
                        normalizedUrl += url.AbsolutePath;
205
 
 
206
 
                        log.LogDebug ("Generated normalized URL: {0}", normalizedUrl);
207
 
                        log.LogDebug ("Normalizing request parameters.");
208
 
 
209
 
                        parameters.Sort ();
210
 
                        string normalizedRequestParameters = parameters.NormalizeRequestParameters ();
211
 
 
212
 
                        log.LogDebug ("Normalized request parameters {0}.", normalizedRequestParameters);
213
 
                        log.LogDebug ("Generating signature base from normalized URL and request parameters.");
214
 
 
215
 
                        var signatureBase = new StringBuilder ();
216
 
                        signatureBase.AppendFormat("{0}&", method.ToString ());
217
 
                        signatureBase.AppendFormat("{0}&", UrlEncode (normalizedUrl));
218
 
                        signatureBase.AppendFormat("{0}", UrlEncode (normalizedRequestParameters));
219
 
 
220
 
                        log.LogDebug ("Signature base: {0}", signatureBase.ToString ());
221
 
 
222
 
                        return signatureBase.ToString ();
223
 
                }
224
 
 
225
 
                /// <summary>
226
 
                /// Generate the signature value based on the given signature base and hash algorithm.
227
 
                /// </summary>
228
 
                /// <param name="signatureBase">
229
 
                ///     The signature based as produced by the GenerateSignatureBase method or by any other means.
230
 
                /// </param>
231
 
                /// <param name="hash">
232
 
                ///     The hash algorithm used to perform the hashing. If the hashing algorithm requires
233
 
                ///     initialization or a key it should be set prior to calling this method.
234
 
                /// </param>
235
 
                /// <returns>A Base64 string of the hash value.</returns>
236
 
                private string GenerateSignatureUsingHash (string signatureBase, HashAlgorithm hash)
237
 
                {
238
 
                        log.LogDebug ("Generating hashed signature.");
239
 
                        return ComputeHash (hash, signatureBase);
240
 
                }
241
 
 
242
 
                /// <summary>
243
 
                /// Generates a signature using the HMAC-SHA1 algorithm
244
 
                /// </summary>
245
 
                /// <param name="url">The full URL that needs to be signed including its non-OAuth URL parameters.</param>
246
 
                /// <param name="consumerKey">The consumer key.</param>
247
 
                /// <param name="consumerSecret">The consumer seceret.</param>
248
 
                /// <param name="token">The token, if available. If not available pass null or an empty string.</param>
249
 
                /// <param name="tokenSecret">The token secret, if available. If not, pass null or an empty string.</param>
250
 
                /// <param name="verifier">The callback verifier, if available. If not, pass null or an empty string.</param>
251
 
                /// <param name="httpMethod">The HTTP method used. Must be valid HTTP method verb (POST, GET, PUT, etc).</param>
252
 
                /// <returns>A Base64 string of the hash value.</returns>
253
 
                protected string GenerateSignature (Uri url, string consumerKey, string consumerSecret, string token,
254
 
                        string tokenSecret, string verifier, RequestMethod method, TimeSpan timeStamp, string nonce, out string normalizedUrl,
255
 
                        out List<IQueryParameter<string>> parameters)
256
 
                {
257
 
                        log.LogDebug ("Generating signature using HMAC-SHA1 algorithm.");
258
 
                        return GenerateSignature (url, consumerKey, consumerSecret, token, tokenSecret, verifier, method, timeStamp, nonce,
259
 
                                SignatureType.HMACSHA1, out normalizedUrl, out parameters);
260
 
                }
261
 
 
262
 
                /// <summary>
263
 
                /// Generates a signature using the specified signature type.
264
 
                /// </summary>
265
 
                /// <param name="url">The full URL that needs to be signed including its non-OAuth URL parameters.</param>
266
 
                /// <param name="consumerKey">The consumer key.</param>
267
 
                /// <param name="consumerSecret">The consumer seceret.</param>
268
 
                /// <param name="token">The token, if available. If not available pass null or an empty string.</param>
269
 
                /// <param name="tokenSecret">The token secret, if available. If not, pass null or an empty string.</param>
270
 
                /// <param name="verifier">The callback verifier, if available. If not, pass null or an empty string.</param>
271
 
                /// <param name="httpMethod">The HTTP method used. Must be a valid HTTP method verb (POST,GET,PUT, etc).</param>
272
 
                /// <param name="signatureType">The type of signature to use.</param>
273
 
                /// <returns>A Base64 string of the hash value.</returns>
274
 
                private string GenerateSignature (Uri url, string consumerKey, string consumerSecret, string token,
275
 
                        string tokenSecret, string verifier, RequestMethod method, TimeSpan timeStamp, string nonce, SignatureType signatureType,
276
 
                        out string normalizedUrl, out List<IQueryParameter<string>> parameters)
277
 
                {
278
 
                        log.LogDebug ("Generating signature using signature type {0}", signatureType);
279
 
 
280
 
                        normalizedUrl = null;
281
 
                        parameters = null;
282
 
 
283
 
                        switch (signatureType)
284
 
                        {
285
 
                                case SignatureType.PLAINTEXT:
286
 
                                        var signature = UrlEncode (string.Format ("{0}&{1}", consumerSecret, tokenSecret));
287
 
                                        log.LogDebug ("Plaintext encoding signature {0} of consumer secret and token secret.", signature);
288
 
                                        return signature;
289
 
                                case SignatureType.HMACSHA1:
290
 
                                        string signatureBase = GenerateSignatureBase (url, consumerKey, token, tokenSecret, verifier, method,
291
 
                                                timeStamp, nonce, SignatureType.HMACSHA1, out normalizedUrl, out parameters);
292
 
 
293
 
                                        var hmacsha1 = new HMACSHA1 ();
294
 
                                        hmacsha1.Key = Encoding.ASCII.GetBytes (string.Format ("{0}&{1}",
295
 
                                                UrlEncode (consumerSecret),
296
 
                                                string.IsNullOrEmpty (tokenSecret) ? "" : UrlEncode(tokenSecret)));
297
 
 
298
 
                                        var hashedSignature = GenerateSignatureUsingHash (signatureBase, hmacsha1);
299
 
 
300
 
                                        log.LogDebug ("HMAC-SHA1 encoded signature {0} of consumer secret and token secret.", hashedSignature);
301
 
                                        return hashedSignature;
302
 
                                case SignatureType.RSASHA1:
303
 
                                        throw new NotImplementedException ();
304
 
                                default:
305
 
                                        throw new ArgumentException ("Unknown signature type", "signatureType");
306
 
                        }
307
 
                }
308
 
 
309
 
                /// <summary>
310
 
                /// Generate the timestamp for the signature.
311
 
                /// </summary>
312
 
                /// <returns>A string timestamp.</returns>
313
 
                protected TimeSpan GenerateTimeStamp ()
314
 
                {
315
 
                        log.LogDebug ("Generating time stamp.");
316
 
                        // Default implementation of UNIX time of the current UTC time
317
 
                        return DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
318
 
                }
319
 
 
320
 
                /// <summary>
321
 
                /// Generate a nonce.
322
 
                /// </summary>
323
 
                /// <returns>A random nonce string.</returns>
324
 
                protected virtual string GenerateNonce()
325
 
                {
326
 
                        log.LogDebug ("Generating nonce.");
327
 
                        // Just a simple implementation of a random number between 123400 and 9999999
328
 
                        return random.Next (123400, 9999999).ToString ();
329
 
                }
330
 
        }
 
1
//
 
2
// OAuthBase.cs
 
3
//  
 
4
// Author:
 
5
//       Bojan Rajkovic <bojanr@brandeis.edu>
 
6
//       Shannon Whitley <swhitley@whitleymedia.com>
 
7
//       Eran Sandler <http://eran.sandler.co.il/>
 
8
//       Sandy Armstrong <sanfordarmstrong@gmail.com>
 
9
// 
 
10
// Copyright (c) 2009 Bojan Rajkovic
 
11
// 
 
12
// Permission is hereby granted, free of charge, to any person obtaining a copy
 
13
// of this software and associated documentation files (the "Software"), to deal
 
14
// in the Software without restriction, including without limitation the rights
 
15
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
16
// copies of the Software, and to permit persons to whom the Software is
 
17
// furnished to do so, subject to the following conditions:
 
18
//
 
19
// The above copyright notice and this permission notice shall be included in
 
20
// all copies or substantial portions of the Software.
 
21
//
 
22
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
23
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
24
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
25
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
26
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
27
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
28
// THE SOFTWARE.
 
29
using OAuth;
 
30
 
 
31
using System;
 
32
using System.Collections.Generic;
 
33
using System.Linq;
 
34
using System.Security.Cryptography;
 
35
using System.Text;
 
36
using System.Web;
 
37
 
 
38
namespace OAuth
 
39
{
 
40
        /// <summary>
 
41
        /// Provides a base class for OAuth authentication and signing.
 
42
        /// </summary>
 
43
        public class Base
 
44
        {
 
45
                class LoggerAdapter
 
46
                {
 
47
                        public void LogDebug (string format, params object[] objects)
 
48
                        {
 
49
                                if (Debugging)
 
50
                                        Tomboy.Logger.Debug (format, objects);
 
51
                        }
 
52
        
 
53
                        public bool Debugging { get; set; }
 
54
                }
 
55
 
 
56
                private readonly LoggerAdapter log = new LoggerAdapter ();
 
57
                private bool debugging;
 
58
 
 
59
                public bool Debugging
 
60
                {
 
61
                        get { return debugging; }
 
62
                        set { debugging = value; log.Debugging = value; }
 
63
                }
 
64
 
 
65
                private const string OAuthVersion = "1.0";
 
66
 
 
67
                //
 
68
                // List of know and used oauth parameters' names
 
69
                //
 
70
                private const string OAuthConsumerKeyKey = "oauth_consumer_key";
 
71
                private const string OAuthCallbackKey = "oauth_callback";
 
72
                private const string OAuthVersionKey = "oauth_version";
 
73
                private const string OAuthSignatureMethodKey = "oauth_signature_method";
 
74
                private const string OAuthSignatureKey = "oauth_signature";
 
75
                private const string OAuthTimestampKey = "oauth_timestamp";
 
76
                private const string OAuthNonceKey = "oauth_nonce";
 
77
                private const string OAuthTokenKey = "oauth_token";
 
78
                private const string OAuthTokenSecretKey = "oauth_token_secret";
 
79
                private const string OAuthVerifierKey = "oauth_verifier";
 
80
 
 
81
                private const string HMACSHA1SignatureType = "HMAC-SHA1";
 
82
                private const string PlainTextSignatureType = "PLAINTEXT";
 
83
                private const string RSASHA1SignatureType = "RSA-SHA1";
 
84
 
 
85
                private Random random = new Random ();
 
86
 
 
87
                private string unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
 
88
 
 
89
                /// <summary>
 
90
                /// Helper function to compute a hash value.
 
91
                /// </summary>
 
92
                /// <param name="hashAlgorithm">
 
93
                ///     The hashing algoirhtm used. If that algorithm needs some initialization, like HMAC and its derivatives,
 
94
                ///     they should be initialized prior to passing it to this function.
 
95
                /// </param>
 
96
                /// <param name="data">The data to hash.</param>
 
97
                /// <returns>A Base64 string of the hash value.</returns>
 
98
                private string ComputeHash (HashAlgorithm hashAlgorithm, string data)
 
99
                {
 
100
                        log.LogDebug ("Computing hash for data {0}", data);
 
101
 
 
102
                        if (hashAlgorithm == null) throw new ArgumentNullException ("hashAlgorithm");
 
103
                        if (string.IsNullOrEmpty (data)) throw new ArgumentNullException ("data");
 
104
 
 
105
                        byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes (data);
 
106
                        byte[] hashBytes = hashAlgorithm.ComputeHash (dataBuffer);
 
107
 
 
108
                        return Convert.ToBase64String (hashBytes);
 
109
                }
 
110
 
 
111
                /// <summary>
 
112
                /// URL encodes a string using OAuth's encoding scheme (slightly different from HttpUtility's UrlEncode).
 
113
                /// </summary>
 
114
                /// <param name="value">The string to URL encode.</param>
 
115
                /// <returns>An URL encoded string.</returns>
 
116
                private string UrlEncode (string value)
 
117
                {
 
118
                        log.LogDebug ("URL encoding value.");
 
119
                        var result = new StringBuilder ();
 
120
 
 
121
                        foreach (char symbol in value) {
 
122
                                if (unreservedChars.IndexOf(symbol) != -1) result.Append(symbol);
 
123
                                else result.Append('%' + String.Format("{0:X2}", (int)symbol));
 
124
                        }
 
125
 
 
126
                        return result.ToString();
 
127
                }
 
128
 
 
129
                /// <summary>
 
130
                /// Internal function to cut out all non oauth query string parameters.
 
131
                /// </summary>
 
132
                /// <param name="parameters">The query string part of the URL.</param>
 
133
                /// <returns>A list of QueryParameter each containing the parameter name and value.</returns>
 
134
                private IEnumerable<IQueryParameter<string>> GetQueryParameters (string parameters)
 
135
                {
 
136
                        log.LogDebug ("Creating list of parameters from parameter string {0}", parameters);
 
137
 
 
138
                        return CreateQueryParametersIterator (parameters);
 
139
                }
 
140
 
 
141
                private IEnumerable<IQueryParameter<string>> CreateQueryParametersIterator (string parameters)
 
142
                {
 
143
                        if (parameters == null) throw new ArgumentNullException ("parameters");
 
144
                        var parameterDictionary = HttpUtility.ParseQueryString (parameters).ToDictionary ();
 
145
 
 
146
                        foreach (var kvp in parameterDictionary)
 
147
                                yield return new QueryParameter<string> (kvp.Key, kvp.Value, s => string.IsNullOrEmpty (s));
 
148
                }
 
149
 
 
150
                /// <summary>
 
151
                /// Generate the signature base that is used to produce the signature
 
152
                /// </summary>
 
153
                /// <param name="url">The full URL that needs to be signed including its non OAuth URL parameters.</param>
 
154
                /// <param name="consumerKey">The consumer key.</param>
 
155
                /// <param name="token">The token, if available. If not available pass null or an empty string.</param>
 
156
                /// <param name="tokenSecret">The token secret, if available. If not available pass null or an empty string.</param>
 
157
                /// <param name="verifier">The callback verifier, if available. If not available pass null or an empty string.</param>
 
158
                /// <param name="httpMethod">The HTTP method used. Must be a valid HTTP method verb (POST,GET,PUT, etc)</param>
 
159
                /// <param name="signatureType">The signature type. To use the default values use <see cref="SignatureType">SignatureType</see>.</param>
 
160
                /// <returns>The signature base.</returns>
 
161
                private string GenerateSignatureBase (Uri url, string consumerKey, string token, string tokenSecret, string verifier,
 
162
                        RequestMethod method, TimeSpan timeStamp, string nonce, SignatureType signatureType, out string normalizedUrl,
 
163
                        out List<IQueryParameter<string>> parameters)
 
164
                {
 
165
                        log.LogDebug ("Generating signature base for OAuth request.");
 
166
 
 
167
                        token = token ?? string.Empty;
 
168
                        tokenSecret = tokenSecret ?? string.Empty;
 
169
                        verifier = verifier ?? String.Empty;
 
170
 
 
171
                        if (consumerKey == null) throw new ArgumentNullException ("consumerKey");
 
172
 
 
173
                        log.LogDebug ("URL: {0}", url.Query);
 
174
 
 
175
                        var signatureString = string.Empty;
 
176
 
 
177
                        switch (signatureType) {
 
178
                                case SignatureType.HMACSHA1:
 
179
                                        signatureString = "HMAC-SHA1";
 
180
                                        break;
 
181
                                case SignatureType.RSASHA1:
 
182
                                        signatureString = "RSA-SHA1";
 
183
                                        break;
 
184
                                case SignatureType.PLAINTEXT:
 
185
                                        signatureString = SignatureType.PLAINTEXT.ToString ();
 
186
                                        break;
 
187
                        }
 
188
 
 
189
                        parameters = GetQueryParameters (url.Query).Concat (new List<IQueryParameter<string>> {
 
190
                                new QueryParameter<string> (OAuthVersionKey, OAuthVersion, s => string.IsNullOrEmpty (s)),
 
191
                                new QueryParameter<string> (OAuthTimestampKey, ((long)timeStamp.TotalSeconds).ToString (), s => string.IsNullOrEmpty (s)),
 
192
                                new QueryParameter<string> (OAuthSignatureMethodKey, signatureString, s => string.IsNullOrEmpty (s)),
 
193
                                new QueryParameter<string> (OAuthNonceKey, nonce, s => string.IsNullOrEmpty (s)),
 
194
                                new QueryParameter<string> (OAuthConsumerKeyKey, consumerKey, s => string.IsNullOrEmpty (s))
 
195
                        }).ToList ();
 
196
 
 
197
                        if (!string.IsNullOrEmpty (token)) parameters.Add (new QueryParameter<string> (OAuthTokenKey, token, s => string.IsNullOrEmpty (s)));
 
198
                        if (!string.IsNullOrEmpty (verifier)) parameters.Add (new QueryParameter<string> (OAuthVerifierKey, verifier, s => string.IsNullOrEmpty (s)));
 
199
 
 
200
                        log.LogDebug ("Normalizing URL for signature.");
 
201
 
 
202
                        normalizedUrl = string.Format ("{0}://{1}", url.Scheme, url.Host);
 
203
                        if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) normalizedUrl += ":" + url.Port;
 
204
                        normalizedUrl += url.AbsolutePath;
 
205
 
 
206
                        log.LogDebug ("Generated normalized URL: {0}", normalizedUrl);
 
207
                        log.LogDebug ("Normalizing request parameters.");
 
208
 
 
209
                        parameters.Sort ();
 
210
                        string normalizedRequestParameters = parameters.NormalizeRequestParameters ();
 
211
 
 
212
                        log.LogDebug ("Normalized request parameters {0}.", normalizedRequestParameters);
 
213
                        log.LogDebug ("Generating signature base from normalized URL and request parameters.");
 
214
 
 
215
                        var signatureBase = new StringBuilder ();
 
216
                        signatureBase.AppendFormat("{0}&", method.ToString ());
 
217
                        signatureBase.AppendFormat("{0}&", UrlEncode (normalizedUrl));
 
218
                        signatureBase.AppendFormat("{0}", UrlEncode (normalizedRequestParameters));
 
219
 
 
220
                        log.LogDebug ("Signature base: {0}", signatureBase.ToString ());
 
221
 
 
222
                        return signatureBase.ToString ();
 
223
                }
 
224
 
 
225
                /// <summary>
 
226
                /// Generate the signature value based on the given signature base and hash algorithm.
 
227
                /// </summary>
 
228
                /// <param name="signatureBase">
 
229
                ///     The signature based as produced by the GenerateSignatureBase method or by any other means.
 
230
                /// </param>
 
231
                /// <param name="hash">
 
232
                ///     The hash algorithm used to perform the hashing. If the hashing algorithm requires
 
233
                ///     initialization or a key it should be set prior to calling this method.
 
234
                /// </param>
 
235
                /// <returns>A Base64 string of the hash value.</returns>
 
236
                private string GenerateSignatureUsingHash (string signatureBase, HashAlgorithm hash)
 
237
                {
 
238
                        log.LogDebug ("Generating hashed signature.");
 
239
                        return ComputeHash (hash, signatureBase);
 
240
                }
 
241
 
 
242
                /// <summary>
 
243
                /// Generates a signature using the HMAC-SHA1 algorithm
 
244
                /// </summary>
 
245
                /// <param name="url">The full URL that needs to be signed including its non-OAuth URL parameters.</param>
 
246
                /// <param name="consumerKey">The consumer key.</param>
 
247
                /// <param name="consumerSecret">The consumer seceret.</param>
 
248
                /// <param name="token">The token, if available. If not available pass null or an empty string.</param>
 
249
                /// <param name="tokenSecret">The token secret, if available. If not, pass null or an empty string.</param>
 
250
                /// <param name="verifier">The callback verifier, if available. If not, pass null or an empty string.</param>
 
251
                /// <param name="httpMethod">The HTTP method used. Must be valid HTTP method verb (POST, GET, PUT, etc).</param>
 
252
                /// <returns>A Base64 string of the hash value.</returns>
 
253
                protected string GenerateSignature (Uri url, string consumerKey, string consumerSecret, string token,
 
254
                        string tokenSecret, string verifier, RequestMethod method, TimeSpan timeStamp, string nonce, out string normalizedUrl,
 
255
                        out List<IQueryParameter<string>> parameters)
 
256
                {
 
257
                        log.LogDebug ("Generating signature using HMAC-SHA1 algorithm.");
 
258
                        return GenerateSignature (url, consumerKey, consumerSecret, token, tokenSecret, verifier, method, timeStamp, nonce,
 
259
                                SignatureType.HMACSHA1, out normalizedUrl, out parameters);
 
260
                }
 
261
 
 
262
                /// <summary>
 
263
                /// Generates a signature using the specified signature type.
 
264
                /// </summary>
 
265
                /// <param name="url">The full URL that needs to be signed including its non-OAuth URL parameters.</param>
 
266
                /// <param name="consumerKey">The consumer key.</param>
 
267
                /// <param name="consumerSecret">The consumer seceret.</param>
 
268
                /// <param name="token">The token, if available. If not available pass null or an empty string.</param>
 
269
                /// <param name="tokenSecret">The token secret, if available. If not, pass null or an empty string.</param>
 
270
                /// <param name="verifier">The callback verifier, if available. If not, pass null or an empty string.</param>
 
271
                /// <param name="httpMethod">The HTTP method used. Must be a valid HTTP method verb (POST,GET,PUT, etc).</param>
 
272
                /// <param name="signatureType">The type of signature to use.</param>
 
273
                /// <returns>A Base64 string of the hash value.</returns>
 
274
                private string GenerateSignature (Uri url, string consumerKey, string consumerSecret, string token,
 
275
                        string tokenSecret, string verifier, RequestMethod method, TimeSpan timeStamp, string nonce, SignatureType signatureType,
 
276
                        out string normalizedUrl, out List<IQueryParameter<string>> parameters)
 
277
                {
 
278
                        log.LogDebug ("Generating signature using signature type {0}", signatureType);
 
279
 
 
280
                        normalizedUrl = null;
 
281
                        parameters = null;
 
282
 
 
283
                        switch (signatureType)
 
284
                        {
 
285
                                case SignatureType.PLAINTEXT:
 
286
                                        var signature = UrlEncode (string.Format ("{0}&{1}", consumerSecret, tokenSecret));
 
287
                                        log.LogDebug ("Plaintext encoding signature {0} of consumer secret and token secret.", signature);
 
288
                                        return signature;
 
289
                                case SignatureType.HMACSHA1:
 
290
                                        string signatureBase = GenerateSignatureBase (url, consumerKey, token, tokenSecret, verifier, method,
 
291
                                                timeStamp, nonce, SignatureType.HMACSHA1, out normalizedUrl, out parameters);
 
292
 
 
293
                                        var hmacsha1 = new HMACSHA1 ();
 
294
                                        hmacsha1.Key = Encoding.ASCII.GetBytes (string.Format ("{0}&{1}",
 
295
                                                UrlEncode (consumerSecret),
 
296
                                                string.IsNullOrEmpty (tokenSecret) ? "" : UrlEncode(tokenSecret)));
 
297
 
 
298
                                        var hashedSignature = GenerateSignatureUsingHash (signatureBase, hmacsha1);
 
299
 
 
300
                                        log.LogDebug ("HMAC-SHA1 encoded signature {0} of consumer secret and token secret.", hashedSignature);
 
301
                                        return hashedSignature;
 
302
                                case SignatureType.RSASHA1:
 
303
                                        throw new NotImplementedException ();
 
304
                                default:
 
305
                                        throw new ArgumentException ("Unknown signature type", "signatureType");
 
306
                        }
 
307
                }
 
308
 
 
309
                /// <summary>
 
310
                /// Generate the timestamp for the signature.
 
311
                /// </summary>
 
312
                /// <returns>A string timestamp.</returns>
 
313
                protected TimeSpan GenerateTimeStamp ()
 
314
                {
 
315
                        log.LogDebug ("Generating time stamp.");
 
316
                        // Default implementation of UNIX time of the current UTC time
 
317
                        return DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
 
318
                }
 
319
 
 
320
                /// <summary>
 
321
                /// Generate a nonce.
 
322
                /// </summary>
 
323
                /// <returns>A random nonce string.</returns>
 
324
                protected virtual string GenerateNonce()
 
325
                {
 
326
                        log.LogDebug ("Generating nonce.");
 
327
                        // Just a simple implementation of a random number between 123400 and 9999999
 
328
                        return random.Next (123400, 9999999).ToString ();
 
329
                }
 
330
        }
331
331
}
 
 
b'\\ No newline at end of file'