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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using Elasticsearch.Net.ConnectionPool;
using Elasticsearch.Net.Serialization;
using Elasticsearch.Net.Connection.Security;

namespace Elasticsearch.Net.Connection
{
Expand Down Expand Up @@ -123,6 +124,9 @@ public class ConnectionConfiguration<T> : IConnectionConfigurationValues, IHideO

IElasticsearchSerializer IConnectionConfigurationValues.Serializer { get; set; }

private BasicAuthorizationCredentials _basicAuthCredentials;
BasicAuthorizationCredentials IConnectionConfigurationValues.BasicAuthorizationCredentials { get { return _basicAuthCredentials; } }

public ConnectionConfiguration(IConnectionPool connectionPool)
{
this._timeout = 60*1000;
Expand Down Expand Up @@ -328,6 +332,17 @@ public T SetConnectionStatusHandler(Action<IElasticsearchResponse> handler)
return (T)this;
}

/// <summary>
/// Basic access authorization credentials to specify with all requests.
/// </summary>
public T SetBasicAuthorization(string userName, string password)
{
if (this._basicAuthCredentials == null)
this._basicAuthCredentials = new BasicAuthorizationCredentials();
this._basicAuthCredentials.UserName = userName;
this._basicAuthCredentials.Password = password;
return (T)this;
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Specialized;
using Elasticsearch.Net.ConnectionPool;
using Elasticsearch.Net.Serialization;
using Elasticsearch.Net.Connection.Security;

namespace Elasticsearch.Net.Connection
{
Expand Down Expand Up @@ -65,5 +66,10 @@ public interface IConnectionConfigurationValues
///
/// </summary>
IElasticsearchSerializer Serializer { get; set; }

/// <summary>
/// Basic access authorization credentials to specify with all requests.
/// </summary>
BasicAuthorizationCredentials BasicAuthorizationCredentials { get; }
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Elasticsearch.Net.Connection.Security;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -48,6 +49,10 @@ public interface IRequestConfiguration
/// </summary>
IEnumerable<int> AllowedStatusCodes { get; set; }


/// <summary>
/// Basic access authorization credentials to specify with this request.
/// Overrides any credentials that are set at the global IConnectionSettings level.
/// </summary>
BasicAuthorizationCredentials BasicAuthorizationCredentials { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Elasticsearch.Net.Connection.Security;
using System;
using System.Collections.Generic;

Expand All @@ -13,5 +14,6 @@ public class RequestConfiguration : IRequestConfiguration
public bool? DisableSniff { get; set; }
public bool? DisablePing { get; set; }
public IEnumerable<int> AllowedStatusCodes { get; set; }
public BasicAuthorizationCredentials BasicAuthorizationCredentials { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Elasticsearch.Net.Connection.Security;
using System;
using System.Collections.Generic;

Expand All @@ -23,6 +24,8 @@ public class RequestConfigurationDescriptor : IRequestConfiguration

IEnumerable<int> IRequestConfiguration.AllowedStatusCodes { get; set; }

BasicAuthorizationCredentials IRequestConfiguration.BasicAuthorizationCredentials { get; set; }

public RequestConfigurationDescriptor RequestTimeout(int requestTimeoutInMilliseconds)
{
Self.RequestTimeout = requestTimeoutInMilliseconds;
Expand Down Expand Up @@ -75,5 +78,14 @@ public RequestConfigurationDescriptor MaxRetries(int retry)
Self.MaxRetries = retry;
return this;
}

public RequestConfigurationDescriptor BasicAuthorization(string userName, string password)
{
if (Self.BasicAuthorizationCredentials == null)
Self.BasicAuthorizationCredentials = new BasicAuthorizationCredentials();
Self.BasicAuthorizationCredentials.UserName = userName;
Self.BasicAuthorizationCredentials.Password = password;
return this;
}
}
}
23 changes: 17 additions & 6 deletions src/Elasticsearch.Net/Connection/HttpConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ private static void ThreadTimeoutCallback(object state, bool timedOut)
protected virtual HttpWebRequest CreateHttpWebRequest(Uri uri, string method, byte[] data, IRequestConfiguration requestSpecificConfig)
{
var myReq = this.CreateWebRequest(uri, method, data, requestSpecificConfig);
this.SetBasicAuthorizationIfNeeded(uri, myReq);
this.SetBasicAuthorizationIfNeeded(uri, myReq, requestSpecificConfig);
this.SetProxyIfNeeded(myReq);
return myReq;
}
Expand All @@ -164,12 +164,23 @@ private void SetProxyIfNeeded(HttpWebRequest myReq)
}
}

private void SetBasicAuthorizationIfNeeded(Uri uri, HttpWebRequest myReq)
private void SetBasicAuthorizationIfNeeded(Uri uri, HttpWebRequest request, IRequestConfiguration requestSpecificConfig)
{
if (!uri.UserInfo.IsNullOrEmpty())
{
myReq.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(myReq.RequestUri.UserInfo));
}
// Basic auth credentials take the following precedence (highest -> lowest):
// 1 - Specified on the request (highest precedence)
// 2 - Specified at the global IConnectionSettings level
// 3 - Specified with the URI (lowest precedence)

var userInfo = Uri.UnescapeDataString(uri.UserInfo);

if (this.ConnectionSettings.BasicAuthorizationCredentials != null)
userInfo = this.ConnectionSettings.BasicAuthorizationCredentials.ToString();

if (requestSpecificConfig != null && requestSpecificConfig.BasicAuthorizationCredentials != null)
userInfo = requestSpecificConfig.BasicAuthorizationCredentials.ToString();

if (!userInfo.IsNullOrEmpty())
request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(userInfo));
}

protected virtual HttpWebRequest CreateWebRequest(Uri uri, string method, byte[] data, IRequestConfiguration requestSpecificConfig)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Elasticsearch.Net.Connection.Security
{
public class BasicAuthorizationCredentials
{
public string UserName { get; set; }
public string Password { get; set; }

public override string ToString()
{
return this.UserName + ":" + this.Password;
}
}
}
1 change: 1 addition & 0 deletions src/Elasticsearch.Net/Elasticsearch.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
<Compile Include="Connection\RequestState\ITransportRequestState.cs" />
<Compile Include="Connection\RequestState\NoopRequestTimings.cs" />
<Compile Include="Connection\RequestState\RequestTimings.cs" />
<Compile Include="Connection\Security\BasicAuthorizationCredentials.cs" />
<Compile Include="Domain\RequestParameters\BaseRequestParameters.cs" />
<Compile Include="Domain\Response\CallMetrics.cs" />
<Compile Include="Domain\Response\IElasticsearchResponse.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@

using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using Nest;

// TODO: Need to figure out a better way to incorporate these tests into the normal test suite workflow.

// Purposely outside of the Nest namespace in order to bypass test setup.
namespace Tests.Security.BasicAuthTests
{
[TestFixture]
// Ignore these tests by default and run manually (for now) by commenting out the [Ignore] attribute.
// A considerable amount of setup is required to run them, which will also cause the rest of the test
// suite to fail.
[Ignore]
public class BasicAuthorizationTests
{
[Test]
public void No_Credentials_Result_In_401()
{
var settings = new ConnectionSettings(new Uri("http://localhost:9200"));
var client = new ElasticClient(settings);
var response = client.RootNodeInfo();
response.IsValid.Should().BeFalse();
response.ConnectionStatus.HttpStatusCode.Should().Be(401);
}

[Test]
public void Invalid_Credentials_Result_In_401()
{
var settings = new ConnectionSettings(new Uri("http://localhost:9200"))
.SetBasicAuthorization("nestuser", "incorrectpassword");
var client = new ElasticClient(settings);
var response = client.RootNodeInfo();
response.IsValid.Should().BeFalse();
response.ConnectionStatus.HttpStatusCode.Should().Be(401);
}

[Test]
public void Valid_Credentials_Result_In_200()
{
var settings = new ConnectionSettings(new Uri("http://localhost:9200"))
.SetBasicAuthorization("nestuser", "elastic");
var client = new ElasticClient(settings);
var response = client.RootNodeInfo();
response.IsValid.Should().BeTrue();
}

[Test]
public void Credentials_On_URI_Result_In_200()
{
var settings = new ConnectionSettings(new Uri("http://nestuser:elastic@localhost:9200"));
var client = new ElasticClient(settings);
var response = client.RootNodeInfo();
response.IsValid.Should().BeTrue();
}

[Test]
public void Escaped_Credentials_On_URI_Result_In_200()
{
var settings = new ConnectionSettings(new Uri("http://gmarz:p%40ssword@localhost:9200"));
var client = new ElasticClient(settings);
var response = client.RootNodeInfo();
response.IsValid.Should().BeTrue();
}

[Test]
public void ConnectionSettings_Overrides_URI()
{
var settings = new ConnectionSettings(new Uri("http://invalid:user@localhost:9200"))
.SetBasicAuthorization("nestuser", "elastic");
var client = new ElasticClient(settings);
var response = client.RootNodeInfo();
response.IsValid.Should().BeTrue();
}

[Test]
public void RequestConfiguration_Overrides_ConnectionSettings()
{
var settings = new ConnectionSettings(new Uri("http://localhost:9200"))
.SetBasicAuthorization("invalid", "user");
var client = new ElasticClient(settings);
var response = client.RootNodeInfo(c => c
.RequestConfiguration(rc => rc
.BasicAuthorization("nestuser", "elastic")
)
);
response.IsValid.Should().BeTrue();
}
}
}
52 changes: 26 additions & 26 deletions src/Tests/Nest.Tests.Integration/IntegrationSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,41 @@
using Nest.Tests.MockData.Domain;
using NUnit.Framework;

[SetUpFixture]
public class SetupAndTeardownForIntegrationTests
namespace Nest.Tests.Integration
{
[SetUp]
public void Setup()
[SetUpFixture]
public class SetupAndTeardownForIntegrationTests
{
var client = new ElasticClient(
//ElasticsearchConfiguration.Settings(hostOverride: new Uri("http://localhost:9200"))
ElasticsearchConfiguration.Settings()
);

try
[SetUp]
public void Setup()
{
IntegrationSetup.CreateTestIndex(client, ElasticsearchConfiguration.DefaultIndex);
IntegrationSetup.CreateTestIndex(client, ElasticsearchConfiguration.DefaultIndex + "_clone");
var client = new ElasticClient(
//ElasticsearchConfiguration.Settings(hostOverride: new Uri("http://localhost:9200"))
ElasticsearchConfiguration.Settings()
);

try
{
IntegrationSetup.CreateTestIndex(client, ElasticsearchConfiguration.DefaultIndex);
IntegrationSetup.CreateTestIndex(client, ElasticsearchConfiguration.DefaultIndex + "_clone");

IntegrationSetup.IndexDemoData(client);
}
catch (Exception)
{

throw;
}

IntegrationSetup.IndexDemoData(client);
}
catch (Exception)
[TearDown]
public void TearDown()
{

throw;
var client = ElasticsearchConfiguration.Client.Value;
client.DeleteIndex(di => di.Indices(ElasticsearchConfiguration.DefaultIndex, ElasticsearchConfiguration.DefaultIndex + "*"));
}

}
[TearDown]
public void TearDown()
{
var client = ElasticsearchConfiguration.Client.Value;
client.DeleteIndex(di => di.Indices(ElasticsearchConfiguration.DefaultIndex, ElasticsearchConfiguration.DefaultIndex + "*"));
}
}

namespace Nest.Tests.Integration
{
public static class IntegrationSetup
{
public static void IndexDemoData(IElasticClient client, string index = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
<Compile Include="Cluster\StatsTest.cs" />
<Compile Include="Connection\Failover\SniffTests.cs" />
<Compile Include="Connection\HttpClient\HttpClientTests.cs" />
<Compile Include="Connection\Security\BasicAuthorizationTests.cs" />
<Compile Include="Connection\Thrift\ThiftBugReportTests.cs" />
<Compile Include="Core\Analyze\AnalyzeTests.cs" />
<Compile Include="Core\Bulk\BulkTests.cs" />
Expand Down