diff --git a/OpenSearch.sln b/OpenSearch.sln index d2c0f49b5a..42571182e0 100644 --- a/OpenSearch.sln +++ b/OpenSearch.sln @@ -73,6 +73,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{29E53C13 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSearch.Client.JsonNetSerializer", "src\OpenSearch.Client.JsonNetSerializer\OpenSearch.Client.JsonNetSerializer.csproj", "{B16AAB37-9FF4-4940-AC7D-437DFD18A6F6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSearch.Net.Auth.AwsSigV4", "src\OpenSearch.Net.Auth.AwsSigV4\OpenSearch.Net.Auth.AwsSigV4.csproj", "{2BDA50C8-767A-4560-9547-15AFC972A6E3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.Auth.AwsSigV4", "tests\Tests.Auth.AwsSigV4\Tests.Auth.AwsSigV4.csproj", "{2BCE8150-C16C-4226-B216-C7A0463ADC56}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSearch.Stack.ArtifactsApiTests", "abstractions\src\OpenSearch.Stack.ArtifactsApiTests\OpenSearch.Stack.ArtifactsApiTests.csproj", "{1F5A7B1A-2566-481F-91B5-A63D7F939973}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "abstractions", "abstractions", "{87ABA679-F3F4-48CE-82B3-1AAE5D0A5935}" @@ -121,6 +124,8 @@ Global {D6997ADC-E933-418E-831C-DE1A78897493} = {29E53C13-34F7-4F0D-8D28-41EF768793E7} {432D5575-2347-4D3C-BF8C-3E38410C46CA} = {29E53C13-34F7-4F0D-8D28-41EF768793E7} {B16AAB37-9FF4-4940-AC7D-437DFD18A6F6} = {3EA11364-0513-44B7-AD6D-A675485E7448} + {2BDA50C8-767A-4560-9547-15AFC972A6E3} = {3EA11364-0513-44B7-AD6D-A675485E7448} + {2BCE8150-C16C-4226-B216-C7A0463ADC56} = {6C4A2627-AF22-4388-9DF7-7A9AEACFD635} {ABE3B7EE-5B31-4C9A-976A-AD28D257B147} = {87ABA679-F3F4-48CE-82B3-1AAE5D0A5935} {31668B33-6157-4A5B-8D4C-18AF760DCA1B} = {ABE3B7EE-5B31-4C9A-976A-AD28D257B147} {C80D225C-F072-4B24-9ACE-82EFD9362237} = {ABE3B7EE-5B31-4C9A-976A-AD28D257B147} @@ -189,6 +194,14 @@ Global {B16AAB37-9FF4-4940-AC7D-437DFD18A6F6}.Debug|Any CPU.Build.0 = Debug|Any CPU {B16AAB37-9FF4-4940-AC7D-437DFD18A6F6}.Release|Any CPU.ActiveCfg = Release|Any CPU {B16AAB37-9FF4-4940-AC7D-437DFD18A6F6}.Release|Any CPU.Build.0 = Release|Any CPU + {2BDA50C8-767A-4560-9547-15AFC972A6E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2BDA50C8-767A-4560-9547-15AFC972A6E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2BDA50C8-767A-4560-9547-15AFC972A6E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2BDA50C8-767A-4560-9547-15AFC972A6E3}.Release|Any CPU.Build.0 = Release|Any CPU + {2BCE8150-C16C-4226-B216-C7A0463ADC56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2BCE8150-C16C-4226-B216-C7A0463ADC56}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2BCE8150-C16C-4226-B216-C7A0463ADC56}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2BCE8150-C16C-4226-B216-C7A0463ADC56}.Release|Any CPU.Build.0 = Release|Any CPU {1F5A7B1A-2566-481F-91B5-A63D7F939973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1F5A7B1A-2566-481F-91B5-A63D7F939973}.Debug|Any CPU.Build.0 = Debug|Any CPU {1F5A7B1A-2566-481F-91B5-A63D7F939973}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 27e5fbd14d..18033ed4ee 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -1,25 +1,32 @@ - [User Guide](#user-guide) + - [OpenSearch.Client](#opensearchclient) - [Getting Started](#getting-started) - [Connecting](#connecting) - [Indexing](#indexing) - [Getting a document](#getting-a-document) - [Searching for documents](#searching-for-documents) - [Falling back to OpenSearch.Net](#falling-back-to-opensearchnet) - - [OpenSearch.Net](#opensearchnet) + - [OpenSearch.Net.Auth.AwsSigV4](#opensearchnetauthawssigv4) - [Getting Started](#getting-started-1) - [Connecting](#connecting-1) + - [Configuring Region & Credentials](#configuring-region--credentials) + - [OpenSearch.Net](#opensearchnet) + - [Getting Started](#getting-started-2) + - [Connecting](#connecting-2) # User Guide This user guide specifies how to include and use the .NET client in your application. +## [OpenSearch.Client](src/OpenSearch.Client) + ### Getting Started -Include OSC in your .csproj file. +Include OpenSearch.Client in your .csproj file. ```xml ... - + ``` @@ -31,7 +38,7 @@ You can connect to your OpenSearch cluster via a single node, or by specifying m **Connecting to a single node** ```csharp var node = new Uri("http://myserver:9200"); -var config = new ConnectionConfiguration(node); +var config = new ConnectionSettings(node); var client = new OpenSearchClient(config); ``` @@ -83,7 +90,7 @@ var tweet = getResponse.Source; // the original document ### Searching for documents -OSC exposes a fluent interface and a [powerful query DSL](https://opensearch.org/docs/latest/opensearch/query-dsl/index/) +OpenSearch.Client exposes a fluent interface and a [powerful query DSL](https://opensearch.org/docs/latest/opensearch/query-dsl/index/) ```csharp var searchResponse = client.Search(s => s @@ -112,7 +119,7 @@ var searchResponse = client.Search(request); ``` ### Falling back to OpenSearch.Net -OSC also includes and exposes the low-level [OpenSearch.Net](https://github.com/opensearch-project/opensearch-net/tree/main/src/OpenSearch.Net) client that you can fall back to in case anything is missing: +OpenSearch.Client also includes and exposes the low-level [OpenSearch.Net](https://github.com/opensearch-project/opensearch-net/tree/main/src/OpenSearch.Net) client that you can fall back to in case anything is missing: ```csharp IOpenSearchLowLevelClient lowLevelClient = client.LowLevel; @@ -132,6 +139,86 @@ var response = lowLevelClient.Search>("mytweetindex", Post })); ``` +## [OpenSearch.Net.Auth.AwsSigV4](src/OpenSearch.Net.Auth.AwsSigV4) + +An implementation of AWS SigV4 request signing for performing IAM authentication against the managed Amazon OpenSearch Service. +It can be used with both the low-level OpenSearch.Net client as well as the higher-level OpenSearch.Client client. + +### Getting Started +Include OpenSearch.Net.Auth.AwsSigV4 along with your preferred client in your .csproj file. +```xml + + ... + + + + + +``` + +### Connecting +The only wiring required is to use the `AwsSigV4HttpConnection` implementation of `IConnection`. + +**With OpenSearch.Client** +```csharp +var endpoint = new Uri("https://example-aaabbbcccddd111222333.us-east-1.es.amazonaws.com"); +var connection = new AwsSigV4HttpConnection(); +var config = new ConnectionSettings(endpoint, connection); +var client = new OpenSearchClient(config); +``` + +**With OpenSearch.Net** +```csharp +var endpoint = new Uri("https://example-aaabbbcccddd111222333.us-east-1.es.amazonaws.com"); +var connection = new AwsSigV4HttpConnection(); +var config = new ConnectionConfiguration(endpoint, connection); +var client = new OpenSearchLowLevelClient(config); +``` + +### Configuring Region & Credentials +By default, `AwsSigV4HttpConnection` will use the same default logic as the [AWS SDK for .NET](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/creds-assign.html) to determine the credentials and region to use. +However, you may explicitly specify one or both to override this logic, for example: + +**Explicitly setting the region, but the credentials coming from the environment** +```shell +export AWS_ACCESS_KEY_ID="..." +export AWS_SECRET_ACCESS_KEY="..." +export AWS_SESSION_TOKEN="..." +``` +```csharp +var endpoint = new Uri("https://example-aaabbbcccddd111222333.ap-southeast-2.es.amazonaws.com"); +var connection = new AwsSigV4HttpConnection(RegionEndpoint.APSoutheast2); +var config = new ConnectionSettings(endpoint, connection); +var client = new OpenSearchClient(config); +``` + +**Explicitly setting credentials, such as to assume a role, but the region coming from the environment** +```shell +export AWS_REGION="ap-southeast-2" +``` +```csharp +var endpoint = new Uri("https://example-aaabbbcccddd111222333.ap-southeast-2.es.amazonaws.com"); +var credentials = new AssumeRoleAWSCredentials( + FallbackCredentialsFactory.GetCredentials(), + "arn:aws:iam::123456789012:role/my-open-search-ingest-role", + "my-ingest-application"); +var connection = new AwsSigV4HttpConnection(credentials); +var config = new ConnectionSettings(endpoint, connection); +var client = new OpenSearchClient(config); +``` + +**Explicitly setting credentials and region, such as to assume a role** +```csharp +var endpoint = new Uri("https://example-aaabbbcccddd111222333.ap-southeast-2.es.amazonaws.com"); +var credentials = new AssumeRoleAWSCredentials( + FallbackCredentialsFactory.GetCredentials(), + "arn:aws:iam::123456789012:role/my-open-search-ingest-role", + "my-ingest-application"); +var connection = new AwsSigV4HttpConnection(credentials, RegionEndpoint.APSoutheast2); +var config = new ConnectionSettings(endpoint, connection); +var client = new OpenSearchClient(config); +``` + ## [OpenSearch.Net](src/OpenSearch.Net) A low-level, dependency free client that is a simple .NET wrapper for the REST API. It allows you to build and represent your own requests and responses according to you needs. @@ -149,7 +236,7 @@ Include OpenSearch.Net in your .csproj file. ### Connecting -Connecting using the low-level client is very similar to how you would connect using OSC. In fact, the connection constructs that OSC use are actually OpenSearch.Net constructs. Thus, single node connections and connection pooling still apply when using OpenSearch.Net. +Connecting using the low-level client is very similar to how you would connect using OpenSearch.Client. In fact, the connection constructs that OpenSearch.Client use are actually OpenSearch.Net constructs. Thus, single node connections and connection pooling still apply when using OpenSearch.Net. ```csharp var node = new Uri("http://myserver:9200"); diff --git a/src/OpenSearch.Client/CommonAbstractions/ConnectionSettings/ConnectionSettingsBase.cs b/src/OpenSearch.Client/CommonAbstractions/ConnectionSettings/ConnectionSettingsBase.cs index db7985cb48..dbc85d8b27 100644 --- a/src/OpenSearch.Client/CommonAbstractions/ConnectionSettings/ConnectionSettingsBase.cs +++ b/src/OpenSearch.Client/CommonAbstractions/ConnectionSettings/ConnectionSettingsBase.cs @@ -58,7 +58,8 @@ public class ConnectionSettings : ConnectionSettingsBase /// Creates a new instance of connection settings, if is not specified will default to connecting to http://localhost:9200 /// /// - public ConnectionSettings(Uri uri = null) : this(new SingleNodeConnectionPool(uri ?? new Uri("http://localhost:9200"))) { } + /// + public ConnectionSettings(Uri uri = null, IConnection connection = null) : this(new SingleNodeConnectionPool(uri ?? new Uri("http://localhost:9200")), connection) { } /// /// Sets up the client to communicate to OpenSearch Cloud using , diff --git a/src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4HttpClientHandler.cs b/src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4HttpClientHandler.cs new file mode 100644 index 0000000000..4aef4b0b8a --- /dev/null +++ b/src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4HttpClientHandler.cs @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +#if DOTNETCORE + +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Amazon; +using Amazon.Runtime; + +namespace OpenSearch.Net.Auth.AwsSigV4 +{ + internal class AwsSigV4HttpClientHandler : DelegatingHandler + { + private readonly AWSCredentials _credentials; + private readonly RegionEndpoint _region; + + public AwsSigV4HttpClientHandler(AWSCredentials credentials, RegionEndpoint region, HttpMessageHandler innerHandler) + : base(innerHandler) + { + _credentials = credentials ?? throw new ArgumentNullException(nameof(credentials)); + _region = region ?? throw new ArgumentNullException(nameof(region)); + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var credentials = await _credentials.GetCredentialsAsync().ConfigureAwait(false); + + await AwsSigV4Util.SignRequest(request, credentials, _region, DateTime.UtcNow).ConfigureAwait(false); + + return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); + } + } +} + +#endif diff --git a/src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4HttpConnection.cs b/src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4HttpConnection.cs new file mode 100644 index 0000000000..5e9abcd285 --- /dev/null +++ b/src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4HttpConnection.cs @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +using System; +using Amazon; +using Amazon.Runtime; + +namespace OpenSearch.Net.Auth.AwsSigV4 +{ + /// + /// An implementation that performs AWS SigV4 request signing, for performing authentication with Amazon Managed OpenSearch. + /// + public class AwsSigV4HttpConnection : HttpConnection + { + private readonly AWSCredentials _credentials; + private readonly RegionEndpoint _region; + + /// + /// Construct a new connection discovering both the credentials and region from the environment. + /// + /// + public AwsSigV4HttpConnection() : this(null, null) { } + + /// + /// Construct a new connection configured with the specified credentials and using the region discovered from the environment. + /// + /// The credentials to use when signing. + /// + public AwsSigV4HttpConnection(AWSCredentials credentials) : this(credentials, null) { } + + /// + /// Construct a new connection configured with a specified region and using credentials discovered from the environment. + /// + /// The region to use when signing. + /// + public AwsSigV4HttpConnection(RegionEndpoint region) : this(null, region) { } + + /// + /// Construct a new connection configured with the given credentials and region. + /// + /// The credentials to use when signing, or null to have them discovered automatically by the AWS SDK. + /// The region to use when signing, or null to have it discovered automatically by the AWS SDK. + /// Thrown if region is null and is unable to be automatically discovered by the AWS SDK. + /// + /// The same logic as the AWS SDK for .NET + /// is used to automatically discover the credentials and region to use if not provided explicitly. + /// + public AwsSigV4HttpConnection(AWSCredentials credentials, RegionEndpoint region) + { + _credentials = credentials ?? FallbackCredentialsFactory.GetCredentials(); // FallbackCredentialsFactory throws in case of not finding credentials. + _region = region + ?? FallbackRegionFactory.GetRegionEndpoint() // FallbackRegionFactory can return null. + ?? throw new ArgumentNullException(nameof(region), "A RegionEndpoint was not provided and was unable to be determined from the environment."); + } + +#if DOTNETCORE + + protected override System.Net.Http.HttpMessageHandler CreateHttpClientHandler(RequestData requestData) => + new AwsSigV4HttpClientHandler(_credentials, _region, base.CreateHttpClientHandler(requestData)); + +#else + + protected override System.Net.HttpWebRequest CreateHttpWebRequest(RequestData requestData) + { + var request = base.CreateHttpWebRequest(requestData); + AwsSigV4Util.SignRequest(request, requestData, _credentials.GetCredentials(), _region, DateTime.UtcNow); + return request; + } + +#endif + } +} diff --git a/src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4Util.cs b/src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4Util.cs new file mode 100644 index 0000000000..9a6d4a8100 --- /dev/null +++ b/src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4Util.cs @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +using System; +#if DOTNETCORE +using System.Net.Http; +using System.Threading.Tasks; +#else +using System.Net; +#endif +using Amazon; +using Amazon.Runtime; +using Amazon.Runtime.Internal.Auth; + +namespace OpenSearch.Net.Auth.AwsSigV4 +{ + public static class AwsSigV4Util + { +#if DOTNETCORE + public static async Task SignRequest( + HttpRequestMessage request, + ImmutableCredentials credentials, + RegionEndpoint region, + DateTime signingTime) + { + var canonicalRequest = await CanonicalRequest.From(request, credentials, signingTime).ConfigureAwait(false); + + var signature = AWS4Signer.ComputeSignature(credentials, region.SystemName, signingTime, "es", canonicalRequest.SignedHeaders, + canonicalRequest.ToString()); + + request.Headers.TryAddWithoutValidation("x-amz-date", canonicalRequest.XAmzDate); + request.Headers.TryAddWithoutValidation("authorization", signature.ForAuthorizationHeader); + if (!string.IsNullOrEmpty(canonicalRequest.XAmzSecurityToken)) request.Headers.TryAddWithoutValidation("x-amz-security-token", canonicalRequest.XAmzSecurityToken); + } +#else + public static void SignRequest( + HttpWebRequest request, + RequestData requestData, + ImmutableCredentials credentials, + RegionEndpoint region, + DateTime signingTime) + { + var canonicalRequest = CanonicalRequest.From(request, requestData, credentials, signingTime); + + var signature = AWS4Signer.ComputeSignature(credentials, region.SystemName, signingTime, "es", canonicalRequest.SignedHeaders, + canonicalRequest.ToString()); + + request.Headers["x-amz-date"] = canonicalRequest.XAmzDate; + request.Headers["authorization"] = signature.ForAuthorizationHeader; + if (!string.IsNullOrEmpty(canonicalRequest.XAmzSecurityToken)) + request.Headers["x-amz-security-token"] = canonicalRequest.XAmzSecurityToken; + } +#endif + } +} diff --git a/src/OpenSearch.Net.Auth.AwsSigV4/CanonicalRequest.cs b/src/OpenSearch.Net.Auth.AwsSigV4/CanonicalRequest.cs new file mode 100644 index 0000000000..7cb1d3d086 --- /dev/null +++ b/src/OpenSearch.Net.Auth.AwsSigV4/CanonicalRequest.cs @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; +using Amazon.Runtime; +using Amazon.Runtime.Internal.Auth; +using Amazon.Util; + +#if DOTNETCORE +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +#else +using System.Collections.Specialized; +using System.IO; +using System.IO.Compression; +using System.Net; +#endif + +namespace OpenSearch.Net.Auth.AwsSigV4 +{ + public class CanonicalRequest + { + private static readonly IComparer> StringPairComparer = new KeyValuePairComparer(); + + private readonly string _method; + private readonly string _path; + private readonly string _params; + private readonly SortedDictionary> _headers; + private readonly string _contentSha256; + + public string XAmzDate { get; } + + public string XAmzSecurityToken { get; } + + public string SignedHeaders { get; } + + private CanonicalRequest(string method, string path, string queryParams, SortedDictionary> headers, + string contentSha256, string xAmzDate, string xAmzSecurityToken + ) + { + _method = method; + _path = path; + _params = queryParams; + _headers = headers; + _contentSha256 = contentSha256; + SignedHeaders = string.Join(";", _headers.Keys); + XAmzDate = xAmzDate; + XAmzSecurityToken = xAmzSecurityToken; + } + +#if DOTNETCORE + public static async Task From(HttpRequestMessage request, ImmutableCredentials credentials, DateTime signingTime) +#else + public static CanonicalRequest From(HttpWebRequest request, RequestData requestData, ImmutableCredentials credentials, DateTime signingTime) +#endif + { + var path = AWSSDKUtils.CanonicalizeResourcePath(request.RequestUri, null, false); + +#if DOTNETCORE + var bodyBytes = await GetBodyBytes(request).ConfigureAwait(false); +#else + var bodyBytes = GetBodyBytes(requestData); +#endif + + var contentSha256 = AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(bodyBytes), true); + + var xAmzDate = AWS4Signer.FormatDateTime(signingTime, "yyyyMMddTHHmmssZ"); + + var canonicalHeaders = new SortedDictionary>(); + + CanonicalizeHeaders(canonicalHeaders, request.Headers); +#if DOTNETCORE + CanonicalizeHeaders(canonicalHeaders, request.Content?.Headers); +#endif + + canonicalHeaders["host"] = new List { request.RequestUri.Authority }; + canonicalHeaders["x-amz-date"] = new List { xAmzDate }; + + string xAmzSecurityToken = null; + if (credentials.UseToken) + { + xAmzSecurityToken = credentials.Token; + canonicalHeaders["x-amz-security-token"] = new List { xAmzSecurityToken }; + } + + var queryParams = HttpUtility.ParseQueryString(request.RequestUri.Query); + + var orderedParams = queryParams + .AllKeys + .SelectMany(k => queryParams.GetValues(k) + ?.Select(v => !string.IsNullOrEmpty(k) + ? new KeyValuePair(k, v) + : new KeyValuePair(v, string.Empty)) + ?? Enumerable.Empty>()) + .OrderBy(pair => pair, StringPairComparer) + .Select(pair => $"{AWSSDKUtils.UrlEncode(pair.Key, false)}={AWSSDKUtils.UrlEncode(pair.Value, false)}"); + + var paramString = string.Join("&", orderedParams); + +#if DOTNETCORE + var method = request.Method.ToString(); +#else + var method = request.Method; +#endif + + return new CanonicalRequest(method, path, paramString, canonicalHeaders, contentSha256, xAmzDate, xAmzSecurityToken); + } + +#if DOTNETCORE + private static async Task GetBodyBytes(HttpRequestMessage request) + { + if (request.Content == null) return Array.Empty(); + + var body = await request.Content.ReadAsByteArrayAsync().ConfigureAwait(false); + + if (request.Content is ByteArrayContent) return body; + + var content = new ByteArrayContent(body); + foreach (var pair in request.Content.Headers) + { + if (string.Equals(pair.Key, "Content-Length", StringComparison.OrdinalIgnoreCase)) continue; + + content.Headers.TryAddWithoutValidation(pair.Key, pair.Value); + } + request.Content = content; + + return body; + } + +#else + private static byte[] GetBodyBytes(RequestData requestData) + { + if (requestData.PostData == null) return Array.Empty(); + + using var ms = new MemoryStream(); + if (requestData.HttpCompression) + using (var zipStream = new GZipStream(ms, CompressionMode.Compress)) + requestData.PostData.Write(zipStream, requestData.ConnectionSettings); + else + requestData.PostData.Write(ms, requestData.ConnectionSettings); + + return ms.ToArray(); + } +#endif + + private static void CanonicalizeHeaders( + IDictionary> canonicalHeaders, +#if DOTNETCORE + HttpHeaders headers +#else + NameValueCollection headers +#endif + ) + { + if (headers == null) return; + +#if DOTNETCORE + foreach (var pair in headers) +#else + foreach (var pair in headers.AllKeys.Select(k => new KeyValuePair>(k, headers.GetValues(k)))) +#endif + { + if (pair.Value == null) continue; + + var key = pair.Key.ToLowerInvariant(); + + if (key == "user-agent") continue; + + if (!canonicalHeaders.TryGetValue(key, out var dictValues)) + dictValues = canonicalHeaders[key] = new List(); + + dictValues.AddRange(pair.Value.Select(v => AWSSDKUtils.CompressSpaces(v).Trim())); + } + } + + public override string ToString() + { + var sb = new StringBuilder(); + + sb.Append($"{_method}\n"); + sb.Append($"{_path}\n"); + sb.Append($"{_params}\n"); + foreach (var header in _headers) sb.Append($"{header.Key}:{string.Join(",", header.Value)}\n"); + sb.Append('\n'); + sb.Append($"{SignedHeaders}\n"); + sb.Append(_contentSha256); + + return sb.ToString(); + } + + private class KeyValuePairComparer : IComparer> + where TKey : IComparable + where TValue : IComparable + { + public int Compare(KeyValuePair x, KeyValuePair y) + { + var keyComparison = x.Key.CompareTo(y.Key); + return keyComparison != 0 ? keyComparison : x.Value.CompareTo(y.Value); + } + } + } +} diff --git a/src/OpenSearch.Net.Auth.AwsSigV4/OpenSearch.Net.Auth.AwsSigV4.csproj b/src/OpenSearch.Net.Auth.AwsSigV4/OpenSearch.Net.Auth.AwsSigV4.csproj new file mode 100644 index 0000000000..33890a3184 --- /dev/null +++ b/src/OpenSearch.Net.Auth.AwsSigV4/OpenSearch.Net.Auth.AwsSigV4.csproj @@ -0,0 +1,28 @@ + + + OpenSearch.Net.Auth.AwsSigV4 + OpenSearch.Net.Auth.AwsSigV4 + opensearch;opensearch;search;lucene;client;opensearch.client + + Adds support for AWS SigV4 authentication to the OpenSearch.Net client. + + + + + true + true + netstandard2.0;net461 + + + + + + + + + + + + + + diff --git a/src/OpenSearch.Net.Auth.AwsSigV4/packages.lock.json b/src/OpenSearch.Net.Auth.AwsSigV4/packages.lock.json new file mode 100644 index 0000000000..87ad6a5103 --- /dev/null +++ b/src/OpenSearch.Net.Auth.AwsSigV4/packages.lock.json @@ -0,0 +1,323 @@ +{ + "version": 1, + "dependencies": { + ".NETFramework,Version=v4.6.1": { + "AWSSDK.Core": { + "type": "Direct", + "requested": "[3.7.12.11, )", + "resolved": "3.7.12.11", + "contentHash": "Tb6llf5tUU8FiptuB6Xq8vaJpxXDRcWL39nkEiHkDhdctj9l2kPL0DydrCNCAVwLWWTlPXyLUD8i37Rm0mRjaw==" + }, + "ConfigureAwaitChecker.Analyzer": { + "type": "Direct", + "requested": "[4.0.0, )", + "resolved": "4.0.0", + "contentHash": "PCgUb5I1DIe0GsBZ2fPXr/tOgph9Gh6yoHcpsFxNmTvyOQFXxyOcjM7wPs8ylakPNdFYBUs9YeF2Wsx6K/nEDQ==" + }, + "Microsoft.NETFramework.ReferenceAssemblies": { + "type": "Direct", + "requested": "[1.0.0-preview.2, )", + "resolved": "1.0.0-preview.2", + "contentHash": "m+pJPEO7HyXvrOna5Sr3s77ewXonjYWJTNL6drh8xACnMNxnlqUDKx9HfGeSE9wmfY0lQwppaeZpFTPGaH7kZg==", + "dependencies": { + "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.0-preview.2" + } + }, + "Microsoft.SourceLink.GitHub": { + "type": "Direct", + "requested": "[1.0.0, )", + "resolved": "1.0.0", + "contentHash": "aZyGyGg2nFSxix+xMkPmlmZSsnGQ3w+mIG23LTxJZHN+GPwTQ5FpPgDo7RMOq+Kcf5D4hFWfXkGhoGstawX13Q==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.0.0", + "Microsoft.SourceLink.Common": "1.0.0" + } + }, + "Microsoft.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "z2fpmmt+1Jfl+ZnBki9nSP08S1/tbEOxFdsK1rSR+LBehIJz1Xv9/6qOOoGNqlwnAGGVGis1Oj6S8Kt9COEYlQ==" + }, + "Microsoft.CSharp": { + "type": "Transitive", + "resolved": "4.6.0", + "contentHash": "kxn3M2rnAGy5N5DgcIwcE8QTePWU/XiYcQVzn9HqTls2NKluVzVSmVWRjK7OUPWbljCXuZxHyhEz9kPRIQeXow==" + }, + "Microsoft.NETFramework.ReferenceAssemblies.net461": { + "type": "Transitive", + "resolved": "1.0.0-preview.2", + "contentHash": "59D9ISjzCpfHG41r5x4BNZNNOCmE2o5YX8vcdOwsqfxOA0+6vQnxZrYq8KtthUU2JSvC13g941rSr5GRaNQOJg==" + }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "G8DuQY8/DK5NN+3jm5wcMcd9QYD90UV7MiLmdljSJixi3U/vNaeBKmmXUqI4DJCOeWizIUEh4ALhSt58mR+5eg==" + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA==", + "dependencies": { + "System.Memory": "4.5.4", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + } + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==" + }, + "opensearch.net": { + "type": "Project", + "dependencies": { + "Microsoft.CSharp": "4.6.0", + "System.Buffers": "4.5.1", + "System.Diagnostics.DiagnosticSource": "5.0.0" + } + } + }, + ".NETStandard,Version=v2.0": { + "AWSSDK.Core": { + "type": "Direct", + "requested": "[3.7.12.11, )", + "resolved": "3.7.12.11", + "contentHash": "Tb6llf5tUU8FiptuB6Xq8vaJpxXDRcWL39nkEiHkDhdctj9l2kPL0DydrCNCAVwLWWTlPXyLUD8i37Rm0mRjaw==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "1.1.0" + } + }, + "ConfigureAwaitChecker.Analyzer": { + "type": "Direct", + "requested": "[4.0.0, )", + "resolved": "4.0.0", + "contentHash": "PCgUb5I1DIe0GsBZ2fPXr/tOgph9Gh6yoHcpsFxNmTvyOQFXxyOcjM7wPs8ylakPNdFYBUs9YeF2Wsx6K/nEDQ==" + }, + "Microsoft.NETFramework.ReferenceAssemblies": { + "type": "Direct", + "requested": "[1.0.0-preview.2, )", + "resolved": "1.0.0-preview.2", + "contentHash": "m+pJPEO7HyXvrOna5Sr3s77ewXonjYWJTNL6drh8xACnMNxnlqUDKx9HfGeSE9wmfY0lQwppaeZpFTPGaH7kZg==" + }, + "Microsoft.SourceLink.GitHub": { + "type": "Direct", + "requested": "[1.0.0, )", + "resolved": "1.0.0", + "contentHash": "aZyGyGg2nFSxix+xMkPmlmZSsnGQ3w+mIG23LTxJZHN+GPwTQ5FpPgDo7RMOq+Kcf5D4hFWfXkGhoGstawX13Q==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.0.0", + "Microsoft.SourceLink.Common": "1.0.0" + } + }, + "NETStandard.Library": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "1Am6l4Vpn3/K32daEqZI+FFr96OlZkgwK2LcT3pZ2zWubR5zTPW3/FkO1Rat9kb7oQOa4rxgl9LJHc5tspCWfg==", + "dependencies": { + "System.Threading.Tasks.Extensions": "4.5.2" + } + }, + "Microsoft.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "z2fpmmt+1Jfl+ZnBki9nSP08S1/tbEOxFdsK1rSR+LBehIJz1Xv9/6qOOoGNqlwnAGGVGis1Oj6S8Kt9COEYlQ==" + }, + "Microsoft.CSharp": { + "type": "Transitive", + "resolved": "4.6.0", + "contentHash": "kxn3M2rnAGy5N5DgcIwcE8QTePWU/XiYcQVzn9HqTls2NKluVzVSmVWRjK7OUPWbljCXuZxHyhEz9kPRIQeXow==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + }, + "Microsoft.NETCore.Targets": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "G8DuQY8/DK5NN+3jm5wcMcd9QYD90UV7MiLmdljSJixi3U/vNaeBKmmXUqI4DJCOeWizIUEh4ALhSt58mR+5eg==" + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA==", + "dependencies": { + "System.Memory": "4.5.4", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + } + }, + "System.IO": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.4.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ==" + }, + "System.Reflection": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==", + "dependencies": { + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.ILGeneration": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.Lightweight": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==" + }, + "System.Text.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Threading.Tasks": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.2", + "contentHash": "BG/TNxDFv0svAzx8OiMXDlsHfGw623BZ8tCXw4YLhDFDvDhNUEV58jKYMGRnkbJNm7c3JNNJDiN7JBMzxRBR2w==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.2" + } + }, + "opensearch.net": { + "type": "Project", + "dependencies": { + "Microsoft.CSharp": "4.6.0", + "System.Buffers": "4.5.1", + "System.Diagnostics.DiagnosticSource": "5.0.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.Lightweight": "4.3.0" + } + } + } + } +} \ No newline at end of file diff --git a/src/OpenSearch.Net/Configuration/ConnectionConfiguration.cs b/src/OpenSearch.Net/Configuration/ConnectionConfiguration.cs index a58a7fa96a..f847c82351 100644 --- a/src/OpenSearch.Net/Configuration/ConnectionConfiguration.cs +++ b/src/OpenSearch.Net/Configuration/ConnectionConfiguration.cs @@ -99,9 +99,10 @@ public class ConnectionConfiguration : ConnectionConfiguration /// /// The root of the OpenSearch node we want to connect to. Defaults to http://localhost:9200 + /// A connection implementation that can make API requests. Defaults to [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - public ConnectionConfiguration(Uri uri = null) - : this(new SingleNodeConnectionPool(uri ?? new Uri("http://localhost:9200"))) { } + public ConnectionConfiguration(Uri uri = null, IConnection connection = null) + : this(new SingleNodeConnectionPool(uri ?? new Uri("http://localhost:9200")), connection) { } /// /// Sets up the client to communicate to OpenSearch Cloud using , @@ -281,7 +282,7 @@ protected ConnectionConfiguration(IConnectionPool connectionPool, IConnection co bool IConnectionConfigurationValues.TransferEncodingChunked => _transferEncodingChunked; bool IConnectionConfigurationValues.EnableTcpStats => _enableTcpStats; bool IConnectionConfigurationValues.EnableThreadPoolStats => _enableThreadPoolStats; - + MetaHeaderProvider IConnectionConfigurationValues.MetaHeaderProvider { get; } = new MetaHeaderProvider(); void IDisposable.Dispose() => DisposeManagedResources(); @@ -366,7 +367,7 @@ public T SniffOnConnectionFault(bool sniffsOnConnectionFault = true) => public T DisableAutomaticProxyDetection(bool disable = true) => Assign(disable, (a, v) => a._disableAutomaticProxyDetection = v); /// - /// Disables the meta header which is included on all requests by default. This header contains lightweight information + /// Disables the meta header which is included on all requests by default. This header contains lightweight information /// about the client and runtime. /// public T DisableMetaHeader(bool disable = true) => Assign(disable, (a, v) => a._disableMetaHeader = v); diff --git a/src/OpenSearch.Net/OpenSearch.Net.csproj b/src/OpenSearch.Net/OpenSearch.Net.csproj index 56e328c00c..7a356c1e1b 100644 --- a/src/OpenSearch.Net/OpenSearch.Net.csproj +++ b/src/OpenSearch.Net/OpenSearch.Net.csproj @@ -93,4 +93,4 @@ UnsafeMemory.tt - \ No newline at end of file + diff --git a/tests/Tests.Auth.AwsSigV4/CanonicalRequestTests.cs b/tests/Tests.Auth.AwsSigV4/CanonicalRequestTests.cs new file mode 100644 index 0000000000..886f42b25d --- /dev/null +++ b/tests/Tests.Auth.AwsSigV4/CanonicalRequestTests.cs @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +using System; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using System.Web; +using Amazon.Runtime; +using FluentAssertions; +using OpenSearch.Net.Auth.AwsSigV4; +using OpenSearch.OpenSearch.Xunit.XunitPlumbing; + +namespace Tests.Auth.AwsSigV4 +{ + public class CanonicalRequestTests + { + private static readonly ImmutableCredentials TestCredentials = new("test-access-key", "test-secret-key", null); + private static readonly DateTime TestSigningTime = new(2021, 05, 11, 15, 40, 45, DateTimeKind.Utc); + + [U] public async Task TestDoubleEncodePath() + { + var request = new HttpRequestMessage(HttpMethod.Post, + "https://tj9n5r0m12.execute-api.us-east-1.amazonaws.com/test/@connections/JBDvjfGEIAMCERw%3D"); + + await TestCanonicalRequest(request, @"POST +/test/%40connections/JBDvjfGEIAMCERw%253D + +host:tj9n5r0m12.execute-api.us-east-1.amazonaws.com +x-amz-date:20210511T154045Z + +host;x-amz-date +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + } + + [U] public async Task TestDoubleUrlEncode() + { + var request = new HttpRequestMessage(HttpMethod.Post, + "https://lambda.us-east-2.amazonaws.com/2015-03-31/functions/arn%3Aaws%3Alambda%3Aus-west-2%3A892717189312%3Afunction%3Amy-rusty-fun/invocations"); + + await TestCanonicalRequest(request, @"POST +/2015-03-31/functions/arn%253Aaws%253Alambda%253Aus-west-2%253A892717189312%253Afunction%253Amy-rusty-fun/invocations + +host:lambda.us-east-2.amazonaws.com +x-amz-date:20210511T154045Z + +host;x-amz-date +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + } + + [U] public async Task TestTildeInUri() + { + var request = new HttpRequestMessage(HttpMethod.Get, + "https://s3.us-east-1.amazonaws.com/my-bucket?list-type=2&prefix=~objprefix&single&k=&unreserved=-_.~"); + + await TestCanonicalRequest(request, @"GET +/my-bucket +k=&list-type=2&prefix=~objprefix&single=&unreserved=-_.~ +host:s3.us-east-1.amazonaws.com +x-amz-date:20210511T154045Z + +host;x-amz-date +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + } + + [U] public async Task TestQueryParamMultipleValues() + { + var request = new HttpRequestMessage(HttpMethod.Get, + "https://s3.us-east-1.amazonaws.com/my-bucket?list-type=2&list-type=1"); + + await TestCanonicalRequest(request, @"GET +/my-bucket +list-type=1&list-type=2 +host:s3.us-east-1.amazonaws.com +x-amz-date:20210511T154045Z + +host;x-amz-date +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + } + + [U] public static async Task TestAllPrintableAsciiQueryParam() + { + var printableAscii = string.Concat(Enumerable.Range(32, 95).Select(c => (char)c)); + var queryParams = HttpUtility.ParseQueryString(string.Empty); + queryParams["list-type"] = "2"; + queryParams["prefix"] = printableAscii; + + var uri = new UriBuilder + { + Scheme = "https", + Host = "s3.us-east-1.amazonaws.com", + Path = "/my-bucket", + Query = queryParams.ToString() ?? string.Empty + } + .Uri; + + var request = new HttpRequestMessage(HttpMethod.Get, uri); + + await TestCanonicalRequest(request, @"GET +/my-bucket +list-type=2&prefix=%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~ +host:s3.us-east-1.amazonaws.com +x-amz-date:20210511T154045Z + +host;x-amz-date +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + } + + private static async Task TestCanonicalRequest(HttpRequestMessage request, string expected) + { + var canonicalRequest = await CanonicalRequest.From(request, TestCredentials, TestSigningTime); + + canonicalRequest + .ToString() + .Should() + .Be(expected.Replace("\r\n", "\n")); + } + } +} diff --git a/tests/Tests.Auth.AwsSigV4/Tests.Auth.AwsSigV4.csproj b/tests/Tests.Auth.AwsSigV4/Tests.Auth.AwsSigV4.csproj new file mode 100644 index 0000000000..2795d830cc --- /dev/null +++ b/tests/Tests.Auth.AwsSigV4/Tests.Auth.AwsSigV4.csproj @@ -0,0 +1,18 @@ + + + + net5.0 + True + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Tests.Auth.AwsSigV4/XunitBootstrap.cs b/tests/Tests.Auth.AwsSigV4/XunitBootstrap.cs new file mode 100644 index 0000000000..55f37d3efb --- /dev/null +++ b/tests/Tests.Auth.AwsSigV4/XunitBootstrap.cs @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +using OpenSearch.OpenSearch.Xunit; +using Tests.Core.Xunit; +using Xunit; + +[assembly: TestFramework("OpenSearch.OpenSearch.Xunit.Sdk.OpenSearchTestFramework", "OpenSearch.OpenSearch.Xunit")] +[assembly: OpenSearchXunitConfiguration(typeof(OpenSearchClientXunitRunOptions))] diff --git a/tests/Tests.Auth.AwsSigV4/packages.lock.json b/tests/Tests.Auth.AwsSigV4/packages.lock.json new file mode 100644 index 0000000000..cb36602120 --- /dev/null +++ b/tests/Tests.Auth.AwsSigV4/packages.lock.json @@ -0,0 +1,963 @@ +{ + "version": 1, + "dependencies": { + ".NETCoreApp,Version=v5.0": { + "Microsoft.NET.Test.Sdk": { + "type": "Direct", + "requested": "[16.5.0, )", + "resolved": "16.5.0", + "contentHash": "yHZOhVSPuGqgHi+KhHiAZqNY08avkQraXKvgKgDU8c/ztmGzw7gmukkv49EaTq6T3xmp4XroWk3gAlbJHMxl8w==", + "dependencies": { + "Microsoft.CodeCoverage": "16.5.0", + "Microsoft.TestPlatform.TestHost": "16.5.0" + } + }, + "Microsoft.NETFramework.ReferenceAssemblies": { + "type": "Direct", + "requested": "[1.0.0-preview.2, )", + "resolved": "1.0.0-preview.2", + "contentHash": "m+pJPEO7HyXvrOna5Sr3s77ewXonjYWJTNL6drh8xACnMNxnlqUDKx9HfGeSE9wmfY0lQwppaeZpFTPGaH7kZg==" + }, + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[2.4.5, )", + "resolved": "2.4.5", + "contentHash": "OwHamvBdUKgqsXfBzWiCW/O98BTx81UKzx2bieIOQI7CZFE5NEQZGi8PBQGIKawDW96xeRffiNf20SjfC0x9hw==" + }, + "AWSSDK.Core": { + "type": "Transitive", + "resolved": "3.7.12.11", + "contentHash": "Tb6llf5tUU8FiptuB6Xq8vaJpxXDRcWL39nkEiHkDhdctj9l2kPL0DydrCNCAVwLWWTlPXyLUD8i37Rm0mRjaw==" + }, + "Bogus": { + "type": "Transitive", + "resolved": "22.1.2", + "contentHash": "FnYg++zOsFkN3wQJcPT6U4bmZoW/zDWp474QsZG2KX/ClCiEOwIfUxJ9xuKgwv46K0LvVoicQD09hgPke0FG1A==" + }, + "DiffPlex": { + "type": "Transitive", + "resolved": "1.7.1", + "contentHash": "a0fSO2p8ykrcfzgG0sjpZAMZPthXXz4l6UIVuM9uyIYIh5yga4sq3aydSGt6n+MkdSBKvMurjjaKnxIqZtfG1g==" + }, + "FluentAssertions": { + "type": "Transitive", + "resolved": "5.10.3", + "contentHash": "gVPEVp1hLVqcv+7Q2wiDf7kqCNn7+bQcQ0jbJ2mcRT6CeRoZl1tNkqvzSIhvekyldDptk77j1b03MXTTRIqqpg==", + "dependencies": { + "System.Configuration.ConfigurationManager": "4.4.0" + } + }, + "JunitXml.TestLogger": { + "type": "Transitive", + "resolved": "2.1.78", + "contentHash": "4y4FSfKWxlked8ilQdqBBSeRMf5jD/Hkvyp744hc54yQcABLt4rR2Q+4hNqAqrSo+mhwAlusj2rpXpN/5TICCA==" + }, + "Microsoft.CodeCoverage": { + "type": "Transitive", + "resolved": "16.5.0", + "contentHash": "PM5YLtyN45EyUGePJpaNogndlaQPrMgQQXHKMhMESC6KfSVvt+j7+dxBi8NYC6X6dZVysf7ngwhSW3wwvPJRSQ==" + }, + "Microsoft.CSharp": { + "type": "Transitive", + "resolved": "4.6.0", + "contentHash": "kxn3M2rnAGy5N5DgcIwcE8QTePWU/XiYcQVzn9HqTls2NKluVzVSmVWRjK7OUPWbljCXuZxHyhEz9kPRIQeXow==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "TMBuzAHpTenGbGgk0SMTwyEkyijY/Eae4ZGsFNYJvAr/LDn1ku3Etp3FPxChmDp5HHF3kzJuoaa08N0xjqAJfQ==" + }, + "Microsoft.NETCore.Targets": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + }, + "Microsoft.TestPlatform.ObjectModel": { + "type": "Transitive", + "resolved": "16.5.0", + "contentHash": "NnLFxmFBCAS6kye2JFszD5WKgj4Zve5KX/R0mhYwh6BVnSeybI2unRnjEPtLyY3CAVhwrY4bh/8LNFtslAcGZg==", + "dependencies": { + "NuGet.Frameworks": "5.0.0" + } + }, + "Microsoft.TestPlatform.TestHost": { + "type": "Transitive", + "resolved": "16.5.0", + "contentHash": "ytGymboQIvjNX5pLC0yp/Bz9sGDHqSnLQgBRtd4VrqOUgKmmcfxMYZ6p0TBZgAT1oijdC6xqUZ7rl8mbaaXTJw==", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "16.5.0", + "Newtonsoft.Json": "9.0.1" + } + }, + "Microsoft.Win32.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "9ZQKCWxH7Ijp9BfahvL2Zyf1cJIk8XYLF6Yjzr2yi0b2cOut/HQ31qf1ThHAgCc3WiZMdnWcfJCgN82/0UunxA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "Microsoft.Win32.Registry": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "Lw1/VwLH1yxz6SfFEjVRCN0pnflLEsWgnV4qsdJ512/HhTwnKXUG+zDQ4yTO3K/EJQemGoNaBHX5InISNKTzUQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "NuGet.Frameworks": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "c5JVjuVAm4f7E9Vj+v09Z9s2ZsqFDjBpcsyS3M9xRo0bEdm/LVZSzLxxNvfvAwRiiE8nwe1h2G4OwiwlzFKXlA==" + }, + "Nullean.VsTest.Pretty.TestLogger": { + "type": "Transitive", + "resolved": "0.3.0", + "contentHash": "11Cklf+kZ1JS+l3CRZaWQaQHmRm0Je/iIrci6bwY5c9/QXrCuYgWe/A2w0G1eYe33QU5sgUmds48Y7HQFK89mw==", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "15.8.0" + } + }, + "Proc": { + "type": "Transitive", + "resolved": "0.6.1", + "contentHash": "xRSCfgQNoGy60MOuvD2X1euzqvWDoyfpB8NAfVs2E5K5U1I8cA9MvVY6NbUkp5ApbOmVXls2JEPrOn8rQi2Pzg==", + "dependencies": { + "System.Diagnostics.Process": "[4.3.0]", + "System.Threading.Thread": "[4.3.0]" + } + }, + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "7VSGO0URRKoMEAq0Sc9cRz8mb6zbyx/BZDEWhgPdzzpmFhkam3fJ1DAGWFXBI4nGlma+uPKpfuMQP5LXRnOH5g==" + }, + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "0oAaTAm6e2oVH+/Zttt0cuhGaePQYKII1dY8iaqP7CvOpVKgLybKRFvQjXR2LtxXOXTVPNv14j0ot8uV+HrUmw==" + }, + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "G24ibsCNi5Kbz0oXWynBoRgtGvsw5ZSVEWjv13/KiCAM8C6wz9zzcCniMeQFIkJ2tasjo2kXlvlBZhplL51kGg==" + }, + "runtime.native.System": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Net.Http": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZVuZJqnnegJhd2k/PtAbbIcZ3aZeITq3sj06oKfMBSfphW3HDmk/t4ObvbOk/JA/swGR0LNqMksAh/f7gpTROg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Security.Cryptography.Apple": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "DloMk88juo0OuOWr56QG7MNchmafTLYWvABy36izkrLI5VledI0rq28KGs1i9wbpeT9NPQrx/wTf8U2vazqQ3Q==", + "dependencies": { + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "4.3.0" + } + }, + "runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "QR1OwtwehHxSeQvZKXe+iSd+d3XZNkEcuWMFYa2i0aG1l+lR739HPicKMlTbJst3spmeekDVBUS7SeS26s4U/g==", + "dependencies": { + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2" + } + }, + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "I+GNKGg2xCHueRd1m9PzeEW7WLbNNLznmTuEi8/vZX71HudUbx1UTwlGkiwMri7JLl8hGaIAWnA/GONhu+LOyQ==" + }, + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "1Z3TAq1ytS1IBRtPXJvEUZdVsfWfeNEhBkbiOCGEl9wwAfsjP2lz3ZFDx5tq8p60/EqbS0HItG5piHuB71RjoA==" + }, + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kVXCuMTrTlxq4XOOMAysuNwsXWpYeboGddNGpIgNSZmv1b6r/s/DPk0fYMB7Q5Qo4bY68o48jt4T4y5BVecbCQ==" + }, + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "6mU/cVmmHtQiDXhnzUImxIcDL48GbTk+TsptXyJA+MIOG9LRjPoAQC/qBFB7X+UNyK86bmvGwC8t+M66wsYC8w==" + }, + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "vjwG0GGcTW/PPg6KVud8F9GLWYuAV1rrw1BKAqY0oh4jcUqg15oYF1+qkGR2x2ZHM4DQnWKQ7cJgYbfncz/lYg==" + }, + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "7KMFpTkHC/zoExs+PwP8jDCWcrK9H6L7soowT80CUx3e+nxP/AFnq0AQAW5W76z2WYbLAYCRyPfwYFG6zkvQRw==" + }, + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "xrlmRCnKZJLHxyyLIqkZjNXqgxnKdZxfItrPkjI+6pkRo5lHX8YvSZlWrSI5AVwLMi4HbNWP7064hcAWeZKp5w==" + }, + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg==" + }, + "SemanticVersioning": { + "type": "Transitive", + "resolved": "0.8.0", + "contentHash": "hUCnQL79hU0W6X4jPeMAtGDwoEJeBEZfGBnkT+jPG45lD7KHn4h61HgYN8y1HAjPrXmC5oJcLx3l8ygPJOqvlA==", + "dependencies": { + "NETStandard.Library": "1.6.0" + } + }, + "SharpZipLib.NETStandard": { + "type": "Transitive", + "resolved": "1.0.7", + "contentHash": "mYKPizF2CY32RQB8FITYy0e30gVgItFA63SFquruaxq+votwL1T+yOfssK10v4enBcxklr8ks48hS1emw5TTXg==", + "dependencies": { + "NETStandard.Library": "1.6.1" + } + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Collections": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Collections.Concurrent": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ztl69Xp0Y/UXCL+3v3tEU+lIy+bvjKNUmopn1wep/a291pVPK7dxBd6T7WnlQqRog+d1a/hSsgRsmFnIBKTPLQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "gWwQv/Ug1qWJmHCmN17nAbxJYmQBM/E94QxKLksvUiiKB1Ld3Sc/eK1lgmbSjDFxkQhVuayI/cGFZhpBSodLrg==", + "dependencies": { + "System.Security.Cryptography.ProtectedData": "4.4.0" + } + }, + "System.Diagnostics.Debug": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA==" + }, + "System.Diagnostics.Process": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "J0wOX07+QASQblsfxmIMFc9Iq7KTXYL3zs2G/Xc704Ylv3NpuVdo6gij6V3PGiptTxqsK0K7CdXenRvKUnkA2g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.Win32.Primitives": "4.3.0", + "Microsoft.Win32.Registry": "4.3.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Thread": "4.3.0", + "System.Threading.ThreadPool": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, + "System.Diagnostics.Tracing": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Calendars": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "GUlBtdOWT4LTV3I+9/PJW+56AnnChTaOqqTLFtdmype/L500M2LIyXgmtd9X2P2VOkmJd5c67H5SaC2QcL1bFA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "FhKmdR6MPG+pxow6wGtNAWdZh7noIOpdD5TwQ3CprzgIE1bBBoim0vbR1+AWsWjQmU7zXHgQo4TWSP6lCeiWcQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0" + } + }, + "System.IO": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.FileSystem": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.FileSystem.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Linq": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Net.Http": { + "type": "Transitive", + "resolved": "4.3.4", + "contentHash": "aOa2d51SEbmM+H+Csw7yJOuNZoHkrP2XnAurye5HWYgGVVU54YZDvsLUYRv6h18X3sPnjNCANmN7ZhIPiqMcjA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.1", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.DiagnosticSource": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Extensions": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Security.Cryptography.X509Certificates": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Http": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2" + } + }, + "System.Net.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "qOu+hDwFwoZPbzPvwut2qATe3ygjeQBDQj91xlsaqGFQUI5i4ZnZb8yyQuLGpDGivEPIt8EJkd1BVzVoP31FXA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Reflection": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Resources.ResourceManager": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "System.Runtime.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.Handles": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.InteropServices": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Runtime.InteropServices.RuntimeInformation": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Threading": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, + "System.Runtime.Numerics": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "yMH+MfdzHjy17l2KESnPiF2dwq7T+xLnSJar7slyimAkUh/gTrS9/UQOtv7xarskJ2/XDSNvfLGOBQPjL7PaHQ==", + "dependencies": { + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Security.Cryptography.Algorithms": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "W1kd2Y8mYSCgc3ULTAZ0hOP2dSdG5YauTb1089T0/kRcN2MpSAW1izOFROrJgxSlMn3ArsgHXagigyi+ibhevg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.Apple": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Cng": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "03idZOqFlsKRL4W+LuCpJ6dBYDUWReug6lZjBa3uJWnk5sPCUXckocevTaUA8iT/MFSrY/2HXkOt753xQ/cf8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Security.Cryptography.Csp": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "X4s/FCkEUnRGnwR3aSfVIkldBmtURMhmexALNTwpjklzxWU7yjMk7GHLKOZTNkgnWnE0q7+BCf9N2LVRWxewaA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Security.Cryptography.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "1DEWjZZly9ae9C79vFwqaO5kaOlI5q+3/55ohmq/7dpDyDfc8lYe7YVxJUZ5MF/NtbkRjwFRo14yM4OEo9EmDw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Linq": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==", + "dependencies": { + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "7bDIyVFNL/xKeFHjhobUAQqSpJq9YTOpbEs6mR233Et01STBMXNAc/V+BM6dwYGc95gVh/Zf+iVXWzj3mE8DWg==", + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog==" + }, + "System.Security.Cryptography.X509Certificates": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "t2Tmu6Y2NtJ2um0RtcuhP7ZdNNxXEgUm2JeoA/0NvlMjAhKCnM1NX07TDl3244mVp3QU6LPEhT3HTtH1uF7IYw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Calendars": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Cng": "4.3.0", + "System.Security.Cryptography.Csp": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Http": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Text.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Text.Encoding.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "6.0.5", + "contentHash": "SSH+YYrMpvLcy7Orzb5K1tSyffnFacWahyxCCjYH1PbSHdAF4dekmIetBurFKgtTHDmwEe/J2Csi/7niRH6d/g==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encodings.Web": "6.0.0" + } + }, + "System.Threading": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", + "dependencies": { + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Tasks": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Threading.Thread": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Threading.ThreadPool": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "k/+g4b7vjdd4aix83sTgC9VG6oXYKAktSfNIJUNGxPEj7ryEOfzHHhfnmsZvjxawwcD9HyWXKCXmPjX8U4zeSw==", + "dependencies": { + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "xunit": { + "type": "Transitive", + "resolved": "2.4.2", + "contentHash": "6Mj73Ont3zj2CJuoykVJfE0ZmRwn7C+pTuRP8c4bnaaTFjwNG6tGe0prJ1yIbMe9AHrpDys63ctWacSsFJWK/w==", + "dependencies": { + "xunit.analyzers": "1.0.0", + "xunit.assert": "2.4.2", + "xunit.core": "[2.4.2]" + } + }, + "xunit.abstractions": { + "type": "Transitive", + "resolved": "2.0.3", + "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" + }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "BeO8hEgs/c8Ls2647fPfieMngncvf0D0xYNDfIO59MolxtCtVjFRd6SRc+7tj8VMqkVOuJcnc9eh4ngI2cAmLQ==" + }, + "xunit.assert": { + "type": "Transitive", + "resolved": "2.4.2", + "contentHash": "pxJISOFjn2XTTi1mcDCkRZrTFb9OtRRCtx2kZFNF51GdReLr1ls2rnyxvAS4JO247K3aNtflvh5Q0346K5BROA==", + "dependencies": { + "NETStandard.Library": "1.6.1" + } + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.4.2", + "contentHash": "KB4yGCxNqIVyekhJLXtKSEq6BaXVp/JO3mbGVE1hxypZTLEe7h+sTbAhpA+yZW2dPtXTuiW+C1B2oxxHEkrmOw==", + "dependencies": { + "xunit.extensibility.core": "[2.4.2]", + "xunit.extensibility.execution": "[2.4.2]" + } + }, + "xunit.extensibility.core": { + "type": "Transitive", + "resolved": "2.4.2", + "contentHash": "W1BoXTIN1C6kpVSMw25huSet25ky6IAQUNovu3zGOGN/jWnbgSoTyCrlIhmXSg0tH5nEf8q7h3OjNHOjyu5PfA==", + "dependencies": { + "NETStandard.Library": "1.6.1", + "xunit.abstractions": "2.0.3" + } + }, + "xunit.extensibility.execution": { + "type": "Transitive", + "resolved": "2.4.2", + "contentHash": "CZmgcKkwpyo8FlupZdWpJCryrAOWLh1FBPG6gmVZuPQkGQsim/oL4PcP4nfrC2hHgXUFtluvaJ0Sp9PQKUMNpg==", + "dependencies": { + "NETStandard.Library": "1.6.1", + "xunit.extensibility.core": "[2.4.2]" + } + }, + "opensearch.client": { + "type": "Project", + "dependencies": { + "OpenSearch.Net": "1.1.0" + } + }, + "opensearch.client.jsonnetserializer": { + "type": "Project", + "dependencies": { + "Newtonsoft.Json": "13.0.1", + "OpenSearch.Client": "1.1.0" + } + }, + "opensearch.net": { + "type": "Project", + "dependencies": { + "Microsoft.CSharp": "4.6.0", + "System.Buffers": "4.5.1", + "System.Diagnostics.DiagnosticSource": "5.0.0" + } + }, + "opensearch.net.auth.awssigv4": { + "type": "Project", + "dependencies": { + "AWSSDK.Core": "3.7.12.11", + "OpenSearch.Net": "1.1.0" + } + }, + "opensearch.opensearch.ephemeral": { + "type": "Project", + "dependencies": { + "OpenSearch.OpenSearch.Managed": "1.1.0", + "SharpZipLib.NETStandard": "1.0.7" + } + }, + "opensearch.opensearch.managed": { + "type": "Project", + "dependencies": { + "OpenSearch.Stack.ArtifactsApi": "1.1.0", + "Proc": "0.6.1", + "System.Net.Http": "4.3.4" + } + }, + "opensearch.opensearch.xunit": { + "type": "Project", + "dependencies": { + "OpenSearch.OpenSearch.Ephemeral": "1.1.0", + "xunit": "2.4.2" + } + }, + "opensearch.stack.artifactsapi": { + "type": "Project", + "dependencies": { + "SemanticVersioning": "0.8.0", + "System.Net.Http": "4.3.4", + "System.Runtime.InteropServices.RuntimeInformation": "4.3.0", + "System.Text.Json": "6.0.5" + } + }, + "tests.configuration": { + "type": "Project", + "dependencies": { + "OpenSearch.OpenSearch.Managed": "1.1.0" + } + }, + "tests.core": { + "type": "Project", + "dependencies": { + "DiffPlex": "1.7.1", + "FluentAssertions": "5.10.3", + "JunitXml.TestLogger": "2.1.78", + "Microsoft.NET.Test.Sdk": "16.5.0", + "Nullean.VsTest.Pretty.TestLogger": "0.3.0", + "OpenSearch.Client.JsonNetSerializer": "1.1.0", + "OpenSearch.OpenSearch.Xunit": "1.1.0", + "Proc": "0.6.1", + "Tests.Domain": "1.1.0", + "xunit": "2.4.2" + } + }, + "tests.domain": { + "type": "Project", + "dependencies": { + "Bogus": "22.1.2", + "Newtonsoft.Json": "13.0.1", + "OpenSearch.Client": "1.1.0", + "OpenSearch.OpenSearch.Managed": "1.1.0", + "Tests.Configuration": "1.1.0" + } + } + } + } +} \ No newline at end of file diff --git a/tests/Tests.Reproduce/Tests.Reproduce.csproj b/tests/Tests.Reproduce/Tests.Reproduce.csproj index 2f4f520ba6..0a57c943c8 100644 --- a/tests/Tests.Reproduce/Tests.Reproduce.csproj +++ b/tests/Tests.Reproduce/Tests.Reproduce.csproj @@ -6,5 +6,6 @@ + \ No newline at end of file diff --git a/tests/Tests.Reproduce/packages.lock.json b/tests/Tests.Reproduce/packages.lock.json index 20b78b3974..145d27b7f4 100644 --- a/tests/Tests.Reproduce/packages.lock.json +++ b/tests/Tests.Reproduce/packages.lock.json @@ -21,6 +21,12 @@ "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.0-preview.2" } }, + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[2.4.5, )", + "resolved": "2.4.5", + "contentHash": "OwHamvBdUKgqsXfBzWiCW/O98BTx81UKzx2bieIOQI7CZFE5NEQZGi8PBQGIKawDW96xeRffiNf20SjfC0x9hw==" + }, "Bogus": { "type": "Transitive", "resolved": "22.1.2",