/* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ using Amazon.Runtime.Internal.Util; using Amazon.Runtime.SharedInterfaces; using Amazon.Util.Internal; using System.Collections.Generic; using System.Globalization; using System.IO; namespace Amazon.Runtime.Internal.Auth { /// /// Asymmetric SigV4 signer using a the AWS Common Runtime implementation of SigV4a via AWSSDK.Extensions.CrtIntegration /// public class AWS4aSignerCRTWrapper : AbstractAWSSigner { private const string CRT_WRAPPER_ASSEMBLY_NAME = "AWSSDK.Extensions.CrtIntegration"; private const string CRT_WRAPPER_NUGET_PACKGE_NAME = "AWSSDK.Extensions.CrtIntegration"; private const string CRT_WRAPPER_CLASS_NAME = "Amazon.Extensions.CrtIntegration.CrtAWS4aSigner"; private static IAWSSigV4aProvider _awsSigV4AProvider; private static object _lock = new object(); /// /// Instantiates an SigV4a signer using CRT's SigV4a implementation /// public AWS4aSignerCRTWrapper() : this(true) { } /// /// Instantiates an SigV4a signer using CRT's SigV4a implementation /// /// Whether to sign the request's payload public AWS4aSignerCRTWrapper(bool signPayload) { if (_awsSigV4AProvider == null) { lock(_lock) { if (_awsSigV4AProvider == null) { try { var crtWrapperTypeInfo = ServiceClientHelpers.LoadTypeFromAssembly(CRT_WRAPPER_ASSEMBLY_NAME, CRT_WRAPPER_CLASS_NAME); var constructor = crtWrapperTypeInfo.GetConstructor(new ITypeInfo[] { TypeFactory.GetTypeInfo(typeof(bool)) }); _awsSigV4AProvider = constructor.Invoke(new object[] { signPayload }) as IAWSSigV4aProvider; } catch (FileNotFoundException) { throw new AWSCommonRuntimeException ( string.Format(CultureInfo.InvariantCulture, "Attempting to make a request that requires an implementation of AWS Signature V4a. " + $"Add a reference to the {CRT_WRAPPER_NUGET_PACKGE_NAME} NuGet package to your project to include the AWS Signature V4a signer.") ); } } } } } /// /// Protocol for the requests being signed /// public override ClientProtocol Protocol { get { return _awsSigV4AProvider.Protocol; } } /// /// Calculates and signs the specified request using the asymmetric Sigv4 (Sigv4a) signing protocol. /// The resulting signature is added to the request headers as 'Authorization'. Parameters supplied in the request, either in /// the resource path as a query string or in the Parameters collection must not have been /// uri encoded. If they have, use the SignRequest method to obtain a signature. /// /// /// The request to compute the signature for. Additional headers mandated by the AWS4a protocol /// ('host' and 'x-amz-date') will be added to the request before signing. /// /// /// Client configuration data encompassing the service call (notably authentication /// region, endpoint and service name). /// /// /// Metrics for the request /// /// /// The AWS credentials for the account making the service call. /// public override void Sign(IRequest request, IClientConfig clientConfig, RequestMetrics metrics, ImmutableCredentials credentials) { _awsSigV4AProvider.Sign(request, clientConfig, metrics, credentials); } public override void Sign(IRequest request, IClientConfig clientConfig, RequestMetrics metrics, string awsAccessKeyId, string awsSecretAccessKey) { throw new AWSCommonRuntimeException("SigV4a signing with only an access key and secret is not supported. Call the Sign override with ImmutableCredentials instead."); } /// /// Calculates and signs the specified request using the asymmetric Sigv4 (Sigv4a) signing protocol. /// The resulting signature is added to the request headers as 'Authorization'. Parameters supplied in the request, either in /// the resource path as a query string or in the Parameters collection must not have been /// uri encoded. If they have, use the SignRequest method to obtain a signature. /// /// /// The request to compute the signature for. Additional headers mandated by the AWS4a protocol /// ('host' and 'x-amz-date') will be added to the request before signing. /// /// /// Client configuration data encompassing the service call (notably authentication /// region, endpoint and service name). /// /// /// Metrics for the request /// /// /// The AWS credentials for the account making the service call. /// /// AWS4a Signing Result public AWS4aSigningResult SignRequest(IRequest request, IClientConfig clientConfig, RequestMetrics metrics, ImmutableCredentials credentials) { return _awsSigV4AProvider.SignRequest(request, clientConfig, metrics, credentials); } /// /// Calculates the asymmetric Sigv4 (Sigv4a) signature for a presigned url. /// /// /// The request to compute the signature for. /// /// /// Adding supporting data for the service call required by the signer (notably authentication /// region, endpoint and service name). /// /// /// Metrics for the request /// /// /// The AWS credentials for the account making the service call. /// /// /// The service to sign for /// /// /// The region to sign to, if null then the region the client is configured for will be used. /// /// AWS4a Signing Result public AWS4aSigningResult Presign4a(IRequest request, IClientConfig clientConfig, RequestMetrics metrics, ImmutableCredentials credentials, string service, string overrideSigningRegion) { return _awsSigV4AProvider.Presign4a(request, clientConfig, metrics, credentials, service, overrideSigningRegion); } /// /// Calculates the signature for a single chunk of a chunked SigV4a request /// /// Content of the current chunk /// Signature of the previous chunk /// Signing result of the request's header /// Unpadded SigV4a signature of the given chunk public string SignChunk(Stream chunkBody, string previousSignature, AWS4aSigningResult headerSigningResult) { return _awsSigV4AProvider.SignChunk(chunkBody, previousSignature, headerSigningResult); } /// /// Signs the final chunk containing trailing headers /// /// Trailing header keys and values /// Signature of the previously signed chunk /// Signing result for the "seed" signature consisting of headers /// Signature of the trailing header chunk public string SignTrailingHeaderChunk(IDictionary trailingHeaders, string previousSignature, AWS4aSigningResult headerSigningResult) { return _awsSigV4AProvider.SignTrailingHeaderChunk(trailingHeaders, previousSignature, headerSigningResult); } } }