From ddcb137d5d942341a3b5965879a432e14f688944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A4mes=20M=C3=A9n=C3=A9trey?= Date: Thu, 15 Jul 2021 13:18:57 +0200 Subject: [PATCH] OAuth1: Allow empty customer secrets, according to the specifications. (#1596) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * OAuth1: Allow empty customer secrets, according to the specifications. Signed-off-by: Jämes Ménétrey * Enhance the unit test of the empty consumer secrets to account for the different OAuthTypes. --- .../OAuth/OAuth1Authenticator.cs | 26 +++++++--------- .../Authenticators/OAuth/OAuthTools.cs | 14 ++++----- .../Authenticators/OAuth/OAuthWorkflow.cs | 7 +---- .../OAuth1AuthenticatorTests.cs | 31 +++++++++++++++++++ 4 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs b/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs index f1a02be30..7b3384c56 100644 --- a/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs +++ b/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs @@ -12,15 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +using JetBrains.Annotations; +using RestSharp.Authenticators.OAuth; +using RestSharp.Extensions; using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Web; -using JetBrains.Annotations; -using RestSharp.Authenticators.OAuth; -using RestSharp.Authenticators.OAuth.Extensions; -using RestSharp.Extensions; // ReSharper disable CheckNamespace @@ -42,7 +40,7 @@ public class OAuth1Authenticator : IAuthenticator internal virtual string ConsumerKey { get; set; } - internal virtual string ConsumerSecret { get; set; } + internal virtual string? ConsumerSecret { get; set; } internal virtual string Token { get; set; } @@ -84,7 +82,7 @@ public void Authenticate(IRestClient client, IRestRequest request) public static OAuth1Authenticator ForRequestToken( string consumerKey, - string consumerSecret, + string? consumerSecret, OAuthSignatureMethod signatureMethod = OAuthSignatureMethod.HmacSha1 ) { @@ -101,7 +99,7 @@ public void Authenticate(IRestClient client, IRestRequest request) return authenticator; } - public static OAuth1Authenticator ForRequestToken(string consumerKey, string consumerSecret, string callbackUrl) + public static OAuth1Authenticator ForRequestToken(string consumerKey, string? consumerSecret, string callbackUrl) { var authenticator = ForRequestToken(consumerKey, consumerSecret); @@ -112,7 +110,7 @@ public static OAuth1Authenticator ForRequestToken(string consumerKey, string con public static OAuth1Authenticator ForAccessToken( string consumerKey, - string consumerSecret, + string? consumerSecret, string token, string tokenSecret, OAuthSignatureMethod signatureMethod = OAuthSignatureMethod.HmacSha1 @@ -131,7 +129,7 @@ public static OAuth1Authenticator ForRequestToken(string consumerKey, string con public static OAuth1Authenticator ForAccessToken( string consumerKey, - string consumerSecret, + string? consumerSecret, string token, string tokenSecret, string verifier @@ -155,7 +153,7 @@ string verifier /// public static OAuth1Authenticator ForAccessTokenRefresh( string consumerKey, - string consumerSecret, + string? consumerSecret, string token, string tokenSecret, string sessionHandle @@ -180,7 +178,7 @@ string sessionHandle /// public static OAuth1Authenticator ForAccessTokenRefresh( string consumerKey, - string consumerSecret, + string? consumerSecret, string token, string tokenSecret, string verifier, @@ -206,7 +204,7 @@ string sessionHandle /// public static OAuth1Authenticator ForClientAuthentication( string consumerKey, - string consumerSecret, + string? consumerSecret, string username, string password, OAuthSignatureMethod signatureMethod = OAuthSignatureMethod.HmacSha1 @@ -234,7 +232,7 @@ string sessionHandle /// public static OAuth1Authenticator ForProtectedResource( string consumerKey, - string consumerSecret, + string? consumerSecret, string accessToken, string accessTokenSecret, OAuthSignatureMethod signatureMethod = OAuthSignatureMethod.HmacSha1 diff --git a/src/RestSharp/Authenticators/OAuth/OAuthTools.cs b/src/RestSharp/Authenticators/OAuth/OAuthTools.cs index 9fa723f8b..bc9c36c9f 100644 --- a/src/RestSharp/Authenticators/OAuth/OAuthTools.cs +++ b/src/RestSharp/Authenticators/OAuth/OAuthTools.cs @@ -15,7 +15,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.Serialization; using System.Security.Cryptography; using System.Text; using RestSharp.Authenticators.OAuth.Extensions; @@ -209,7 +208,7 @@ public static string ConcatenateRequestElements(string method, string url, WebPa public static string GetSignature( OAuthSignatureMethod signatureMethod, string signatureBase, - string consumerSecret + string? consumerSecret ) => GetSignature(signatureMethod, OAuthSignatureTreatment.Escaped, signatureBase, consumerSecret, null); @@ -226,7 +225,7 @@ string consumerSecret OAuthSignatureMethod signatureMethod, OAuthSignatureTreatment signatureTreatment, string signatureBase, - string consumerSecret + string? consumerSecret ) => GetSignature(signatureMethod, signatureTreatment, signatureBase, consumerSecret, null); @@ -243,14 +242,15 @@ string consumerSecret OAuthSignatureMethod signatureMethod, OAuthSignatureTreatment signatureTreatment, string signatureBase, - string consumerSecret, + string? consumerSecret, string? tokenSecret ) { - if (tokenSecret.IsEmpty()) tokenSecret = string.Empty; + if (tokenSecret.IsEmpty()) tokenSecret = string.Empty; + if (consumerSecret.IsEmpty()) consumerSecret = string.Empty; - var unencodedConsumerSecret = consumerSecret; - consumerSecret = Uri.EscapeDataString(consumerSecret); + var unencodedConsumerSecret = consumerSecret!; + consumerSecret = Uri.EscapeDataString(consumerSecret!); tokenSecret = Uri.EscapeDataString(tokenSecret!); var signature = signatureMethod switch diff --git a/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs b/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs index 236d74465..fda86f945 100644 --- a/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs +++ b/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs @@ -13,7 +13,6 @@ // limitations under the License. using System; -using System.Collections.Generic; using System.Linq; using System.Web; using RestSharp.Authenticators.OAuth.Extensions; @@ -31,7 +30,7 @@ sealed class OAuthWorkflow public string ConsumerKey { get; set; } - public string ConsumerSecret { get; set; } + public string? ConsumerSecret { get; set; } public string Token { get; set; } @@ -179,14 +178,12 @@ void ValidateTokenRequestState() { Ensure.NotEmpty(RequestTokenUrl, nameof(RequestTokenUrl)); Ensure.NotEmpty(ConsumerKey, nameof(ConsumerKey)); - Ensure.NotEmpty(ConsumerSecret, nameof(ConsumerSecret)); } void ValidateAccessRequestState() { Ensure.NotEmpty(AccessTokenUrl, nameof(AccessTokenUrl)); Ensure.NotEmpty(ConsumerKey, nameof(ConsumerKey)); - Ensure.NotEmpty(ConsumerSecret, nameof(ConsumerSecret)); Ensure.NotEmpty(Token, nameof(Token)); } @@ -194,14 +191,12 @@ void ValidateClientAuthAccessRequestState() { Ensure.NotEmpty(AccessTokenUrl, nameof(AccessTokenUrl)); Ensure.NotEmpty(ConsumerKey, nameof(ConsumerKey)); - Ensure.NotEmpty(ConsumerSecret, nameof(ConsumerSecret)); Ensure.NotEmpty(ClientUsername, nameof(ClientUsername)); } void ValidateProtectedResourceState() { Ensure.NotEmpty(ConsumerKey, nameof(ConsumerKey)); - Ensure.NotEmpty(ConsumerSecret, nameof(ConsumerSecret)); } WebPairCollection GenerateAuthParameters(string timestamp, string nonce) diff --git a/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs b/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs index 9616b29b7..71af9b506 100644 --- a/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs +++ b/test/RestSharp.Tests/OAuth1AuthenticatorTests.cs @@ -166,5 +166,36 @@ public void Authenticate_ShouldEncodeOAuthTokenParameter(OAuthType type,string v Assert.IsNotNull(authHeader); Assert.IsTrue(authHeader.Contains($"oauth_token=\"{expected}\"")); } + + /// + /// According the specifications of OAuth 1.0a, the customer secret is not required. + /// For more information, check the section 4 on https://oauth.net/core/1.0a/. + /// + [Test] + [TestCase(OAuthType.AccessToken)] + [TestCase(OAuthType.ProtectedResource)] + [TestCase(OAuthType.AccessToken)] + [TestCase(OAuthType.ProtectedResource)] + public void Authenticate_ShouldAllowEmptyConsumerSecret_OnHttpAuthorizationHeaderHandling(OAuthType type) + { + // Arrange + const string url = "https://no-query.string"; + + var client = new RestClient(url); + var request = new RestRequest(); + _authenticator.Type = type; + _authenticator.ConsumerSecret = null; + + // Act + _authenticator.Authenticate(client, request); + + // Assert + var authParameter = request.Parameters.Single(x => x.Name == "Authorization"); + var value = (string)authParameter.Value; + + Assert.IsNotEmpty(value); + Assert.IsTrue(value!.Contains("OAuth")); + Assert.IsTrue(value.Contains("oauth_signature=\"" + OAuthTools.UrlEncodeStrict("&"))); + } } }