Correct Twitter OAuth signing code & refactor copy/pasted code. #1695 (#1720)

This commit is contained in:
Devin Garner 2018-04-17 10:34:10 -06:00 committed by Chris Ross
parent 6e0377bad8
commit 2e3a1071a8
1 changed files with 64 additions and 120 deletions

View File

@ -148,53 +148,92 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
await Events.RedirectToAuthorizationEndpoint(redirectContext);
}
private async Task<RequestToken> ObtainRequestTokenAsync(string callBackUri, AuthenticationProperties properties)
private async Task<HttpResponseMessage> ExecuteRequestAsync(string url, HttpMethod httpMethod, RequestToken accessToken = null, Dictionary<string, string> extraOAuthPairs = null, Dictionary<string, string> queryParameters = null, Dictionary<string, string> formData = null)
{
Logger.ObtainRequestToken();
var nonce = Guid.NewGuid().ToString("N");
var authorizationParts = new SortedDictionary<string, string>
var authorizationParts = new SortedDictionary<string, string>(extraOAuthPairs ?? new Dictionary<string, string>())
{
{ "oauth_callback", callBackUri },
{ "oauth_consumer_key", Options.ConsumerKey },
{ "oauth_nonce", nonce },
{ "oauth_nonce", Guid.NewGuid().ToString("N") },
{ "oauth_signature_method", "HMAC-SHA1" },
{ "oauth_timestamp", GenerateTimeStamp() },
{ "oauth_version", "1.0" }
};
var parameterBuilder = new StringBuilder();
foreach (var authorizationKey in authorizationParts)
if (accessToken != null)
{
parameterBuilder.AppendFormat("{0}={1}&", UrlEncoder.Encode(authorizationKey.Key), UrlEncoder.Encode(authorizationKey.Value));
authorizationParts.Add("oauth_token", accessToken.Token);
}
var signatureParts = new SortedDictionary<string, string>(authorizationParts);
if (queryParameters != null)
{
foreach (var queryParameter in queryParameters)
{
signatureParts.Add(queryParameter.Key, queryParameter.Value);
}
}
if (formData != null)
{
foreach (var formItem in formData)
{
signatureParts.Add(formItem.Key, formItem.Value);
}
}
var parameterBuilder = new StringBuilder();
foreach (var signaturePart in signatureParts)
{
parameterBuilder.AppendFormat("{0}={1}&", Uri.EscapeDataString(signaturePart.Key), Uri.EscapeDataString(signaturePart.Value));
}
parameterBuilder.Length--;
var parameterString = parameterBuilder.ToString();
var canonicalizedRequestBuilder = new StringBuilder();
canonicalizedRequestBuilder.Append(HttpMethod.Post.Method);
canonicalizedRequestBuilder.Append(httpMethod.Method);
canonicalizedRequestBuilder.Append("&");
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(RequestTokenEndpoint));
canonicalizedRequestBuilder.Append(Uri.EscapeDataString(url));
canonicalizedRequestBuilder.Append("&");
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString));
canonicalizedRequestBuilder.Append(Uri.EscapeDataString(parameterString));
var signature = ComputeSignature(Options.ConsumerSecret, null, canonicalizedRequestBuilder.ToString());
var signature = ComputeSignature(Options.ConsumerSecret, accessToken?.TokenSecret, canonicalizedRequestBuilder.ToString());
authorizationParts.Add("oauth_signature", signature);
var queryString = "";
if (queryParameters != null)
{
var queryStringBuilder = new StringBuilder("?");
foreach (var queryParam in queryParameters)
{
queryStringBuilder.AppendFormat("{0}={1}&", queryParam.Key, queryParam.Value);
}
queryStringBuilder.Length--;
queryString = queryStringBuilder.ToString();
}
var authorizationHeaderBuilder = new StringBuilder();
authorizationHeaderBuilder.Append("OAuth ");
foreach (var authorizationPart in authorizationParts)
{
authorizationHeaderBuilder.AppendFormat(
"{0}=\"{1}\", ", authorizationPart.Key, UrlEncoder.Encode(authorizationPart.Value));
authorizationHeaderBuilder.AppendFormat("{0}=\"{1}\",", authorizationPart.Key, Uri.EscapeDataString(authorizationPart.Value));
}
authorizationHeaderBuilder.Length = authorizationHeaderBuilder.Length - 2;
authorizationHeaderBuilder.Length--;
var request = new HttpRequestMessage(HttpMethod.Post, RequestTokenEndpoint);
var request = new HttpRequestMessage(httpMethod, url + queryString);
request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString());
var response = await Backchannel.SendAsync(request, Context.RequestAborted);
if (formData != null)
{
request.Content = new FormUrlEncodedContent(formData);
}
return await Backchannel.SendAsync(request, Context.RequestAborted);
}
private async Task<RequestToken> ObtainRequestTokenAsync(string callBackUri, AuthenticationProperties properties)
{
Logger.ObtainRequestToken();
var response = await ExecuteRequestAsync(RequestTokenEndpoint, HttpMethod.Post, extraOAuthPairs: new Dictionary<string, string>() { { "oauth_callback", callBackUri } });
response.EnsureSuccessStatusCode();
var responseText = await response.Content.ReadAsStringAsync();
@ -213,58 +252,8 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
Logger.ObtainAccessToken();
var nonce = Guid.NewGuid().ToString("N");
var authorizationParts = new SortedDictionary<string, string>
{
{ "oauth_consumer_key", Options.ConsumerKey },
{ "oauth_nonce", nonce },
{ "oauth_signature_method", "HMAC-SHA1" },
{ "oauth_token", token.Token },
{ "oauth_timestamp", GenerateTimeStamp() },
{ "oauth_verifier", verifier },
{ "oauth_version", "1.0" },
};
var parameterBuilder = new StringBuilder();
foreach (var authorizationKey in authorizationParts)
{
parameterBuilder.AppendFormat("{0}={1}&", UrlEncoder.Encode(authorizationKey.Key), UrlEncoder.Encode(authorizationKey.Value));
}
parameterBuilder.Length--;
var parameterString = parameterBuilder.ToString();
var canonicalizedRequestBuilder = new StringBuilder();
canonicalizedRequestBuilder.Append(HttpMethod.Post.Method);
canonicalizedRequestBuilder.Append("&");
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(AccessTokenEndpoint));
canonicalizedRequestBuilder.Append("&");
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString));
var signature = ComputeSignature(Options.ConsumerSecret, token.TokenSecret, canonicalizedRequestBuilder.ToString());
authorizationParts.Add("oauth_signature", signature);
authorizationParts.Remove("oauth_verifier");
var authorizationHeaderBuilder = new StringBuilder();
authorizationHeaderBuilder.Append("OAuth ");
foreach (var authorizationPart in authorizationParts)
{
authorizationHeaderBuilder.AppendFormat(
"{0}=\"{1}\", ", authorizationPart.Key, UrlEncoder.Encode(authorizationPart.Value));
}
authorizationHeaderBuilder.Length = authorizationHeaderBuilder.Length - 2;
var request = new HttpRequestMessage(HttpMethod.Post, AccessTokenEndpoint);
request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString());
var formPairs = new Dictionary<string, string>()
{
{ "oauth_verifier", verifier },
};
request.Content = new FormUrlEncodedContent(formPairs);
var response = await Backchannel.SendAsync(request, Context.RequestAborted);
var formPost = new Dictionary<string, string> { { "oauth_verifier", verifier } };
var response = await ExecuteRequestAsync(AccessTokenEndpoint, HttpMethod.Post, token, formData: formPost);
if (!response.IsSuccessStatusCode)
{
@ -289,53 +278,8 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
{
Logger.RetrieveUserDetails();
var nonce = Guid.NewGuid().ToString("N");
var response = await ExecuteRequestAsync("https://api.twitter.com/1.1/account/verify_credentials.json", HttpMethod.Get, accessToken, queryParameters: new Dictionary<string, string>() { { "include_email", "true" } });
var authorizationParts = new SortedDictionary<string, string>
{
{ "oauth_consumer_key", Options.ConsumerKey },
{ "oauth_nonce", nonce },
{ "oauth_signature_method", "HMAC-SHA1" },
{ "oauth_timestamp", GenerateTimeStamp() },
{ "oauth_token", accessToken.Token },
{ "oauth_version", "1.0" }
};
var parameterBuilder = new StringBuilder();
foreach (var authorizationKey in authorizationParts)
{
parameterBuilder.AppendFormat("{0}={1}&", UrlEncoder.Encode(authorizationKey.Key), UrlEncoder.Encode(authorizationKey.Value));
}
parameterBuilder.Length--;
var parameterString = parameterBuilder.ToString();
var resource_url = "https://api.twitter.com/1.1/account/verify_credentials.json";
var resource_query = "include_email=true";
var canonicalizedRequestBuilder = new StringBuilder();
canonicalizedRequestBuilder.Append(HttpMethod.Get.Method);
canonicalizedRequestBuilder.Append("&");
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(resource_url));
canonicalizedRequestBuilder.Append("&");
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(resource_query));
canonicalizedRequestBuilder.Append("%26");
canonicalizedRequestBuilder.Append(UrlEncoder.Encode(parameterString));
var signature = ComputeSignature(Options.ConsumerSecret, accessToken.TokenSecret, canonicalizedRequestBuilder.ToString());
authorizationParts.Add("oauth_signature", signature);
var authorizationHeaderBuilder = new StringBuilder();
authorizationHeaderBuilder.Append("OAuth ");
foreach (var authorizationPart in authorizationParts)
{
authorizationHeaderBuilder.AppendFormat(
"{0}=\"{1}\", ", authorizationPart.Key, UrlEncoder.Encode(authorizationPart.Value));
}
authorizationHeaderBuilder.Length = authorizationHeaderBuilder.Length - 2;
var request = new HttpRequestMessage(HttpMethod.Get, resource_url + "?include_email=true");
request.Headers.Add("Authorization", authorizationHeaderBuilder.ToString());
var response = await Backchannel.SendAsync(request, Context.RequestAborted);
if (!response.IsSuccessStatusCode)
{
Logger.LogError("Email request failed with a status code of " + response.StatusCode);
@ -361,8 +305,8 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
algorithm.Key = Encoding.ASCII.GetBytes(
string.Format(CultureInfo.InvariantCulture,
"{0}&{1}",
UrlEncoder.Encode(consumerSecret),
string.IsNullOrEmpty(tokenSecret) ? string.Empty : UrlEncoder.Encode(tokenSecret)));
Uri.EscapeDataString(consumerSecret),
string.IsNullOrEmpty(tokenSecret) ? string.Empty : Uri.EscapeDataString(tokenSecret)));
var hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(signatureData));
return Convert.ToBase64String(hash);
}