/*
* 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 System;
using System.Collections.Generic;
using System.Text;
using System.Net;
#if AWS_ASYNC_API
using System.Threading;
using System.Threading.Tasks;
#endif
using Amazon.Internal;
using Amazon.Util;
using Amazon.Runtime.Internal.Util;
namespace Amazon.Runtime.Internal.Auth
{
public enum ClientProtocol { QueryStringProtocol, RestProtocol, Unknown }
public abstract class AbstractAWSSigner
{
private AWS4Signer _aws4Signer;
private AWS4Signer AWS4SignerInstance
{
get
{
if (_aws4Signer == null)
{
lock (this)
{
if (_aws4Signer == null)
_aws4Signer = new AWS4Signer();
}
}
return _aws4Signer;
}
}
private AWS4aSignerCRTWrapper _aws4aSignerCRTWrapper;
private AWS4aSignerCRTWrapper AWS4aSignerCRTWrapperInstance
{
get
{
if (_aws4aSignerCRTWrapper == null)
{
lock (this)
{
if (_aws4aSignerCRTWrapper == null)
_aws4aSignerCRTWrapper = new AWS4aSignerCRTWrapper();
}
}
return _aws4aSignerCRTWrapper;
}
}
///
/// Signals to the Pipeline Handler
/// if a Signer requires valid in order
/// to correctly .
///
public virtual bool RequiresCredentials { get; } = true;
///
/// Computes RFC 2104-compliant HMAC signature.
///
protected static string ComputeHash(string data, string secretkey, SigningAlgorithm algorithm)
{
try
{
string signature = CryptoUtilFactory.CryptoInstance.HMACSign(data, secretkey, algorithm);
return signature;
}
catch (Exception e)
{
throw new Amazon.Runtime.SignatureException("Failed to generate signature: " + e.Message, e);
}
}
///
/// Computes RFC 2104-compliant HMAC signature.
///
protected static string ComputeHash(byte[] data, string secretkey, SigningAlgorithm algorithm)
{
try
{
string signature = CryptoUtilFactory.CryptoInstance.HMACSign(data, secretkey, algorithm);
return signature;
}
catch (Exception e)
{
throw new Amazon.Runtime.SignatureException("Failed to generate signature: " + e.Message, e);
}
}
public abstract void Sign(IRequest request, IClientConfig clientConfig, RequestMetrics metrics, string awsAccessKeyId, string awsSecretAccessKey);
public virtual void Sign(IRequest request, IClientConfig clientConfig, RequestMetrics metrics, ImmutableCredentials credentials)
{
Sign(request, clientConfig, metrics, credentials?.AccessKey, credentials?.SecretKey);
}
#if AWS_ASYNC_API
public virtual System.Threading.Tasks.Task SignAsync(
IRequest request,
IClientConfig clientConfig,
RequestMetrics metrics,
ImmutableCredentials credentials,
CancellationToken token = default)
{
Sign(request, clientConfig, metrics, credentials);
#if NETSTANDARD
return Task.CompletedTask;
#else
return Task.FromResult(0);
#endif
}
#endif
public abstract ClientProtocol Protocol { get; }
///
/// Inspects the supplied evidence to determine if sigv4 or sigv2 signing should be used
///
/// Global setting for the service
/// The request.
/// Configuration for the client
/// True if signature v4 request signing should be used, false if v2 signing should be used
protected static bool UseV4Signing(bool useSigV4Setting, IRequest request, IClientConfig config)
{
if (request.SignatureVersion == SignatureVersion.SigV4 ||
config.SignatureVersion == "4" ||
(useSigV4Setting && config.SignatureVersion != "2"))
{
return true;
}
else
{
// do a cascading series of checks to try and arrive at whether we have
// a recognisable region; this is required to use the AWS4 signer
RegionEndpoint r = null;
if (!string.IsNullOrEmpty(request.AuthenticationRegion))
r = RegionEndpoint.GetBySystemName(request.AuthenticationRegion);
if (r == null && !string.IsNullOrEmpty(config.ServiceURL))
{
var parsedRegion = AWSSDKUtils.DetermineRegion(config.ServiceURL);
if (!string.IsNullOrEmpty(parsedRegion))
r = RegionEndpoint.GetBySystemName(parsedRegion);
}
if (r == null && config.RegionEndpoint != null)
r = config.RegionEndpoint;
if (r != null)
{
var endpoint = r.GetEndpointForService(config.RegionEndpointServiceName, config.ToGetEndpointForServiceOptions());
if (endpoint != null && (endpoint.SignatureVersionOverride == "4" || string.IsNullOrEmpty(endpoint.SignatureVersionOverride)))
return true;
}
return false;
}
}
protected AbstractAWSSigner SelectSigner(IRequest request, IClientConfig config)
{
return SelectSigner(this, useSigV4Setting: false, request: request, config: config);
}
protected AbstractAWSSigner SelectSigner(AbstractAWSSigner defaultSigner,bool useSigV4Setting,
IRequest request, IClientConfig config)
{
if (request.SignatureVersion == SignatureVersion.SigV4a)
return AWS4aSignerCRTWrapperInstance;
else if (UseV4Signing(useSigV4Setting, request, config))
return AWS4SignerInstance;
else
return defaultSigner;
}
}
}