Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 63 additions & 119 deletions src/Microsoft.AspNetCore.Authentication.Twitter/TwitterHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,53 +148,92 @@ protected override async Task HandleChallengeAsync(AuthenticationProperties prop
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" }
};

if (accessToken != null)
{
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 authorizationKey in authorizationParts)
foreach (var signaturePart in signatureParts)
{
parameterBuilder.AppendFormat("{0}={1}&", UrlEncoder.Encode(authorizationKey.Key), UrlEncoder.Encode(authorizationKey.Value));
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();

Expand All @@ -213,58 +252,8 @@ private async Task<AccessToken> ObtainAccessTokenAsync(RequestToken token, strin

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)
{
Expand All @@ -289,53 +278,8 @@ private async Task<JObject> RetrieveUserDetailsAsync(AccessToken accessToken, Cl
{
Logger.RetrieveUserDetails();

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_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 ExecuteRequestAsync("https://api.twitter.com/1.1/account/verify_credentials.json", HttpMethod.Get, accessToken, queryParameters: new Dictionary<string, string>() { { "include_email", "true" } });

var response = await Backchannel.SendAsync(request, Context.RequestAborted);
if (!response.IsSuccessStatusCode)
{
Logger.LogError("Email request failed with a status code of " + response.StatusCode);
Expand All @@ -361,8 +305,8 @@ private string ComputeSignature(string consumerSecret, string tokenSecret, strin
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);
}
Expand Down