diff --git a/.gitignore b/.gitignore index 986a32a..af8a7b8 100644 --- a/.gitignore +++ b/.gitignore @@ -195,5 +195,7 @@ FakesAssemblies/ # Visual Studio 6 workspace options file *.opt +*.lock.json + # VIM files .*.swp diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.Netcore.sln b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.Netcore.sln new file mode 100644 index 0000000..cc077f0 --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.Netcore.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Elasticsearch.Net.Aws", "Elasticsearch.Net.Aws\Elasticsearch.Net.Aws.xproj", "{EDC0CA5E-1970-4C97-936D-B9D3A1675F09}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Tests", "Tests\Tests.xproj", "{DE3D30F3-64CD-4145-A38D-6F24A2028BA5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EDC0CA5E-1970-4C97-936D-B9D3A1675F09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDC0CA5E-1970-4C97-936D-B9D3A1675F09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDC0CA5E-1970-4C97-936D-B9D3A1675F09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDC0CA5E-1970-4C97-936D-B9D3A1675F09}.Release|Any CPU.Build.0 = Release|Any CPU + {DE3D30F3-64CD-4145-A38D-6F24A2028BA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DE3D30F3-64CD-4145-A38D-6F24A2028BA5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DE3D30F3-64CD-4145-A38D-6F24A2028BA5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DE3D30F3-64CD-4145-A38D-6F24A2028BA5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/AwsHttpConnection-Netcore.cs b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/AwsHttpConnection-Netcore.cs new file mode 100644 index 0000000..200a044 --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/AwsHttpConnection-Netcore.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +namespace Elasticsearch.Net.Aws +{ + public class AwsHttpConnection : HttpConnection + { + readonly Credentials _credentials; + readonly string _region; + + public AwsHttpConnection(AwsSettings settings) + { + // todo - proper credential chain + _credentials = new Credentials + { + AccessKey = settings.AccessKey, + SecretKey = settings.SecretKey, + }; + _region = settings.Region; + } + + protected override HttpRequestMessage CreateHttpRequestMessage(RequestData requestData) + { + + var result = base.CreateHttpRequestMessage(requestData); + var signable = new SignableHttpRequestMessage(result, requestData); + SignV4Util.SignRequest(signable, _credentials, _region, "es"); + return result; + } + } +} diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/AwsHttpConnection.cs b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/AwsHttpConnection.cs index 43032a5..27aeda2 100644 --- a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/AwsHttpConnection.cs +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/AwsHttpConnection.cs @@ -1,4 +1,5 @@ -using System; +#if !DOTNETCORE +using System; using System.Configuration; using System.IO; using System.Net; @@ -14,8 +15,10 @@ private static string GetAccessKey(AwsSettings awsSettings) { var key = awsSettings.AccessKey; if (!string.IsNullOrWhiteSpace(key)) return key; +#if NET45 key = ConfigurationManager.AppSettings["AWSAccessKey"]; if (!string.IsNullOrWhiteSpace(key)) return key; +#endif return Environment.GetEnvironmentVariable("AWS_ACCESS_KEY_ID"); } @@ -87,7 +90,8 @@ protected override HttpWebRequest CreateHttpWebRequest(RequestData requestData) } } } - SignV4Util.SignRequest(request, data, _credentials, _region, "es"); + var signableRequest = new SignableHttpWebRequest(request, data); + SignV4Util.SignRequest(signableRequest, _credentials, _region, "es"); return request; } @@ -106,3 +110,4 @@ private void RefreshCredentials() } } } +#endif \ No newline at end of file diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.csproj b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.csproj index aca8b54..c5937ad 100644 --- a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.csproj +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.csproj @@ -56,10 +56,14 @@ + + + + diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.project.json b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.project.json new file mode 100644 index 0000000..16c3e4a --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.project.json @@ -0,0 +1,11 @@ +{ + "runtimes": { + "win": {} + }, + "frameworks": { + "net45": {} + }, + "dependencies": { + "Newtonsoft.Json": "9.0.1" + } +} \ No newline at end of file diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.xproj b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.xproj new file mode 100644 index 0000000..a2891bd --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws.xproj @@ -0,0 +1,19 @@ + + + + 14.0.25420 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + edc0ca5e-1970-4c97-936d-b9d3a1675f09 + Elasticsearch.Net.Aws + .\obj + .\bin\ + + + + 2.0 + + + \ No newline at end of file diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/HttpRequestExtensions.cs b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/HttpRequestExtensions.cs new file mode 100644 index 0000000..dec6c58 --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/HttpRequestExtensions.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Elasticsearch.Net.Aws +{ + internal static class HttpRequestExtensions + { + public static string GetHeaderValue(this IHttpRequest request, string name) + => string.Join(",", request.GetHeaderValues(name)); + } +} diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/IHttpRequest.cs b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/IHttpRequest.cs new file mode 100644 index 0000000..b72a86d --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/IHttpRequest.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Elasticsearch.Net.Aws +{ + internal interface IHttpRequest + { + Uri Uri { get; } + string Method { get; } + byte[] Body { get; } + IEnumerable GetHeaderKeys(); + IEnumerable GetHeaderValues(string name); + void SetHeader(string name, string value); + } +} diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/InstanceProfileService.cs b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/InstanceProfileService.cs index cc0abba..a487186 100644 --- a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/InstanceProfileService.cs +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/InstanceProfileService.cs @@ -2,7 +2,11 @@ using System.Collections.Generic; using System.IO; using System.Net; -using System.Web.Script.Serialization; +using Newtonsoft.Json; + +#if DOTNETCORE +using System.Net.Http; +#endif namespace Elasticsearch.Net.Aws { @@ -12,7 +16,6 @@ internal static class InstanceProfileService private const string Server = "http://169.254.169.254"; private const string RolesPath = "/latest/meta-data/iam/security-credentials/"; private const string SuccessCode = "Success"; - private static readonly JavaScriptSerializer CredentialSerializer = new JavaScriptSerializer(); private static InstanceProfileCredentials _cachedCredentials; private static readonly object CacheLock = new object(); @@ -28,7 +31,7 @@ internal static InstanceProfileCredentials GetCredentials() { var role = GetFirstRole(); var json = GetContents(new Uri(Server + RolesPath + role)); - var credentials = CredentialSerializer.Deserialize(json); + var credentials = JsonConvert.DeserializeObject(json); if (credentials.Code != SuccessCode) return null; @@ -84,16 +87,24 @@ private static string GetContents(Uri uri) { try { - var request = WebRequest.Create(uri) as HttpWebRequest; - using (var response = request.GetResponse() as HttpWebResponse) - using (var reader = new StreamReader(response.GetResponseStream())) +#if DOTNETCORE + using (var client = new HttpClient()) + using (var response = client.GetAsync(uri).Result) + { + return response.Content.ReadAsStringAsync().Result; + } +#else + using (var response = WebRequest.CreateHttp(uri).GetResponse()) + using (var body = response.GetResponseStream()) + using (var reader = new StreamReader(body)) { return reader.ReadToEnd(); } +#endif } - catch (WebException ex) + catch (Exception ex) { - throw new Exception("Unable to reach credentials server", ex); + throw new Exception("Unable to get instance profile credentials", ex); } } diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/SignV4Util.cs b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/SignV4Util.cs index 0204b5c..e947050 100644 --- a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/SignV4Util.cs +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/SignV4Util.cs @@ -6,7 +6,11 @@ using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; +#if DOTNETCORE +using Microsoft.AspNetCore.WebUtilities; +#else using System.Web; +#endif namespace Elasticsearch.Net.Aws { @@ -14,15 +18,15 @@ internal static class SignV4Util { static readonly char[] _datePartSplitChars = { 'T' }; - public static void SignRequest(HttpWebRequest request, byte[] body, Credentials credentials, string region, string service) + public static void SignRequest(IHttpRequest request, Credentials credentials, string region, string service) { var date = DateTime.UtcNow; var dateStamp = date.ToString("yyyyMMdd"); var amzDate = date.ToString("yyyyMMddTHHmmssZ"); - request.Headers["X-Amz-Date"] = amzDate; + request.SetHeader("X-Amz-Date", amzDate); var signingKey = GetSigningKey(credentials.SecretKey, dateStamp, region, service); - var stringToSign = GetStringToSign(request, body, region, service); + var stringToSign = GetStringToSign(request, region, service); Debug.Write("========== String to Sign ==========\r\n{0}\r\n========== String to Sign ==========\r\n", stringToSign); var signature = signingKey.GetHmacSha256Hash(stringToSign).ToLowercaseHex(); var auth = string.Format( @@ -32,9 +36,11 @@ public static void SignRequest(HttpWebRequest request, byte[] body, Credentials GetSignedHeaders(request), signature); - request.Headers[HttpRequestHeader.Authorization] = auth; - if (!String.IsNullOrWhiteSpace(credentials.Token)) - request.Headers["x-amz-security-token"] = credentials.Token; + request.SetHeader("Authorization", auth); + if (!string.IsNullOrWhiteSpace(credentials.Token)) + { + request.SetHeader("x-amz-security-token", credentials.Token); + } } public static byte[] GetSigningKey(string secretKey, string dateStamp, string region, string service) @@ -48,18 +54,17 @@ public static byte[] GetSigningKey(string secretKey, string dateStamp, string re private static byte[] GetHmacSha256Hash(this byte[] key, string data) { - using (var kha = KeyedHashAlgorithm.Create("HmacSHA256")) + using (var kha = new HMACSHA256(key)) { - kha.Key = key; return kha.ComputeHash(_encoding.GetBytes(data)); } } - public static string GetStringToSign(HttpWebRequest request, byte[] data, string region, string service) + public static string GetStringToSign(IHttpRequest request, string region, string service) { - var canonicalRequest = GetCanonicalRequest(request, data); + var canonicalRequest = GetCanonicalRequest(request); Debug.Write("========== Canonical Request ==========\r\n{0}\r\n========== Canonical Request ==========\r\n", canonicalRequest); - var awsDate = request.Headers["x-amz-date"]; + var awsDate = request.GetHeaderValue("x-amz-date"); Debug.Assert(Regex.IsMatch(awsDate, @"\d{8}T\d{6}Z")); var datePart = awsDate.Split(_datePartSplitChars, 2)[0]; return string.Join("\n", @@ -75,21 +80,21 @@ private static string GetCredentialScope(string date, string region, string serv return string.Format("{0}/{1}/{2}/aws4_request", date, region, service); } - public static string GetCanonicalRequest(HttpWebRequest request, byte[] data) + public static string GetCanonicalRequest(IHttpRequest request) { var canonicalHeaders = request.GetCanonicalHeaders(); var result = new StringBuilder(); result.Append(request.Method); result.Append('\n'); - result.Append(GetPath(request.RequestUri)); + result.Append(GetPath(request.Uri)); result.Append('\n'); - result.Append(request.RequestUri.GetCanonicalQueryString()); + result.Append(request.Uri.GetCanonicalQueryString()); result.Append('\n'); WriteCanonicalHeaders(canonicalHeaders, result); result.Append('\n'); WriteSignedHeaders(canonicalHeaders, result); result.Append('\n'); - WriteRequestPayloadHash(data, result); + WriteRequestPayloadHash(request.Body, result); return result.ToString(); } @@ -102,7 +107,7 @@ private static string GetPath(Uri uri) .Split('/') .Select(segment => { - string escaped = HttpUtility.UrlEncode(segment); + string escaped = WebUtility.UrlEncode(segment); escaped = escaped.Replace("*", "%2A"); return escaped; } @@ -110,18 +115,17 @@ private static string GetPath(Uri uri) return string.Join("/", segments); } - private static Dictionary GetCanonicalHeaders(this HttpWebRequest request) + private static Dictionary GetCanonicalHeaders(this IHttpRequest request) { - var q = from string key in request.Headers + var q = from string key in request.GetHeaderKeys() let headerName = key.ToLowerInvariant() let headerValues = string.Join(",", - request.Headers - .GetValues(key) ?? Enumerable.Empty() + request.GetHeaderValues(key) ?? Enumerable.Empty() .Select(v => v.Trimall()) ) select new { headerName, headerValues }; var result = q.ToDictionary(v => v.headerName, v => v.headerValues); - result["host"] = request.RequestUri.Host.ToLowerInvariant(); + result["host"] = request.Uri.Host.ToLowerInvariant(); return result; } @@ -129,14 +133,14 @@ private static void WriteCanonicalHeaders(Dictionary canonicalHe { var q = from pair in canonicalHeaders orderby pair.Key ascending - select string.Format("{0}:{1}\n", pair.Key, pair.Value); + select $"{pair.Key}:{pair.Value}\n"; foreach (var line in q) { output.Append(line); } } - private static string GetSignedHeaders(HttpWebRequest request) + private static string GetSignedHeaders(IHttpRequest request) { var canonicalHeaders = request.GetCanonicalHeaders(); var result = new StringBuilder(); @@ -158,11 +162,18 @@ private static void WriteSignedHeaders(Dictionary canonicalHeade public static string GetCanonicalQueryString(this Uri uri) { if (string.IsNullOrWhiteSpace(uri.Query)) return string.Empty; + +#if DOTNETCORE + var q = from kvp in QueryHelpers.ParseQuery(uri.Query) + from value in kvp.Value + select new { key = kvp.Key, value }; +#else var queryParams = HttpUtility.ParseQueryString(uri.Query); var q = from string key in queryParams orderby key from value in queryParams.GetValues(key) select new { key, value }; +#endif var output = new StringBuilder(); foreach (var param in q) @@ -181,7 +192,7 @@ private static void WriteEncoded(this StringBuilder output, string value) { if (value[i].RequiresEncoding()) { - output.Append(Uri.HexEscape(value[i])); + output.AppendHexEscaped(value[i]); } else { @@ -237,7 +248,7 @@ private static byte[] GetHash(string data) private static byte[] GetHash(this byte[] data) { - using (var algo = HashAlgorithm.Create("SHA256")) + using (var algo = SHA256.Create()) { return algo.ComputeHash(data); } diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/SignableHttpRequestMessage.cs b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/SignableHttpRequestMessage.cs new file mode 100644 index 0000000..a2f16ac --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/SignableHttpRequestMessage.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; + +namespace Elasticsearch.Net.Aws +{ + internal class SignableHttpRequestMessage : IHttpRequest + { + readonly HttpRequestMessage _request; + readonly RequestData _requestData; + + public SignableHttpRequestMessage(HttpRequestMessage request, RequestData requestData) + { + _request = request; + _requestData = requestData; + } + + public Uri Uri => _request.RequestUri; + public string Method => _request.Method.Method; + public byte[] Body + { + get + { + // note - this probably won't work if compression is enabled + if (_requestData?.PostData == null) return null; + if (_requestData.PostData.WrittenBytes != null) return _requestData.PostData.WrittenBytes; + using (var ms = new MemoryStream()) + { + _requestData.PostData.Write(ms, _requestData.ConnectionSettings); + return ms.ToArray(); + } + } + } + + public IEnumerable GetHeaderKeys() => _request.Headers.Select(h => h.Key); + + public IEnumerable GetHeaderValues(string name) => _request.Headers.GetValues(name); + + public void SetHeader(string name, string value) + { + _request.Headers.Remove(name); + _request.Headers.Add(name, value); + } + } +} diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/SignableHttpWebRequest.cs b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/SignableHttpWebRequest.cs new file mode 100644 index 0000000..8fa1ede --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/SignableHttpWebRequest.cs @@ -0,0 +1,43 @@ +#if !DOTNETCORE +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Elasticsearch.Net.Aws +{ + internal class SignableHttpWebRequest : IHttpRequest + { + public HttpWebRequest Request { get; } + + public SignableHttpWebRequest(HttpWebRequest request, byte[] body) + { + Request = request; + Body = body; + } + + public Uri Uri => Request.RequestUri; + + public string Method => Request.Method; + + public byte[] Body { get; } + + public IEnumerable GetHeaderKeys() + { + return Request.Headers.Cast(); + } + + public IEnumerable GetHeaderValues(string name) + { + return Request.Headers.GetValues(name); + } + + public void SetHeader(string name, string value) + { + Request.Headers[name] = value; + } + } +} +#endif diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/StringBuilderExtensions.cs b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/StringBuilderExtensions.cs new file mode 100644 index 0000000..0c01f0b --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/StringBuilderExtensions.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Elasticsearch.Net.Aws +{ + internal static class StringBuilderExtensions + { + private static readonly char[] _hexUpperChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + public static void AppendHexEscaped(this StringBuilder builder, char value) + { + builder.Append('%'); + builder.Append(_hexUpperChars[(value & 0xf0) >> 4]); + builder.Append(_hexUpperChars[value & 0xf]); + } + } +} diff --git a/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/project.json b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/project.json new file mode 100644 index 0000000..b40416d --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Elasticsearch.Net.Aws/project.json @@ -0,0 +1,17 @@ +{ + "version": "2.1.4.0", + "dependencies": { + "Elasticsearch.Net": "2.4.6", + "Microsoft.AspNetCore.WebUtilities": "1.0.0", + "NETStandard.Library": "1.6.0", + "Newtonsoft.Json": "9.0.1" + }, + "frameworks": { + "netstandard1.6": { + "imports": "dnxcore50" + } + }, + "buildOptions": { + "define": [ "DOTNETCORE" ] + } +} diff --git a/src/Elasticsearch.Net.Aws/IntegrationTests/IntegrationTests.csproj b/src/Elasticsearch.Net.Aws/IntegrationTests/IntegrationTests.csproj index b4d4758..084022d 100644 --- a/src/Elasticsearch.Net.Aws/IntegrationTests/IntegrationTests.csproj +++ b/src/Elasticsearch.Net.Aws/IntegrationTests/IntegrationTests.csproj @@ -38,15 +38,15 @@ - ..\packages\Elasticsearch.Net.2.0.2\lib\net45\Elasticsearch.Net.dll + ..\packages\Elasticsearch.Net.2.4.1\lib\net45\Elasticsearch.Net.dll True - ..\packages\NEST.2.0.2\lib\net45\Nest.dll + ..\packages\NEST.2.4.1\lib\net45\Nest.dll True - - ..\packages\Newtonsoft.Json.8.0.1\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll True diff --git a/src/Elasticsearch.Net.Aws/IntegrationTests/packages.config b/src/Elasticsearch.Net.Aws/IntegrationTests/packages.config index 498093a..597ab2f 100644 --- a/src/Elasticsearch.Net.Aws/IntegrationTests/packages.config +++ b/src/Elasticsearch.Net.Aws/IntegrationTests/packages.config @@ -1,7 +1,7 @@  - - - + + + \ No newline at end of file diff --git a/src/Elasticsearch.Net.Aws/Tests/InstanceProfileTests.cs b/src/Elasticsearch.Net.Aws/Tests/InstanceProfileTests.cs index b0b35fb..c080733 100644 --- a/src/Elasticsearch.Net.Aws/Tests/InstanceProfileTests.cs +++ b/src/Elasticsearch.Net.Aws/Tests/InstanceProfileTests.cs @@ -14,13 +14,16 @@ public void GetCredentials_should_return_valid_credentials() var credentials = InstanceProfileService.GetCredentials(); Trace.Write(String.Format("AccessKeyId: {0}", credentials.AccessKeyId)); - Assert.IsNotNullOrEmpty(credentials.AccessKeyId); + Assert.IsNotNull(credentials.AccessKeyId); + Assert.IsNotEmpty(credentials.AccessKeyId); Trace.Write(String.Format("SecretAccessKey: {0}", credentials.SecretAccessKey)); - Assert.IsNotNullOrEmpty(credentials.SecretAccessKey); + Assert.IsNotNull(credentials.SecretAccessKey); + Assert.IsNotEmpty(credentials.SecretAccessKey); Trace.Write(String.Format("Token: {0}", credentials.Token)); - Assert.IsNotNullOrEmpty(credentials.Token); + Assert.IsNotNull(credentials.Token); + Assert.IsNotEmpty(credentials.Token); } } } diff --git a/src/Elasticsearch.Net.Aws/Tests/MockHttpRequest.cs b/src/Elasticsearch.Net.Aws/Tests/MockHttpRequest.cs new file mode 100644 index 0000000..5b459a6 --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Tests/MockHttpRequest.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Threading.Tasks; +using Elasticsearch.Net.Aws; + +namespace Tests +{ + public class MockHttpRequest : IHttpRequest + { + public Uri Uri { get; set; } + public string Method { get; set; } + public byte[] Body { get; set; } + public NameValueCollection Headers { get; set; } = new NameValueCollection(); + public IEnumerable GetHeaderKeys() => Headers.Keys.Cast(); + + public IEnumerable GetHeaderValues(string name) + => Headers?.GetValues(name) ?? Enumerable.Empty(); + + public void SetHeader(string name, string value) + { + if (Headers == null) Headers = new NameValueCollection(); + Headers[name] = value; + } + } +} diff --git a/src/Elasticsearch.Net.Aws/Tests/SignUtilTests.cs b/src/Elasticsearch.Net.Aws/Tests/SignUtilTests.cs index 7f1c018..b6ad061 100644 --- a/src/Elasticsearch.Net.Aws/Tests/SignUtilTests.cs +++ b/src/Elasticsearch.Net.Aws/Tests/SignUtilTests.cs @@ -1,7 +1,6 @@ using System; -using System.Diagnostics; -using System.Linq; -using System.Net; +using System.Collections.Generic; +using System.Collections.Specialized; using System.Text; using Elasticsearch.Net.Aws; using NUnit.Framework; @@ -11,24 +10,29 @@ namespace Tests [TestFixture] public class SignUtilTests { - HttpWebRequest _sampleRequest; - byte[] _sampleBody; + MockHttpRequest _sampleRequest; [SetUp] public void SetUp() { - _sampleRequest = WebRequest.CreateHttp("https://iam.amazonaws.com/"); - _sampleRequest.Method = "POST"; - _sampleRequest.ContentType = "application/x-www-form-urlencoded; charset=utf-8"; - _sampleRequest.Headers["X-Amz-Date"] = "20110909T233600Z"; - var encoding = new UTF8Encoding(false); - _sampleBody = encoding.GetBytes("Action=ListUsers&Version=2010-05-08"); + _sampleRequest = new MockHttpRequest + { + Uri = new Uri("https://iam.amazonaws.com/"), + Method = "POST", + Headers = new NameValueCollection + { + ["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8", + ["X-Amz-Date"] = "20110909T233600Z", + + }, + Body = new UTF8Encoding(false).GetBytes("Action=ListUsers&Version=2010-05-08"), + }; } [Test] public void GetCanonicalRequest_should_match_sample() { - var canonicalRequest = SignV4Util.GetCanonicalRequest(_sampleRequest, _sampleBody); + var canonicalRequest = SignV4Util.GetCanonicalRequest(_sampleRequest); Trace.WriteLine("=== Actual ==="); Trace.Write(canonicalRequest); @@ -42,7 +46,7 @@ public void GetCanonicalRequest_should_match_sample() [Test] public void GetStringToSign_should_match_sample() { - var stringToSign = SignV4Util.GetStringToSign(_sampleRequest, _sampleBody, "us-east-1", "iam"); + var stringToSign = SignV4Util.GetStringToSign(_sampleRequest, "us-east-1", "iam"); Trace.WriteLine("=== Actual ==="); Trace.Write(stringToSign); @@ -78,18 +82,21 @@ public void SignRequest_should_apply_signature_to_request() SecretKey = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", Token = "token1", }; - SignV4Util.SignRequest(_sampleRequest, _sampleBody, creds, "us-east-1", "iam"); + SignV4Util.SignRequest(_sampleRequest, creds, "us-east-1", "iam"); var amzDate = _sampleRequest.Headers["X-Amz-Date"]; - Assert.IsNotNullOrEmpty(amzDate); + Assert.IsNotNull(amzDate); + Assert.IsNotEmpty(amzDate); Trace.WriteLine("X-Amz-Date: " + amzDate); - var auth = _sampleRequest.Headers[HttpRequestHeader.Authorization]; - Assert.IsNotNullOrEmpty(auth); + var auth = _sampleRequest.Headers["Authorization"]; + Assert.IsNotNull(auth); + Assert.IsNotEmpty(auth); Trace.WriteLine("Authorize: " + auth); var token = _sampleRequest.Headers["x-amz-security-token"]; - Assert.IsNotNullOrEmpty(token); + Assert.IsNotNull(token); + Assert.IsNotEmpty(token); Trace.WriteLine("Token: " + token); } diff --git a/src/Elasticsearch.Net.Aws/Tests/Tests.csproj b/src/Elasticsearch.Net.Aws/Tests/Tests.csproj index a82ca7e..b28db2b 100644 --- a/src/Elasticsearch.Net.Aws/Tests/Tests.csproj +++ b/src/Elasticsearch.Net.Aws/Tests/Tests.csproj @@ -38,15 +38,15 @@ - ..\packages\Elasticsearch.Net.2.0.2\lib\net45\Elasticsearch.Net.dll + ..\packages\Elasticsearch.Net.2.4.1\lib\net45\Elasticsearch.Net.dll True - ..\packages\NEST.2.0.2\lib\net45\Nest.dll + ..\packages\NEST.2.4.1\lib\net45\Nest.dll True - - ..\packages\Newtonsoft.Json.8.0.1\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll True @@ -63,9 +63,11 @@ + + diff --git a/src/Elasticsearch.Net.Aws/Tests/Tests.project.json b/src/Elasticsearch.Net.Aws/Tests/Tests.project.json new file mode 100644 index 0000000..16c3e4a --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Tests/Tests.project.json @@ -0,0 +1,11 @@ +{ + "runtimes": { + "win": {} + }, + "frameworks": { + "net45": {} + }, + "dependencies": { + "Newtonsoft.Json": "9.0.1" + } +} \ No newline at end of file diff --git a/src/Elasticsearch.Net.Aws/Tests/Tests.xproj b/src/Elasticsearch.Net.Aws/Tests/Tests.xproj new file mode 100644 index 0000000..488ab32 --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Tests/Tests.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + de3d30f3-64cd-4145-a38d-6f24a2028ba5 + Tests + .\obj + .\bin\ + v4.5 + + + 2.0 + + + \ No newline at end of file diff --git a/src/Elasticsearch.Net.Aws/Tests/Trace.cs b/src/Elasticsearch.Net.Aws/Tests/Trace.cs new file mode 100644 index 0000000..8891a78 --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Tests/Trace.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Tests +{ + public static class Trace + { +#if DOTNETCORE + public static void WriteLine(string line) => Console.WriteLine(line); + public static void Write(string line) => Console.Write(line); +#else + public static void WriteLine(string line) => System.Diagnostics.Trace.WriteLine(line); + public static void Write(string line) => System.Diagnostics.Trace.Write(line); +#endif + } +} diff --git a/src/Elasticsearch.Net.Aws/Tests/packages.config b/src/Elasticsearch.Net.Aws/Tests/packages.config index 498093a..597ab2f 100644 --- a/src/Elasticsearch.Net.Aws/Tests/packages.config +++ b/src/Elasticsearch.Net.Aws/Tests/packages.config @@ -1,7 +1,7 @@  - - - + + + \ No newline at end of file diff --git a/src/Elasticsearch.Net.Aws/Tests/project.json b/src/Elasticsearch.Net.Aws/Tests/project.json new file mode 100644 index 0000000..7b0a1e3 --- /dev/null +++ b/src/Elasticsearch.Net.Aws/Tests/project.json @@ -0,0 +1,17 @@ +{ + "version": "1.0.0-*", + "dependencies": { + "Elasticsearch.Net": "2.4.6", + "Elasticsearch.Net.Aws": "2.1.4.0", + "NETStandard.Library": "1.6.0", + "NUnit": "3.5.0" + }, + "frameworks": { + "netstandard1.6": { + "imports": "dnxcore50" + } + }, + "buildOptions": { + "define": [ "DOTNETCORE" ] + } +}