-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement AWS SigV4 authentication (#66)
* Implement AWS SigV4 authentication Signed-off-by: Thomas Farr <[email protected]> * Improve documentation and ergonomics Signed-off-by: Thomas Farr <[email protected]> * Make overloads explicit and document Signed-off-by: Thomas Farr <[email protected]> * Fix USER_GUIDE table of contents Signed-off-by: Thomas Farr <[email protected]> * Ensure payload checksum is correct when HttpCompression=true on net461 Signed-off-by: Thomas Farr <[email protected]> * Update packages Signed-off-by: Thomas Farr <[email protected]> * Fix license headers Signed-off-by: Thomas Farr <[email protected]> * Fix unit test running Signed-off-by: Thomas Farr <[email protected]> * Move using outside namespace Signed-off-by: Thomas Farr <[email protected]> * Update packages.lock.json Signed-off-by: Thomas Farr <[email protected]> Signed-off-by: Thomas Farr <[email protected]> Signed-off-by: Thomas Farr <[email protected]> Co-authored-by: Thomas Farr <[email protected]> Co-authored-by: Kent Chenery <[email protected]> Co-authored-by: Matt Madigan <[email protected]>
- Loading branch information
1 parent
7c8a709
commit 364c2f6
Showing
17 changed files
with
1,978 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4HttpClientHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<HttpResponseMessage> 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 |
76 changes: 76 additions & 0 deletions
76
src/OpenSearch.Net.Auth.AwsSigV4/AwsSigV4HttpConnection.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
{ | ||
/// <summary> | ||
/// An <see cref="IConnection"/> implementation that performs AWS SigV4 request signing, for performing authentication with Amazon Managed OpenSearch. | ||
/// </summary> | ||
public class AwsSigV4HttpConnection : HttpConnection | ||
{ | ||
private readonly AWSCredentials _credentials; | ||
private readonly RegionEndpoint _region; | ||
|
||
/// <summary> | ||
/// Construct a new connection discovering both the credentials and region from the environment. | ||
/// </summary> | ||
/// <seealso cref="AwsSigV4HttpConnection(AWSCredentials, RegionEndpoint)"/> | ||
public AwsSigV4HttpConnection() : this(null, null) { } | ||
|
||
/// <summary> | ||
/// Construct a new connection configured with the specified credentials and using the region discovered from the environment. | ||
/// </summary> | ||
/// <param name="credentials">The credentials to use when signing.</param> | ||
/// <seealso cref="AwsSigV4HttpConnection(AWSCredentials, RegionEndpoint)"/> | ||
public AwsSigV4HttpConnection(AWSCredentials credentials) : this(credentials, null) { } | ||
|
||
/// <summary> | ||
/// Construct a new connection configured with a specified region and using credentials discovered from the environment. | ||
/// </summary> | ||
/// <param name="region">The region to use when signing.</param> | ||
/// <seealso cref="AwsSigV4HttpConnection(AWSCredentials, RegionEndpoint)"/> | ||
public AwsSigV4HttpConnection(RegionEndpoint region) : this(null, region) { } | ||
|
||
/// <summary> | ||
/// Construct a new connection configured with the given credentials and region. | ||
/// </summary> | ||
/// <param name="credentials">The credentials to use when signing, or null to have them discovered automatically by the AWS SDK.</param> | ||
/// <param name="region">The region to use when signing, or null to have it discovered automatically by the AWS SDK.</param> | ||
/// <exception cref="ArgumentNullException">Thrown if region is null and is unable to be automatically discovered by the AWS SDK.</exception> | ||
/// <remarks> | ||
/// The same logic as the <a href="https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/creds-assign.html">AWS SDK for .NET</a> | ||
/// is used to automatically discover the credentials and region to use if not provided explicitly. | ||
/// </remarks> | ||
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} | ||
} |
Oops, something went wrong.