2 using System.Collections.Generic;
3 using Hammock.Extensions;
5 #if !SILVERLIGHT && !MonoTouch &&!NETCF
10 using System.Compat.Web;
13 namespace Hammock.Authentication.OAuth
16 /// A class to encapsulate OAuth authentication flow.
17 /// <seealso cref="http://oauth.net/core/1.0#anchor9"/>
19 public class OAuthWorkflow
21 public virtual string Version { get; set; }
22 public virtual string ConsumerKey { get; set; }
23 public virtual string ConsumerSecret { get; set; }
24 public virtual string Token { get; set; }
25 public virtual string TokenSecret { get; set; }
26 public virtual string CallbackUrl { get; set; }
27 public virtual string Verifier { get; set; }
28 public virtual string SessionHandle { get; set; }
30 public virtual OAuthSignatureMethod SignatureMethod { get; set; }
31 public virtual OAuthSignatureTreatment SignatureTreatment { get; set; }
32 public virtual OAuthParameterHandling ParameterHandling { get; set; }
34 public virtual string ClientUsername { get; set; }
35 public virtual string ClientPassword { get; set; }
37 /// <seealso cref="http://oauth.net/core/1.0#request_urls"/>
38 public virtual string RequestTokenUrl { get; set; }
40 /// <seealso cref="http://oauth.net/core/1.0#request_urls"/>
41 public virtual string AccessTokenUrl { get; set; }
43 /// <seealso cref="http://oauth.net/core/1.0#request_urls"/>
44 public virtual string AuthorizationUrl { get; set; }
47 /// Generates a <see cref="OAuthWebQueryInfo"/> instance to pass to an
48 /// <see cref="OAuthWebQuery" /> for the purpose of requesting an
49 /// unauthorized request token.
51 /// <param name="method">The HTTP method for the intended request</param>
52 /// <seealso cref="http://oauth.net/core/1.0#anchor9"/>
53 /// <returns></returns>
54 public OAuthWebQueryInfo BuildRequestTokenInfo(WebMethod method)
56 return BuildRequestTokenInfo(method, null);
59 public OAuthWorkflow()
65 /// Creates a new instance of <see cref="OAuthWorkflow" /> using
66 /// an <see cref="OAuthCredentials" /> instance.
68 /// <param name="credentials">The credentials to copy</param>
69 public OAuthWorkflow(OAuthCredentials credentials)
71 InitializeFromCredentials(credentials);
74 private void InitializeFromCredentials(OAuthCredentials credentials)
76 ConsumerKey = credentials.ConsumerKey;
77 ConsumerSecret = credentials.ConsumerSecret;
78 ParameterHandling = credentials.ParameterHandling;
79 SignatureMethod = credentials.SignatureMethod;
80 SignatureTreatment = credentials.SignatureTreatment;
81 Token = credentials.Token;
82 TokenSecret = credentials.TokenSecret;
83 Verifier = credentials.Verifier;
84 ClientUsername = credentials.ClientUsername;
85 ClientPassword = credentials.ClientPassword;
86 CallbackUrl = credentials.CallbackUrl;
87 Version = credentials.Version;
88 SessionHandle = credentials.SessionHandle;
92 /// Generates a <see cref="OAuthWebQueryInfo"/> instance to pass to an
93 /// <see cref="OAuthWebQuery" /> for the purpose of requesting an
94 /// unauthorized request token.
96 /// <param name="method">The HTTP method for the intended request</param>
97 /// <param name="parameters">Any existing, non-OAuth query parameters desired in the request</param>
98 /// <seealso cref="http://oauth.net/core/1.0#anchor9"/>
99 /// <returns></returns>
100 public virtual OAuthWebQueryInfo BuildRequestTokenInfo(WebMethod method, WebParameterCollection parameters)
102 ValidateTokenRequestState();
104 if (parameters == null)
106 parameters = new WebParameterCollection();
109 var timestamp = OAuthTools.GetTimestamp();
110 var nonce = OAuthTools.GetNonce();
112 AddAuthParameters(parameters, timestamp, nonce);
114 var signatureBase = OAuthTools.ConcatenateRequestElements(method, RequestTokenUrl, parameters);
115 var signature = OAuthTools.GetSignature(SignatureMethod, SignatureTreatment, signatureBase, ConsumerSecret);
117 var info = new OAuthWebQueryInfo
120 ParameterHandling = ParameterHandling,
121 ConsumerKey = ConsumerKey,
122 SignatureMethod = SignatureMethod.ToRequestValue(),
123 SignatureTreatment = SignatureTreatment,
124 Signature = signature,
125 Timestamp = timestamp,
128 Callback = OAuthTools.UrlEncodeRelaxed(CallbackUrl ?? ""),
129 UserAgent = "Hammock",
130 TokenSecret = TokenSecret,
131 ConsumerSecret = ConsumerSecret
138 /// Generates a <see cref="OAuthWebQueryInfo"/> instance to pass to an
139 /// <see cref="OAuthWebQuery" /> for the purpose of exchanging a request token
140 /// for an access token authorized by the user at the Service Provider site.
142 /// <param name="method">The HTTP method for the intended request</param>
143 /// <seealso cref="http://oauth.net/core/1.0#anchor9"/>
144 public virtual OAuthWebQueryInfo BuildAccessTokenInfo(WebMethod method)
146 return BuildAccessTokenInfo(method, null);
150 /// Generates a <see cref="OAuthWebQueryInfo"/> instance to pass to an
151 /// <see cref="OAuthWebQuery" /> for the purpose of exchanging a request token
152 /// for an access token authorized by the user at the Service Provider site.
154 /// <param name="method">The HTTP method for the intended request</param>
155 /// <seealso cref="http://oauth.net/core/1.0#anchor9"/>
156 /// <param name="parameters">Any existing, non-OAuth query parameters desired in the request</param>
157 public virtual OAuthWebQueryInfo BuildAccessTokenInfo(WebMethod method, WebParameterCollection parameters)
159 ValidateAccessRequestState();
161 if (parameters == null)
163 parameters = new WebParameterCollection();
166 var uri = new Uri(AccessTokenUrl);
167 var timestamp = OAuthTools.GetTimestamp();
168 var nonce = OAuthTools.GetNonce();
170 AddAuthParameters(parameters, timestamp, nonce);
172 var signatureBase = OAuthTools.ConcatenateRequestElements(method, uri.ToString(), parameters);
173 var signature = OAuthTools.GetSignature(SignatureMethod, SignatureTreatment, signatureBase, ConsumerSecret, TokenSecret);
175 var info = new OAuthWebQueryInfo
178 ParameterHandling = ParameterHandling,
179 ConsumerKey = ConsumerKey,
181 SignatureMethod = SignatureMethod.ToRequestValue(),
182 SignatureTreatment = SignatureTreatment,
183 Signature = signature,
184 Timestamp = timestamp,
188 Callback = CallbackUrl,
189 UserAgent = "Hammock",
190 TokenSecret = TokenSecret,
191 ConsumerSecret = ConsumerSecret,
198 /// Generates a <see cref="OAuthWebQueryInfo"/> instance to pass to an
199 /// <see cref="OAuthWebQuery" /> for the purpose of exchanging user credentials
200 /// for an access token authorized by the user at the Service Provider site.
202 /// <param name="method">The HTTP method for the intended request</param>
203 /// <seealso cref="http://tools.ietf.org/html/draft-dehora-farrell-oauth-accesstoken-creds-00#section-4"/>
204 /// <param name="parameters">Any existing, non-OAuth query parameters desired in the request</param>
205 public virtual OAuthWebQueryInfo BuildClientAuthAccessTokenInfo(WebMethod method, WebParameterCollection parameters)
207 ValidateClientAuthAccessRequestState();
209 if (parameters == null)
211 parameters = new WebParameterCollection();
214 var uri = new Uri(AccessTokenUrl);
215 var timestamp = OAuthTools.GetTimestamp();
216 var nonce = OAuthTools.GetNonce();
218 AddXAuthParameters(parameters, timestamp, nonce);
220 var signatureBase = OAuthTools.ConcatenateRequestElements(method, uri.ToString(), parameters);
221 var signature = OAuthTools.GetSignature(SignatureMethod, SignatureTreatment, signatureBase, ConsumerSecret);
223 var info = new OAuthWebQueryInfo
226 ParameterHandling = ParameterHandling,
227 ClientMode = "client_auth",
228 ClientUsername = ClientUsername,
229 ClientPassword = ClientPassword,
230 ConsumerKey = ConsumerKey,
231 SignatureMethod = SignatureMethod.ToRequestValue(),
232 SignatureTreatment = SignatureTreatment,
233 Signature = signature,
234 Timestamp = timestamp,
237 UserAgent = "Hammock",
238 TokenSecret = TokenSecret,
239 ConsumerSecret = ConsumerSecret
245 public virtual OAuthWebQueryInfo BuildProtectedResourceInfo(WebMethod method,
246 WebParameterCollection parameters,
249 ValidateProtectedResourceState();
251 if (parameters == null)
253 parameters = new WebParameterCollection();
256 // Include url parameters in query pool
257 var uri = new Uri(url);
259 var urlParameters = System.Compat.Web.HttpUtility.ParseQueryString(uri.Query);
261 var urlParameters = uri.Query.ParseQueryString();
265 foreach (var parameter in urlParameters.AllKeys)
267 foreach (var parameter in urlParameters.Keys)
273 parameters.Add(new HttpPostParameter(parameter, urlParameters[parameter]));
276 parameters.Add(parameter, urlParameters[parameter]);
281 var timestamp = OAuthTools.GetTimestamp();
282 var nonce = OAuthTools.GetNonce();
284 // [DC] Make a copy of the parameters so that the signature double-encode isn't used
285 var copy = new WebParameterCollection();
286 foreach(var parameter in parameters)
288 copy.Add(new WebPair(parameter.Name, parameter.Value));
291 AddAuthParameters(copy, timestamp, nonce);
293 // [DC] Escape parameters at this point; do not escape again if recalculating
294 var signatureBase = OAuthTools.ConcatenateRequestElements(method, url, copy);
295 var signature = OAuthTools.GetSignature(
296 SignatureMethod, SignatureTreatment, signatureBase, ConsumerSecret, TokenSecret
299 var info = new OAuthWebQueryInfo
302 ParameterHandling = ParameterHandling,
303 ConsumerKey = ConsumerKey,
305 SignatureMethod = SignatureMethod.ToRequestValue(),
306 SignatureTreatment = SignatureTreatment,
307 Signature = signature,
308 Timestamp = timestamp,
310 Version = Version ?? "1.0",
311 Callback = CallbackUrl,
312 UserAgent = "Hammock",
313 ConsumerSecret = ConsumerSecret,
314 TokenSecret = TokenSecret
320 private void ValidateTokenRequestState()
322 if (RequestTokenUrl.IsNullOrBlank())
324 throw new ArgumentException("You must specify a request token URL");
327 if (ConsumerKey.IsNullOrBlank())
329 throw new ArgumentException("You must specify a consumer key");
332 if (ConsumerSecret.IsNullOrBlank())
334 throw new ArgumentException("You must specify a consumer secret");
338 private void ValidateAccessRequestState()
340 if (AccessTokenUrl.IsNullOrBlank())
342 throw new ArgumentException("You must specify an access token URL");
345 if (ConsumerKey.IsNullOrBlank())
347 throw new ArgumentException("You must specify a consumer key");
350 if (ConsumerSecret.IsNullOrBlank())
352 throw new ArgumentException("You must specify a consumer secret");
355 if (Token.IsNullOrBlank())
357 throw new ArgumentException("You must specify a token");
361 private void ValidateClientAuthAccessRequestState()
363 if (AccessTokenUrl.IsNullOrBlank())
365 throw new ArgumentException("You must specify an access token URL");
368 if (ConsumerKey.IsNullOrBlank())
370 throw new ArgumentException("You must specify a consumer key");
373 if (ConsumerSecret.IsNullOrBlank())
375 throw new ArgumentException("You must specify a consumer secret");
378 if (ClientUsername.IsNullOrBlank() || ClientPassword.IsNullOrBlank())
380 throw new ArgumentException("You must specify user credentials");
384 private void ValidateProtectedResourceState()
386 if (ConsumerKey.IsNullOrBlank())
388 throw new ArgumentException("You must specify a consumer key");
391 if (ConsumerSecret.IsNullOrBlank())
393 throw new ArgumentException("You must specify a consumer secret");
397 if (Token.IsNullOrBlank())
399 throw new ArgumentException("You must specify a token");
402 if (TokenSecret.IsNullOrBlank())
404 throw new ArgumentException("You must specify a token secret");
409 private void AddAuthParameters(ICollection<WebPair> parameters, string timestamp, string nonce)
411 var authParameters = new WebParameterCollection
413 new WebPair("oauth_consumer_key", ConsumerKey),
414 new WebPair("oauth_nonce", nonce),
415 new WebPair("oauth_signature_method", SignatureMethod.ToRequestValue()),
416 new WebPair("oauth_timestamp", timestamp),
417 new WebPair("oauth_version", Version ?? "1.0")
420 if (!Token.IsNullOrBlank())
422 authParameters.Add(new WebPair("oauth_token", Token));
425 if (!CallbackUrl.IsNullOrBlank())
427 authParameters.Add(new WebPair("oauth_callback", CallbackUrl));
430 if (!Verifier.IsNullOrBlank())
432 authParameters.Add(new WebPair("oauth_verifier", Verifier));
435 if(!SessionHandle.IsNullOrBlank())
437 authParameters.Add(new WebPair("oauth_session_handle", SessionHandle));
440 foreach (var authParameter in authParameters)
442 parameters.Add(authParameter);
446 private void AddXAuthParameters(ICollection<WebPair> parameters, string timestamp, string nonce)
448 var authParameters = new WebParameterCollection
450 new WebPair("x_auth_username", ClientUsername),
451 new WebPair("x_auth_password", ClientPassword),
452 new WebPair("x_auth_mode", "client_auth"),
453 new WebPair("oauth_consumer_key", ConsumerKey),
454 new WebPair("oauth_signature_method", SignatureMethod.ToRequestValue()),
455 new WebPair("oauth_timestamp", timestamp),
456 new WebPair("oauth_nonce", nonce),
457 new WebPair("oauth_version", Version ?? "1.0")
460 foreach (var authParameter in authParameters)
462 parameters.Add(authParameter);