Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion src/RestSharp/Authenticators/AuthenticatorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace RestSharp.Authenticators;
public abstract class AuthenticatorBase : IAuthenticator {
protected AuthenticatorBase(string token) => Token = token;

protected string Token { get; }
protected string Token { get; set; }

protected abstract ValueTask<Parameter> GetAuthenticationParameter(string accessToken);

Expand Down
2 changes: 1 addition & 1 deletion src/RestSharp/Authenticators/HttpBasicAuthenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@ static string GetHeader(string username, string password, Encoding encoding)

// return ;
protected override ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
=> new(new Parameter("Authorization", $"Basic {accessToken}", ParameterType.HttpHeader));
=> new(new Parameter(KnownHeaders.Authorization, $"Basic {accessToken}", ParameterType.HttpHeader, false));
}
17 changes: 7 additions & 10 deletions src/RestSharp/Authenticators/JwtAuthenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,18 @@ namespace RestSharp.Authenticators;
/// JSON WEB TOKEN (JWT) Authenticator class.
/// <remarks>https://tools.ietf.org/html/draft-ietf-oauth-json-web-token</remarks>
/// </summary>
public class JwtAuthenticator : IAuthenticator {
string _authHeader = null!;

// ReSharper disable once IntroduceOptionalParameters.Global
public JwtAuthenticator(string accessToken) => SetBearerToken(accessToken);
public class JwtAuthenticator : AuthenticatorBase {
public JwtAuthenticator(string accessToken) : base(GetToken(accessToken)) { }

/// <summary>
/// Set the new bearer token so the request gets the new header value
/// </summary>
/// <param name="accessToken"></param>
[PublicAPI]
public void SetBearerToken(string accessToken) => _authHeader = $"Bearer {Ensure.NotEmpty(accessToken, nameof(accessToken))}";
public void SetBearerToken(string accessToken) => Token = GetToken(accessToken);

static string GetToken(string accessToken) => $"Bearer {Ensure.NotEmpty(accessToken, nameof(accessToken))}";

public ValueTask Authenticate(RestClient client, RestRequest request) {
request.AddOrUpdateParameter("Authorization", _authHeader, ParameterType.HttpHeader);
return default;
}
protected override ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
=> new(new Parameter(KnownHeaders.Authorization, accessToken, ParameterType.HttpHeader, false));
}
14 changes: 7 additions & 7 deletions src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public class OAuth1Authenticator : IAuthenticator {

public ValueTask Authenticate(RestClient client, RestRequest request) {
var workflow = new OAuthWorkflow {
ConsumerKey = ConsumerKey,
ConsumerSecret = ConsumerSecret,
// ParameterHandling = ParameterHandling,
ConsumerKey = ConsumerKey,
ConsumerSecret = ConsumerSecret,
ParameterHandling = ParameterHandling,
SignatureMethod = SignatureMethod,
SignatureTreatment = SignatureTreatment,
Verifier = Verifier,
Expand Down Expand Up @@ -191,7 +191,7 @@ public static OAuth1Authenticator ForProtectedResource(
};

void AddOAuthData(RestClient client, RestRequest request, OAuthWorkflow workflow) {
var requestUrl = client.BuildUriWithoutQueryParameters(request);
var requestUrl = client.BuildUriWithoutQueryParameters(request).AbsoluteUri;

if (requestUrl.Contains('?'))
throw new ApplicationException(
Expand Down Expand Up @@ -233,7 +233,7 @@ void AddOAuthData(RestClient client, RestRequest request, OAuthWorkflow workflow
OAuthType.AccessToken => workflow.BuildAccessTokenSignature(method, parameters),
OAuthType.ClientAuthentication => workflow.BuildClientAuthAccessTokenSignature(method, parameters),
OAuthType.ProtectedResource => workflow.BuildProtectedResourceSignature(method, parameters, url),
_ => throw new ArgumentOutOfRangeException()
_ => throw new ArgumentOutOfRangeException(nameof(Type))
};

oauth.Parameters.Add("oauth_signature", oauth.Signature);
Expand All @@ -242,13 +242,13 @@ void AddOAuthData(RestClient client, RestRequest request, OAuthWorkflow workflow
OAuthParameterHandling.HttpAuthorizationHeader => CreateHeaderParameters(),
OAuthParameterHandling.UrlOrPostParameters => CreateUrlParameters(),
_ =>
throw new ArgumentOutOfRangeException()
throw new ArgumentOutOfRangeException(nameof(ParameterHandling))
};

request.AddOrUpdateParameters(oauthParameters);

IEnumerable<Parameter> CreateHeaderParameters()
=> new[] { new Parameter("Authorization", GetAuthorizationHeader(), ParameterType.HttpHeader) };
=> new[] { new Parameter(KnownHeaders.Authorization, GetAuthorizationHeader(), ParameterType.HttpHeader) };

IEnumerable<Parameter> CreateUrlParameters()
=> oauth.Parameters.Select(p => new Parameter(p.Name, HttpUtility.UrlDecode(p.Value), ParameterType.GetOrPost));
Expand Down
45 changes: 18 additions & 27 deletions src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

using System.Web;
using RestSharp.Authenticators.OAuth.Extensions;
using RestSharp.Extensions;

namespace RestSharp.Authenticators.OAuth;

Expand All @@ -32,11 +31,11 @@ sealed class OAuthWorkflow {
public string? SessionHandle { get; set; }
public OAuthSignatureMethod SignatureMethod { get; set; }
public OAuthSignatureTreatment SignatureTreatment { get; set; }
// public OAuthParameterHandling ParameterHandling { get; set; }
public string? ClientUsername { get; set; }
public string? ClientPassword { get; set; }
public string? RequestTokenUrl { get; set; }
public string? AccessTokenUrl { get; set; }
public OAuthParameterHandling ParameterHandling { get; set; }
public string? ClientUsername { get; set; }
public string? ClientPassword { get; set; }
public string? RequestTokenUrl { get; set; }
public string? AccessTokenUrl { get; set; }

/// <summary>
/// Generates an OAuth signature to pass to an
Expand Down Expand Up @@ -169,32 +168,24 @@ void ValidateProtectedResourceState() {
Ensure.NotEmpty(ConsumerKey, nameof(ConsumerKey));
}

WebPairCollection GenerateAuthParameters(string timestamp, string nonce) {
var authParameters = new WebPairCollection {
new("oauth_consumer_key", Ensure.NotNull(ConsumerKey, nameof(ConsumerKey))),
new("oauth_nonce", nonce),
new("oauth_signature_method", SignatureMethod.ToRequestValue()),
new("oauth_timestamp", timestamp),
new("oauth_version", Version ?? "1.0")
};

if (!Token.IsEmpty()) authParameters.Add(new WebPair("oauth_token", Token!, true));

if (!CallbackUrl.IsEmpty()) authParameters.Add(new WebPair("oauth_callback", CallbackUrl!, true));

if (!Verifier.IsEmpty()) authParameters.Add(new WebPair("oauth_verifier", Verifier!));

if (!SessionHandle.IsEmpty()) authParameters.Add(new WebPair("oauth_session_handle", SessionHandle!));

return authParameters;
}
WebPairCollection GenerateAuthParameters(string timestamp, string nonce)
=> new WebPairCollection {
new("oauth_consumer_key", Ensure.NotNull(ConsumerKey, nameof(ConsumerKey)), true),
new("oauth_nonce", nonce),
new("oauth_signature_method", SignatureMethod.ToRequestValue()),
new("oauth_timestamp", timestamp),
new("oauth_version", Version ?? "1.0")
}.AddNotEmpty("oauth_token", Token!, true)
.AddNotEmpty("oauth_callback", CallbackUrl!, true)
.AddNotEmpty("oauth_verifier", Verifier!)
.AddNotEmpty("oauth_session_handle", SessionHandle!);

WebPairCollection GenerateXAuthParameters(string timestamp, string nonce)
=> new() {
=> new WebPairCollection {
new("x_auth_username", Ensure.NotNull(ClientUsername, nameof(ClientUsername))),
new("x_auth_password", Ensure.NotNull(ClientPassword, nameof(ClientPassword))),
new("x_auth_mode", "client_auth"),
new("oauth_consumer_key", Ensure.NotNull(ConsumerKey, nameof(ConsumerKey))),
new("oauth_consumer_key", Ensure.NotNull(ConsumerKey, nameof(ConsumerKey)), true),
new("oauth_signature_method", SignatureMethod.ToRequestValue()),
new("oauth_timestamp", timestamp),
new("oauth_nonce", nonce),
Expand Down
6 changes: 6 additions & 0 deletions src/RestSharp/Authenticators/OAuth/WebPairCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ class WebPairCollection : IList<WebPair> {
public void AddRange(IEnumerable<WebPair> collection) => AddCollection(collection);

public void Add(string name, string value) => Add(new WebPair(name, value));

public WebPairCollection AddNotEmpty(string name, string? value, bool encode = false) {
if (value != null)
Add(new WebPair(name, value, encode));
return this;
}

public void Clear() => _parameters.Clear();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ public OAuth2AuthorizationRequestHeaderAuthenticator(string accessToken)
public OAuth2AuthorizationRequestHeaderAuthenticator(string accessToken, string tokenType) : base(accessToken) => _tokenType = tokenType;

protected override ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
=> new(new Parameter("Authorization", $"{_tokenType} {accessToken}", ParameterType.HttpHeader));
=> new(new Parameter(KnownHeaders.Authorization, $"{_tokenType} {accessToken}", ParameterType.HttpHeader));
}
1 change: 1 addition & 0 deletions src/RestSharp/KnownHeaders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
namespace RestSharp;

public static class KnownHeaders {
public const string Authorization = "Authorization";
public const string Accept = "Accept";
public const string Allow = "Allow";
public const string Expires = "Expires";
Expand Down
1 change: 0 additions & 1 deletion src/RestSharp/Parameters/Parameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ public Parameter(string name, object value, string contentType, ParameterType ty
/// </summary>
/// <returns>String</returns>
public override string ToString() => $"{Name}={Value}";

}

public record XmlParameter : Parameter {
Expand Down
72 changes: 72 additions & 0 deletions src/RestSharp/Parameters/ParametersCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright © 2009-2020 John Sheehan, Andrew Young, Alexey Zimarev and RestSharp community
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

using System.Collections;
using System.Collections.Concurrent;
using RestSharp.Authenticators.OAuth.Extensions;

namespace RestSharp;

public class ParametersCollection : IReadOnlyCollection<Parameter> {
readonly List<Parameter> _parameters = new();

public ParametersCollection() { }

public ParametersCollection(IEnumerable<Parameter> parameters) => _parameters.AddRange(parameters);

public ParametersCollection AddParameters(IEnumerable<Parameter> parameters) {
_parameters.AddRange(parameters);
return this;
}

public ParametersCollection AddParameters(ParametersCollection parameters) {
_parameters.AddRange(parameters);
return this;
}

public void AddParameter(Parameter parameter) => _parameters.Add(parameter);

public void RemoveParameter(string name) => _parameters.RemoveAll(x => x.Name == name);

public void RemoveParameter(Parameter parameter) => _parameters.Remove(parameter);

public bool Exists(Parameter parameter)
=> _parameters.Any(
p => p.Name != null && p.Name.Equals(parameter.Name, StringComparison.InvariantCultureIgnoreCase) && p.Type == parameter.Type
);

public Parameter? TryFind(string parameterName) => _parameters.FirstOrDefault(x => x.Name != null && x.Name.EqualsIgnoreCase(parameterName));

internal ParametersCollection GetParameters(ParameterType parameterType) => new(_parameters.Where(x => x.Type == parameterType));

internal ParametersCollection GetQueryParameters(Method method)
=> new(
method is not Method.Post and not Method.Put and not Method.Patch
? _parameters
.Where(
p => p.Type is ParameterType.GetOrPost or ParameterType.QueryString
)
: _parameters
.Where(
p => p.Type is ParameterType.QueryString
)
);

public IEnumerator<Parameter> GetEnumerator() => _parameters.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

public int Count => _parameters.Count;
}
13 changes: 9 additions & 4 deletions src/RestSharp/Request/HttpRequestMessageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,24 @@
// limitations under the License.
//

using System.Text;
using RestSharp.Extensions;

namespace RestSharp;
namespace RestSharp;

static class HttpRequestMessageExtensions {
public static void AddHeaders(this HttpRequestMessage message, IEnumerable<Parameter> parameters) {
public static void AddHeaders(this HttpRequestMessage message, ParametersCollection parameters, Func<string, string> encode) {
var headerParameters = parameters
.Where(x => x.Type == ParameterType.HttpHeader && !RequestContent.ContentHeaders.Contains(x.Name));
.GetParameters(ParameterType.HttpHeader)
.Where(x => !RequestContent.ContentHeaders.Contains(x.Name));

headerParameters.ForEach(AddHeader);

void AddHeader(Parameter parameter) {
var parameterStringValue = parameter.Value!.ToString();

if (parameter.Encode) parameterStringValue = encode(parameterStringValue!);

message.Headers.Remove(parameter.Name!);
message.Headers.TryAddWithoutValidation(parameter.Name!, parameterStringValue);
}
Expand Down
2 changes: 1 addition & 1 deletion src/RestSharp/Request/RequestContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ void AddPostParameters() {
var formContent = new FormUrlEncodedContent(
_request.Parameters
.Where(x => x.Type == ParameterType.GetOrPost)
.Select(x => new KeyValuePair<string, string>(x.Name!, x.Value!.ToString()!))
.Select(x => new KeyValuePair<string, string>(x.Name!, x.Value!.ToString()!))!
);
Content = formContent;
}
Expand Down
41 changes: 14 additions & 27 deletions src/RestSharp/Request/RequestParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,49 +13,36 @@
// limitations under the License.
//

using RestSharp.Authenticators.OAuth.Extensions;

namespace RestSharp;

class RequestParameters {
static readonly ParameterType[] MultiParameterTypes = { ParameterType.QueryString, ParameterType.GetOrPost };

readonly List<Parameter> _requestParameters = new();

public IReadOnlyCollection<Parameter> Parameters => _requestParameters.AsReadOnly();
public ParametersCollection Parameters { get; } = new();

public RequestParameters AddRequestParameters(RestRequest request) {
_requestParameters.AddRange(request.Parameters);
public RequestParameters AddParameters(ParametersCollection parameters, bool allowSameName) {
Parameters.AddParameters(GetParameters(parameters, allowSameName));
return this;
}

// move RestClient.DefaultParameters into Request.Parameters
public RequestParameters AddDefaultParameters(RestClient client) {
foreach (var defaultParameter in client.DefaultParameters) {
var parameterExists =
_requestParameters.Any(
p =>
p.Name != null &&
p.Name.Equals(defaultParameter.Name, StringComparison.InvariantCultureIgnoreCase) &&
p.Type == defaultParameter.Type
);

if (client.Options.AllowMultipleDefaultParametersWithSameName) {
var isMultiParameter = MultiParameterTypes.Any(pt => pt == defaultParameter.Type);
IEnumerable<Parameter> GetParameters(ParametersCollection parametersCollection, bool allowSameName) {
foreach (var parameter in parametersCollection) {
var parameterExists = Parameters.Exists(parameter);

if (allowSameName) {
var isMultiParameter = MultiParameterTypes.Any(pt => pt == parameter.Type);
parameterExists = !isMultiParameter && parameterExists;
}

if (!parameterExists) _requestParameters.Add(defaultParameter);
if (!parameterExists) yield return parameter;
}

return this;
}

// Add Accept header based on registered deserializers if none has been set by the caller.
public RequestParameters AddAcceptHeader(RestClient client) {
if (_requestParameters.All(p => !p.Name!.EqualsIgnoreCase(KnownHeaders.Accept))) {
var accepts = string.Join(", ", client.AcceptedContentTypes);
_requestParameters.Add(new Parameter(KnownHeaders.Accept, accepts, ParameterType.HttpHeader));
public RequestParameters AddAcceptHeader(string[] acceptedContentTypes) {
if (Parameters.TryFind(KnownHeaders.Accept) == null) {
var accepts = string.Join(", ", acceptedContentTypes);
Parameters.AddParameter(new Parameter(KnownHeaders.Accept, accepts, ParameterType.HttpHeader));
}

return this;
Expand Down
Loading