Skip to content

Commit

Permalink
Fix for OAuth1SignatureTypes.RsaSha1, this is used by Atlassian Jira.…
Browse files Browse the repository at this point in the history
… Some tests will be made there later.

[release]
  • Loading branch information
Lakritzator committed Sep 8, 2016
1 parent c1f703c commit 414b941
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 37 deletions.
6 changes: 3 additions & 3 deletions Dapplo.HttpExtensions.Shared/HttpResponseMessageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,10 @@ public static async Task<string> HandleErrorAsync(this HttpResponseMessage httpR
Log.Debug().WriteLine("Error while reading the error content: {0}", ex.Message);
}
// Write log if an error occured.
Log.Error().WriteLine("Http response {0} ({1}) for {2}, details from website: {3}", (int) httpResponseMessage.StatusCode, httpResponseMessage.StatusCode, requestUri, errorContent);

Log.Error().WriteLine("Http response {0} ({1}) for {2}, details from website:\n{3}", (int) httpResponseMessage.StatusCode, httpResponseMessage.StatusCode, requestUri, errorContent);
// Add some additional information
switch(httpResponseMessage.StatusCode)
switch (httpResponseMessage.StatusCode)
{
case System.Net.HttpStatusCode.Redirect:
case System.Net.HttpStatusCode.MovedPermanently:
Expand Down
1 change: 1 addition & 0 deletions Dapplo.HttpExtensions.Shared/OAuth/BaseOAuthSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public abstract class BaseOAuthSettings : ICodeReceiverSettings

/// <summary>
/// The OAuth client/consumer secret
/// For OAuth1SignatureTypes.RsaSha1 use RsaSha1Provider instead!
/// </summary>
public string ClientSecret { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ private async Task GenerateRefreshTokenAsync(CancellationToken cancellationToken
/// <returns>HttpResponseMessage</returns>
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage httpRequestMessage, CancellationToken cancellationToken)
{
// TODO: The caller of this DelegatingHandler override is passing a CancellationToken which cancels after a certain time, what to do with this?

// Make sure the first call does the authorization, and all others wait for it.
await _oAuth2Settings.Lock.WaitAsync().ConfigureAwait(false);
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ public static Task<T> ListenAsync<T>(this Uri listenUri, Func<HttpListenerContex
// Make the listener stop if the token is cancelled.
// This registratrion is disposed before the httpListener is disposed:
// ReSharper disable once AccessToDisposedClosure
var cancellationTokenRegistration = cancellationToken.Register(() => httpListener.Stop());
var cancellationTokenRegistration = cancellationToken.Register(() =>
{
httpListener.Stop();
});
// Get the context
var httpListenerContext = await httpListener.GetContextAsync().ConfigureAwait(false);
Expand All @@ -82,7 +85,7 @@ public static Task<T> ListenAsync<T>(this Uri listenUri, Func<HttpListenerContex
cancellationTokenRegistration.Dispose();
// Set the result to the TaskCompletionSource, so the await on the task finishes
taskCompletionSource.SetResult(result);
taskCompletionSource.TrySetResult(result);
}
catch (Exception ex)
{
Expand All @@ -91,12 +94,12 @@ public static Task<T> ListenAsync<T>(this Uri listenUri, Func<HttpListenerContex
// Check if cancel was requested, is so set the taskCompletionSource as cancelled
if (cancellationToken.IsCancellationRequested)
{
taskCompletionSource.SetCanceled();
taskCompletionSource.TrySetCanceled();
}
else
{
// Not cancelled, so we use the exception
taskCompletionSource.SetException(ex);
taskCompletionSource.TrySetException(ex);
}
throw;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
using System.Net.Http;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -87,7 +86,13 @@ public OAuth1HttpMessageHandler(OAuth1Settings oAuth1Settings, OAuth1HttpBehavio
{
throw new ArgumentNullException(nameof(oAuth1Settings.ClientId));
}
if (oAuth1Settings.ClientSecret == null)
if (oAuth1Settings.SignatureType == OAuth1SignatureTypes.RsaSha1)
{
if (oAuth1Settings.RsaSha1Provider == null)
{
throw new ArgumentNullException(nameof(oAuth1Settings.RsaSha1Provider));
}
} else if (oAuth1Settings.ClientSecret == null)
{
throw new ArgumentNullException(nameof(oAuth1Settings.ClientSecret));
}
Expand Down Expand Up @@ -415,44 +420,30 @@ private void Sign(HttpRequestMessage httpRequestMessage)
var secret = string.IsNullOrEmpty(_oAuth1Settings.Token.OAuthTokenSecret)
? string.IsNullOrEmpty(_oAuth1Settings.RequestTokenSecret) ? string.Empty : _oAuth1Settings.RequestTokenSecret
: _oAuth1Settings.Token.OAuthTokenSecret;
var key = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", Uri.EscapeDataString(_oAuth1Settings.ClientSecret), Uri.EscapeDataString(secret));
Log.Verbose().WriteLine("Signing with key {0}", key);
switch (_oAuth1Settings.SignatureType)
{
case OAuth1SignatureTypes.RsaSha1:
// Code comes from here: http://www.dotnetfunda.com/articles/article1932-rest-service-call-using-oauth-10-authorization-with-rsa-sha1.aspx
// Read the .P12 file to read Private/Public key Certificate
var certFilePath = _oAuth1Settings.ClientId; // The .P12 certificate file path Example: "C:/mycertificate/MCOpenAPI.p12
var password = _oAuth1Settings.ClientSecret; // password to read certificate .p12 file
// Read the Certification from .P12 file.
var cert = new X509Certificate2(certFilePath, password);
// Retrieve the Private key from Certificate.
var rsaCrypt = (RSACryptoServiceProvider) cert.PrivateKey;
// Create a RSA-SHA1 Hash object
using (var shaHashObject = new SHA1Managed())
{
// Create Byte Array of Signature base string
var data = Encoding.ASCII.GetBytes(signatureBase.ToString());
// Create Hashmap of Signature base string
var hash = shaHashObject.ComputeHash(data);
// Create Sign Hash of base string
// NOTE - 'SignHash' gives correct data. Don't use SignData method
var rsaSignature = rsaCrypt.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
// Convert to Base64 string
var base64String = Convert.ToBase64String(rsaSignature);
// Return the Encoded UTF8 string
parameters.Add(OAuth1Parameters.Signature.EnumValueOf(), Uri.EscapeDataString(base64String));
}
byte[] dataBuffer = Encoding.UTF8.GetBytes(signatureBase.ToString());
byte[] signatureBytes = _oAuth1Settings.RsaSha1Provider.SignData(dataBuffer, "SHA1");
var base64Signature = Convert.ToBase64String(signatureBytes);
// Return the Encoded UTF8 string
parameters.Add(OAuth1Parameters.Signature.EnumValueOf(), base64Signature);
break;
case OAuth1SignatureTypes.PlainText:
parameters.Add(OAuth1Parameters.Signature.EnumValueOf(), key);
var keyPlain = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", Uri.EscapeDataString(_oAuth1Settings.ClientSecret), Uri.EscapeDataString(secret));
Log.Verbose().WriteLine("Signing with key {0}", keyPlain);
parameters.Add(OAuth1Parameters.Signature.EnumValueOf(), keyPlain);
break;
default:
case OAuth1SignatureTypes.HMacSha1:
// Generate Signature and add it to the parameters
var hmacsha1 = new HMACSHA1 {Key = Encoding.UTF8.GetBytes(key)};
var keySha1 = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", Uri.EscapeDataString(_oAuth1Settings.ClientSecret), Uri.EscapeDataString(secret));
Log.Verbose().WriteLine("Signing with key {0}", keySha1);
var hmacsha1 = new HMACSHA1 {Key = Encoding.UTF8.GetBytes(keySha1) };
var signature = ComputeHash(hmacsha1, signatureBase.ToString());
parameters.Add(OAuth1Parameters.Signature.EnumValueOf(), signature);
break;
default:
throw new ArgumentException("Unknown SignatureType", nameof(_oAuth1Settings.SignatureType));
}

var authorizationHeaderValues = string.Join(", ",
Expand Down
6 changes: 6 additions & 0 deletions Dapplo.HttpExtensions.SharedDesktop/OAuth/OAuth1Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

using System;
using System.Net.Http;
using System.Security.Cryptography;

#endregion

Expand Down Expand Up @@ -69,6 +70,11 @@ public class OAuth1Settings : BaseOAuthSettings
/// </summary>
public OAuth1SignatureTypes SignatureType { get; set; } = OAuth1SignatureTypes.HMacSha1;

/// <summary>
/// For OAuth1SignatureTypes.RsaSha1 set this
/// </summary>
public RSACryptoServiceProvider RsaSha1Provider { get; set; }

/// <summary>
/// The actualy token information, placed in an interface for usage with the Dapplo.Config project
/// the OAuthToken, a default implementation is assigned when the settings are created.
Expand Down

0 comments on commit 414b941

Please sign in to comment.