Skip to content

Commit 28cfb31

Browse files
authored
Merge pull request #1 from elastic/fix/main/simplify-authentication
2 parents 3c65776 + 24eb2ee commit 28cfb31

14 files changed

+205
-265
lines changed

nuget.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<packageSources>
4+
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
5+
</packageSources>
6+
</configuration>

src/Elastic.Transport/Components/Connection/HttpConnection.cs

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -286,53 +286,31 @@ protected virtual void SetAuthenticationIfNeeded(HttpRequestMessage requestMessa
286286
return;
287287
}
288288

289-
// Api Key authentication takes precedence
290-
var apiKeySet = SetApiKeyAuthenticationIfNeeded(requestMessage, requestData);
291-
292-
if (!apiKeySet)
293-
SetBasicAuthenticationIfNeeded(requestMessage, requestData);
289+
SetConfiguredAuthenticationHeaderIfNeeded(requestMessage, requestData);
294290
}
295291

296-
private static bool SetApiKeyAuthenticationIfNeeded(HttpRequestMessage requestMessage, RequestData requestData)
297-
{
298-
// ApiKey auth credentials take the following precedence (highest -> lowest):
299-
// 1 - Specified on the request (highest precedence)
300-
// 2 - Specified at the global IConnectionSettings level
301-
302-
303-
string apiKey = null;
304-
if (requestData.ApiKeyAuthenticationCredentials != null)
305-
apiKey = requestData.ApiKeyAuthenticationCredentials.Base64EncodedApiKey.CreateString();
306-
307-
if (string.IsNullOrWhiteSpace(apiKey))
308-
return false;
309-
310-
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("ApiKey", apiKey);
311-
return true;
312-
313-
}
314-
315-
private static void SetBasicAuthenticationIfNeeded(HttpRequestMessage requestMessage, RequestData requestData)
292+
private static void SetConfiguredAuthenticationHeaderIfNeeded(HttpRequestMessage requestMessage, RequestData requestData)
316293
{
317294
// Basic auth credentials take the following precedence (highest -> lowest):
318-
// 1 - Specified on the request (highest precedence)
319-
// 2 - Specified at the global IConnectionSettings level
320-
// 3 - Specified with the URI (lowest precedence)
295+
// 1 - Specified with the URI (highest precedence)
296+
// 2 - Specified on the request
297+
// 3 - Specified at the global IConnectionSettings level (lowest precedence)
321298

322-
string userInfo = null;
299+
string value = null;
300+
string key = null;
323301
if (!requestData.Uri.UserInfo.IsNullOrEmpty())
324-
userInfo = Uri.UnescapeDataString(requestData.Uri.UserInfo);
325-
else if (requestData.BasicAuthorizationCredentials != null)
326302
{
327-
userInfo =
328-
$"{requestData.BasicAuthorizationCredentials.Username}:{requestData.BasicAuthorizationCredentials.Password.CreateString()}";
303+
value = BasicAuthentication.GetBase64String(Uri.UnescapeDataString(requestData.Uri.UserInfo));
304+
key = BasicAuthentication.Base64Header;
329305
}
330-
331-
if (!userInfo.IsNullOrEmpty())
306+
else if (requestData.AuthenticationHeader != null && requestData.AuthenticationHeader.TryGetHeader(out var v))
332307
{
333-
var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(userInfo!));
334-
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic", credentials);
308+
value = v;
309+
key = requestData.AuthenticationHeader.Header;
335310
}
311+
312+
if (value.IsNullOrEmpty()) return;
313+
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(key, value);
336314
}
337315

338316
private static HttpRequestMessage CreateRequestMessage(RequestData requestData)

src/Elastic.Transport/Components/Connection/HttpWebRequestConnection.cs

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -311,11 +311,14 @@ protected virtual void SetProxyIfNeeded(HttpWebRequest request, RequestData requ
311311
/// <summary> Hook for subclasses to set authentication on <paramref name="request"/></summary>
312312
protected virtual void SetAuthenticationIfNeeded(RequestData requestData, HttpWebRequest request)
313313
{
314-
// Api Key authentication takes precedence
315-
var apiKeySet = SetApiKeyAuthenticationIfNeeded(request, requestData);
316-
317-
if (!apiKeySet)
318-
SetBasicAuthenticationIfNeeded(request, requestData);
314+
//If user manually specifies an Authorization Header give it preference
315+
if (requestData.Headers.HasKeys() && requestData.Headers.AllKeys.Contains("Authorization"))
316+
{
317+
var header = requestData.Headers["Authorization"];
318+
request.Headers["Authorization"] = header;
319+
return;
320+
}
321+
SetBasicAuthenticationIfNeeded(request, requestData);
319322
}
320323

321324
private static void SetBasicAuthenticationIfNeeded(HttpWebRequest request, RequestData requestData)
@@ -325,37 +328,28 @@ private static void SetBasicAuthenticationIfNeeded(HttpWebRequest request, Reque
325328
// 2 - Specified at the global IConnectionSettings level
326329
// 3 - Specified with the URI (lowest precedence)
327330

328-
string userInfo = null;
329-
if (!string.IsNullOrEmpty(requestData.Uri.UserInfo))
330-
userInfo = Uri.UnescapeDataString(requestData.Uri.UserInfo);
331-
else if (requestData.BasicAuthorizationCredentials != null)
332-
{
333-
userInfo =
334-
$"{requestData.BasicAuthorizationCredentials.Username}:{requestData.BasicAuthorizationCredentials.Password.CreateString()}";
335-
}
336-
337-
if (string.IsNullOrWhiteSpace(userInfo))
338-
return;
339-
340-
request.Headers["Authorization"] = $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes(userInfo))}";
341-
}
342331

343-
private static bool SetApiKeyAuthenticationIfNeeded(HttpWebRequest request, RequestData requestData)
344-
{
345-
// ApiKey auth credentials take the following precedence (highest -> lowest):
346-
// 1 - Specified on the request (highest precedence)
347-
// 2 - Specified at the global IConnectionSettings level
348-
349-
string apiKey = null;
350-
if (requestData.ApiKeyAuthenticationCredentials != null)
351-
apiKey = requestData.ApiKeyAuthenticationCredentials.Base64EncodedApiKey.CreateString();
332+
// Basic auth credentials take the following precedence (highest -> lowest):
333+
// 1 - Specified with the URI (highest precedence)
334+
// 2 - Specified on the request
335+
// 3 - Specified at the global IConnectionSettings level (lowest precedence)
352336

353-
if (string.IsNullOrWhiteSpace(apiKey))
354-
return false;
337+
string value = null;
338+
string key = null;
339+
if (!requestData.Uri.UserInfo.IsNullOrEmpty())
340+
{
341+
value = BasicAuthentication.GetBase64String(Uri.UnescapeDataString(requestData.Uri.UserInfo));
342+
key = BasicAuthentication.Base64Header;
343+
}
344+
else if (requestData.AuthenticationHeader != null && requestData.AuthenticationHeader.TryGetHeader(out var v))
345+
{
346+
value = v;
347+
key = requestData.AuthenticationHeader.Header;
348+
}
355349

356-
request.Headers["Authorization"] = $"ApiKey {apiKey}";
357-
return true;
350+
if (value.IsNullOrEmpty()) return;
358351

352+
request.Headers["Authorization"] = $"{key} {value}";
359353
}
360354

361355
/// <summary>

src/Elastic.Transport/Components/ConnectionPool/CloudConnectionPool.cs

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -37,32 +37,8 @@ public class CloudConnectionPool : SingleNodeConnectionPool
3737
/// </param>
3838
/// <param name="credentials"></param>
3939
/// <param name="dateTimeProvider">Optionally inject an instance of <see cref="IDateTimeProvider"/> used to set <see cref="IConnectionPool.LastUpdate"/></param>
40-
public CloudConnectionPool(string cloudId, BasicAuthenticationCredentials credentials, IDateTimeProvider dateTimeProvider = null) : this(ParseCloudId(cloudId), dateTimeProvider) =>
41-
BasicCredentials = credentials;
42-
43-
/// <summary>
44-
/// An <see cref="IConnectionPool"/> implementation that can be seeded with a cloud id
45-
/// and will signal the right defaults for the client to use for Elastic Cloud to <see cref="ITransportConfigurationValues"/>.
46-
///
47-
/// <para>Read more about Elastic Cloud Id here</para>
48-
/// <para>https://www.elastic.co/guide/en/cloud/current/ec-cloud-id.html</para>
49-
/// </summary>
50-
/// <param name="cloudId">
51-
/// The Cloud Id, this is available on your cluster's dashboard and is a string in the form of <code>cluster_name:base_64_encoded_string</code>
52-
/// <para>Base64 encoded string contains the following tokens in order separated by $:</para>
53-
/// <para>* Host Name (mandatory)</para>
54-
/// <para>* Elasticsearch UUID (mandatory)</para>
55-
/// <para>* Kibana UUID</para>
56-
/// <para>* APM UUID</para>
57-
/// <para></para>
58-
/// <para> We then use these tokens to create the URI to your Elastic Cloud cluster!</para>
59-
/// <para></para>
60-
/// <para> Read more here: https://www.elastic.co/guide/en/cloud/current/ec-cloud-id.html</para>
61-
/// </param>
62-
/// <param name="credentials"></param>
63-
/// <param name="dateTimeProvider">Optionally inject an instance of <see cref="IDateTimeProvider"/> used to set <see cref="IConnectionPool.LastUpdate"/></param>
64-
public CloudConnectionPool(string cloudId, ApiKeyAuthenticationCredentials credentials, IDateTimeProvider dateTimeProvider = null) : this(ParseCloudId(cloudId), dateTimeProvider) =>
65-
ApiKeyCredentials = credentials;
40+
public CloudConnectionPool(string cloudId, IAuthenticationHeader credentials, IDateTimeProvider dateTimeProvider = null) : this(ParseCloudId(cloudId), dateTimeProvider) =>
41+
AuthenticationHeader = credentials;
6642

6743
private CloudConnectionPool(ParsedCloudId parsedCloudId, IDateTimeProvider dateTimeProvider = null) : base(parsedCloudId.Uri, dateTimeProvider) =>
6844
ClusterName = parsedCloudId.Name;
@@ -71,11 +47,8 @@ private CloudConnectionPool(ParsedCloudId parsedCloudId, IDateTimeProvider dateT
7147
// ReSharper disable once UnusedAutoPropertyAccessor.Local
7248
private string ClusterName { get; }
7349

74-
/// <summary> Read-only access to the basic authentication credentials that were passed in </summary>
75-
public BasicAuthenticationCredentials BasicCredentials { get; }
76-
77-
/// <summary> Read-only access to the api key authentication credentials that were passed in </summary>
78-
public ApiKeyAuthenticationCredentials ApiKeyCredentials { get; }
50+
/// <inheritdoc cref="IAuthenticationHeader"/>
51+
public IAuthenticationHeader AuthenticationHeader { get; }
7952

8053
private readonly struct ParsedCloudId
8154
{
@@ -121,10 +94,6 @@ private static ParsedCloudId ParseCloudId(string cloudId)
12194
}
12295

12396
/// <summary> Allows subclasses to hook into the parents dispose </summary>
124-
protected override void DisposeManagedResources()
125-
{
126-
ApiKeyCredentials?.Dispose();
127-
BasicCredentials?.Dispose();
128-
}
97+
protected override void DisposeManagedResources() => AuthenticationHeader?.Dispose();
12998
}
13099
}

src/Elastic.Transport/Components/Pipeline/RequestData.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ IMemoryStreamFactory memoryStreamFactory
9494
ProxyUsername = global.ProxyUsername;
9595
ProxyPassword = global.ProxyPassword;
9696
DisableAutomaticProxyDetection = global.DisableAutomaticProxyDetection;
97-
BasicAuthorizationCredentials = local?.BasicAuthenticationCredentials ?? global.BasicAuthenticationCredentials;
98-
ApiKeyAuthenticationCredentials = local?.ApiKeyAuthenticationCredentials ?? global.ApiKeyAuthenticationCredentials;
97+
AuthenticationHeader = local?.AuthenticationHeader ?? global.AuthenticationHeader;
9998
AllowedStatusCodes = local?.AllowedStatusCodes ?? EmptyReadOnly<int>.Collection;
10099
ClientCertificates = local?.ClientCertificates ?? global.ClientCertificates;
101100
UserAgent = global.UserAgent;
@@ -109,9 +108,7 @@ IMemoryStreamFactory memoryStreamFactory
109108
public string Accept { get; }
110109
public IReadOnlyCollection<int> AllowedStatusCodes { get; }
111110

112-
public ApiKeyAuthenticationCredentials ApiKeyAuthenticationCredentials { get; }
113-
114-
public BasicAuthenticationCredentials BasicAuthorizationCredentials { get; }
111+
public IAuthenticationHeader AuthenticationHeader { get; }
115112

116113
public X509CertificateCollection ClientCertificates { get; }
117114
public ITransportConfigurationValues ConnectionSettings { get; }

src/Elastic.Transport/Components/Pipeline/RequestPipeline.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ IRequestParameters requestParameters
6262
{
6363
PingTimeout = PingTimeout,
6464
RequestTimeout = PingTimeout,
65-
BasicAuthenticationCredentials = _settings.BasicAuthenticationCredentials,
66-
ApiKeyAuthenticationCredentials = _settings.ApiKeyAuthenticationCredentials,
65+
AuthenticationHeader = _settings.AuthenticationHeader,
6766
EnableHttpPipelining = RequestConfiguration?.EnableHttpPipelining ?? _settings.HttpPipeliningEnabled,
6867
ForceNode = RequestConfiguration?.ForceNode
6968
};

src/Elastic.Transport/Configuration/ITransportConfigurationValues.cs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,8 @@ namespace Elastic.Transport
1919
/// </summary>
2020
public interface ITransportConfigurationValues : IDisposable
2121
{
22-
/// <summary>
23-
/// Basic access authorization credentials to specify with all requests.
24-
/// </summary>
25-
/// <remarks>
26-
/// Cannot be used in conjuction with <see cref="ApiKeyAuthenticationCredentials"/>
27-
/// </remarks>
28-
BasicAuthenticationCredentials BasicAuthenticationCredentials { get; }
29-
30-
/// <summary>
31-
/// Api Key authorization credentials to specify with all requests.
32-
/// </summary>
33-
/// <remarks>
34-
/// Cannot be used in conjuction with <see cref="BasicAuthenticationCredentials"/>
35-
/// </remarks>
36-
ApiKeyAuthenticationCredentials ApiKeyAuthenticationCredentials { get; }
22+
/// <inheritdoc cref="IAuthenticationHeader"/>
23+
IAuthenticationHeader AuthenticationHeader { get; }
3724

3825
/// <summary> Provides a semaphoreslim to transport implementations that need to limit access to a resource</summary>
3926
SemaphoreSlim BootstrapLock { get; }

src/Elastic.Transport/Configuration/RequestConfiguration.cs

Lines changed: 8 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,9 @@ public interface IRequestConfiguration
2727
IReadOnlyCollection<int> AllowedStatusCodes { get; set; }
2828

2929
/// <summary>
30-
/// Basic access authorization credentials to specify with this request.
31-
/// Overrides any credentials that are set at the global IConnectionSettings level.
30+
/// Provide an authentication header override for this request
3231
/// </summary>
33-
/// <remarks>
34-
/// Cannot be used in conjunction with <see cref="ApiKeyAuthenticationCredentials"/>
35-
/// </remarks>
36-
BasicAuthenticationCredentials BasicAuthenticationCredentials { get; set; }
37-
38-
/// <summary>
39-
/// An API-key authorization credentials to specify with this request.
40-
/// Overrides any credentials that are set at the global IConnectionSettings level.
41-
/// </summary>
42-
/// <remarks>
43-
/// Cannot be used in conjunction with <see cref="BasicAuthenticationCredentials"/>
44-
/// </remarks>
45-
ApiKeyAuthenticationCredentials ApiKeyAuthenticationCredentials { get; set; }
32+
IAuthenticationHeader AuthenticationHeader { get; set; }
4633

4734
/// <summary>
4835
/// Use the following client certificates to authenticate this single request
@@ -140,9 +127,7 @@ public class RequestConfiguration : IRequestConfiguration
140127
/// <inheritdoc />
141128
public IReadOnlyCollection<int> AllowedStatusCodes { get; set; }
142129
/// <inheritdoc />
143-
public BasicAuthenticationCredentials BasicAuthenticationCredentials { get; set; }
144-
/// <inheritdoc />
145-
public ApiKeyAuthenticationCredentials ApiKeyAuthenticationCredentials { get; set; }
130+
public IAuthenticationHeader AuthenticationHeader { get; set; }
146131
/// <inheritdoc />
147132
public X509CertificateCollection ClientCertificates { get; set; }
148133
/// <inheritdoc />
@@ -195,8 +180,7 @@ public RequestConfigurationDescriptor(IRequestConfiguration config)
195180
Self.DisablePing = config?.DisablePing;
196181
Self.DisableDirectStreaming = config?.DisableDirectStreaming;
197182
Self.AllowedStatusCodes = config?.AllowedStatusCodes;
198-
Self.BasicAuthenticationCredentials = config?.BasicAuthenticationCredentials;
199-
Self.ApiKeyAuthenticationCredentials = config?.ApiKeyAuthenticationCredentials;
183+
Self.AuthenticationHeader = config?.AuthenticationHeader;
200184
Self.EnableHttpPipelining = config?.EnableHttpPipelining ?? true;
201185
Self.RunAs = config?.RunAs;
202186
Self.ClientCertificates = config?.ClientCertificates;
@@ -210,8 +194,7 @@ public RequestConfigurationDescriptor(IRequestConfiguration config)
210194

211195
string IRequestConfiguration.Accept { get; set; }
212196
IReadOnlyCollection<int> IRequestConfiguration.AllowedStatusCodes { get; set; }
213-
BasicAuthenticationCredentials IRequestConfiguration.BasicAuthenticationCredentials { get; set; }
214-
ApiKeyAuthenticationCredentials IRequestConfiguration.ApiKeyAuthenticationCredentials { get; set; }
197+
IAuthenticationHeader IRequestConfiguration.AuthenticationHeader { get; set; }
215198
X509CertificateCollection IRequestConfiguration.ClientCertificates { get; set; }
216199
string IRequestConfiguration.ContentType { get; set; }
217200
bool? IRequestConfiguration.DisableDirectStreaming { get; set; }
@@ -329,45 +312,10 @@ public RequestConfigurationDescriptor MaxRetries(int retry)
329312
return this;
330313
}
331314

332-
/// <inheritdoc cref="IRequestConfiguration.BasicAuthenticationCredentials"/>
333-
public RequestConfigurationDescriptor BasicAuthentication(string userName, string password)
334-
{
335-
Self.BasicAuthenticationCredentials = new BasicAuthenticationCredentials(userName, password);
336-
return this;
337-
}
338-
339-
/// <inheritdoc cref="IRequestConfiguration.BasicAuthenticationCredentials"/>
340-
public RequestConfigurationDescriptor BasicAuthentication(string userName, SecureString password)
341-
{
342-
Self.BasicAuthenticationCredentials = new BasicAuthenticationCredentials(userName, password);
343-
return this;
344-
}
345-
346-
/// <inheritdoc cref="IRequestConfiguration.ApiKeyAuthenticationCredentials"/>
347-
public RequestConfigurationDescriptor ApiKeyAuthentication(string id, string apiKey)
348-
{
349-
Self.ApiKeyAuthenticationCredentials = new ApiKeyAuthenticationCredentials(id, apiKey);
350-
return this;
351-
}
352-
353-
/// <inheritdoc cref="IRequestConfiguration.ApiKeyAuthenticationCredentials"/>
354-
public RequestConfigurationDescriptor ApiKeyAuthentication(string id, SecureString apiKey)
355-
{
356-
Self.ApiKeyAuthenticationCredentials = new ApiKeyAuthenticationCredentials(id, apiKey);
357-
return this;
358-
}
359-
360-
/// <inheritdoc cref="IRequestConfiguration.RunAs"/>
361-
public RequestConfigurationDescriptor ApiKeyAuthentication(string base64EncodedApiKey)
362-
{
363-
Self.ApiKeyAuthenticationCredentials = new ApiKeyAuthenticationCredentials(base64EncodedApiKey);
364-
return this;
365-
}
366-
367-
/// <inheritdoc cref="IRequestConfiguration.RunAs"/>
368-
public RequestConfigurationDescriptor ApiKeyAuthentication(SecureString base64EncodedApiKey)
315+
/// <inheritdoc cref="IAuthenticationHeader"/>
316+
public RequestConfigurationDescriptor Authentication(IAuthenticationHeader authentication)
369317
{
370-
Self.ApiKeyAuthenticationCredentials = new ApiKeyAuthenticationCredentials(base64EncodedApiKey);
318+
Self.AuthenticationHeader = authentication;
371319
return this;
372320
}
373321

0 commit comments

Comments
 (0)