Lesson 35 - Get Compute Auth Token Working
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
//disable windows complaining about max template size.
|
||||
#pragma warning (disable : 4503)
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if defined (USE_WINDOWS_DLL_SEMANTICS) || defined (_WIN32)
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // _MSC_VER
|
||||
|
||||
#ifdef USE_IMPORT_EXPORT
|
||||
#ifdef SMITHY_EXPORTS
|
||||
#define SMITHY_API __declspec(dllexport)
|
||||
#else
|
||||
#define SMITHY_API __declspec(dllimport)
|
||||
#endif /* SMITHY_EXPORTS */
|
||||
#else
|
||||
#define SMITHY_API
|
||||
#endif // USE_IMPORT_EXPORT
|
||||
#else // defined (USE_WINDOWS_DLL_SEMANTICS) || defined (WIN32)
|
||||
#if ((__GNUC__ >= 6) || defined(__clang__)) && defined(USE_IMPORT_EXPORT) && defined(SMITHY_EXPORTS)
|
||||
#define SMITHY_API __attribute__((visibility("default")))
|
||||
#else
|
||||
#define SMITHY_API
|
||||
#endif /* __GNUC__ >= 4 || defined(__clang__) */
|
||||
#endif // defined (USE_WINDOWS_DLL_SEMANTICS) || defined (WIN32)
|
||||
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/client/AwsSmithyClientBase.h>
|
||||
#include <smithy/client/AwsSmithyClientAsyncRequestContext.h>
|
||||
#include <smithy/client/common/AwsSmithyRequestSigning.h>
|
||||
#include <smithy/identity/identity/AwsIdentity.h>
|
||||
#include <smithy/identity/auth/AuthSchemeOption.h>
|
||||
#include <smithy/identity/auth/AuthSchemeResolverBase.h>
|
||||
#include <smithy/tracing/TelemetryProvider.h>
|
||||
|
||||
#include <aws/crt/Variant.h>
|
||||
|
||||
#include <aws/core/client/ClientConfiguration.h>
|
||||
#include <aws/core/http/HttpResponse.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
#include <aws/core/utils/FutureOutcome.h>
|
||||
#include <aws/core/utils/Outcome.h>
|
||||
|
||||
namespace smithy {
|
||||
namespace client
|
||||
{
|
||||
template<const char* ServiceNameT,
|
||||
typename ServiceClientConfigurationT,
|
||||
typename ServiceAuthSchemeResolverT,
|
||||
typename AuthSchemesVariantT,
|
||||
typename EndpointProviderT,
|
||||
typename SerializerT,
|
||||
typename ResponseT>
|
||||
class AwsSmithyClientT : public AwsSmithyClientBase
|
||||
{
|
||||
public:
|
||||
explicit AwsSmithyClientT(const ServiceClientConfigurationT& clientConfig, const Aws::String& serviceName,
|
||||
const std::shared_ptr<Aws::Http::HttpClient>& httpClient,
|
||||
const std::shared_ptr<Aws::Client::AWSErrorMarshaller>& errorMarshaller,
|
||||
const std::shared_ptr<EndpointProviderT> endpointProvider,
|
||||
const std::shared_ptr<ServiceAuthSchemeResolverT>& authSchemeResolver,
|
||||
const Aws::UnorderedMap<Aws::String, AuthSchemesVariantT>& authSchemes)
|
||||
: AwsSmithyClientBase(Aws::MakeUnique<ServiceClientConfigurationT>(ServiceNameT, clientConfig), serviceName, httpClient, errorMarshaller),
|
||||
m_clientConfiguration(*static_cast<ServiceClientConfigurationT*>(AwsSmithyClientBase::m_clientConfig.get())),
|
||||
m_endpointProvider(endpointProvider),
|
||||
m_authSchemeResolver(authSchemeResolver),
|
||||
m_authSchemes(authSchemes),
|
||||
m_serializer(Aws::MakeUnique<SerializerT>(ServiceNameT, m_clientConfiguration.telemetryProvider))
|
||||
{
|
||||
m_serviceName = ServiceNameT;
|
||||
}
|
||||
|
||||
virtual ~AwsSmithyClientT() = default;
|
||||
|
||||
protected:
|
||||
inline const char* GetServiceClientName() const override { return m_serviceName.c_str(); }
|
||||
|
||||
ResolveEndpointOutcome ResolveEndpoint(const Aws::Endpoint::EndpointParameters& endpointParameters, EndpointUpdateCallback&& epCallback) const override
|
||||
{
|
||||
assert(m_endpointProvider);
|
||||
ResolveEndpointOutcome resolveEndpointOutcome = m_endpointProvider->ResolveEndpoint(endpointParameters);
|
||||
if (resolveEndpointOutcome.IsSuccess())
|
||||
{
|
||||
epCallback(resolveEndpointOutcome.GetResult());
|
||||
}
|
||||
return resolveEndpointOutcome;
|
||||
}
|
||||
|
||||
SelectAuthSchemeOptionOutcome SelectAuthSchemeOption(const AwsSmithyClientAsyncRequestContext& ctx) const override
|
||||
{
|
||||
assert(m_authSchemeResolver);
|
||||
typename ServiceAuthSchemeResolverT::ServiceAuthSchemeParameters identityParams;
|
||||
|
||||
identityParams.serviceName = m_serviceName;
|
||||
identityParams.operation = ctx.m_requestName;
|
||||
identityParams.region = m_clientConfiguration.region;
|
||||
|
||||
if (ctx.m_pRequest) {
|
||||
// refactor once auth scheme resolver will use it's own rule set
|
||||
const auto& epParams = ctx.m_pRequest->GetEndpointContextParams();
|
||||
for (const auto& epParam : epParams) {
|
||||
using ParameterType = Aws::Endpoint::EndpointParameter::ParameterType;
|
||||
if(epParam.GetStoredType() == ParameterType::STRING)
|
||||
identityParams.additionalProperties.insert({epParam.GetName(), epParam.GetStrValueNoCheck()});
|
||||
else if (epParam.GetStoredType() == ParameterType::BOOLEAN)
|
||||
identityParams.additionalProperties.insert({epParam.GetName(), epParam.GetBoolValueNoCheck()});
|
||||
else
|
||||
assert(!"Unknown endpoint parameter!");
|
||||
}
|
||||
const auto& serviceParams = ctx.m_pRequest->GetServiceSpecificParameters();
|
||||
if (serviceParams) {
|
||||
for (const auto& serviceParam : serviceParams->parameterMap) {
|
||||
identityParams.additionalProperties.insert({serviceParam.first, serviceParam.second});
|
||||
}
|
||||
}
|
||||
}
|
||||
Aws::Vector<AuthSchemeOption> authSchemeOptions = m_authSchemeResolver->resolveAuthScheme(identityParams);
|
||||
|
||||
auto authSchemeOptionIt = std::find_if(authSchemeOptions.begin(), authSchemeOptions.end(),
|
||||
[this](const AuthSchemeOption& opt)
|
||||
{
|
||||
return m_authSchemes.find(opt.schemeId) != m_authSchemes.end();
|
||||
});
|
||||
assert(authSchemeOptionIt != authSchemeOptions.end());
|
||||
|
||||
if (authSchemeOptionIt != authSchemeOptions.end()) {
|
||||
return SelectAuthSchemeOptionOutcome(*authSchemeOptionIt);
|
||||
}
|
||||
return AWSError(Aws::Client::CoreErrors::CLIENT_SIGNING_FAILURE,
|
||||
"",
|
||||
"Failed to select an auth scheme",
|
||||
false/*retryable*/);
|
||||
}
|
||||
|
||||
SigningOutcome SignRequest(std::shared_ptr<HttpRequest> httpRequest, const AuthSchemeOption& targetAuthSchemeOption) const override
|
||||
{
|
||||
return AwsClientRequestSigning<AuthSchemesVariantT>::SignRequest(httpRequest, targetAuthSchemeOption, m_authSchemes);
|
||||
}
|
||||
|
||||
bool AdjustClockSkew(HttpResponseOutcome& outcome, const AuthSchemeOption& authSchemeOption) const override
|
||||
{
|
||||
return AwsClientRequestSigning<AuthSchemesVariantT>::AdjustClockSkew(outcome, authSchemeOption, m_authSchemes);
|
||||
}
|
||||
|
||||
ResponseT MakeRequestDeserialize(Aws::AmazonWebServiceRequest const * const request,
|
||||
const char* requestName,
|
||||
Aws::Http::HttpMethod method,
|
||||
EndpointUpdateCallback&& endpointCallback) const
|
||||
{
|
||||
auto httpResponseOutcome = MakeRequestSync(request, requestName, method, std::move(endpointCallback));
|
||||
return m_serializer->Deserialize(std::move(httpResponseOutcome), GetServiceClientName(), requestName);
|
||||
}
|
||||
|
||||
protected:
|
||||
ServiceClientConfigurationT& m_clientConfiguration;
|
||||
std::shared_ptr<EndpointProviderT> m_endpointProvider{};
|
||||
std::shared_ptr<ServiceAuthSchemeResolverT> m_authSchemeResolver{};
|
||||
Aws::UnorderedMap<Aws::String, AuthSchemesVariantT> m_authSchemes{};
|
||||
Aws::UniquePtr<SerializerT> m_serializer{};
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace smithy
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
#include <smithy/interceptor/InterceptorContext.h>
|
||||
|
||||
#include <aws/core/endpoint/AWSEndpoint.h>
|
||||
#include <aws/core/http/HttpRequest.h>
|
||||
#include <aws/core/AmazonWebServiceRequest.h>
|
||||
|
||||
#include <aws/core/utils/DateTime.h>
|
||||
#include <aws/core/utils/Outcome.h>
|
||||
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
class AwsSmithyClientAsyncRequestContext
|
||||
{
|
||||
public:
|
||||
using AwsCoreError = Aws::Client::AWSError<Aws::Client::CoreErrors>;
|
||||
using HttpResponseOutcome = Aws::Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, AwsCoreError>;
|
||||
using ResponseHandlerFunc = std::function<void(HttpResponseOutcome&&)>;
|
||||
|
||||
struct RequestInfo
|
||||
{
|
||||
Aws::Utils::DateTime ttl;
|
||||
long attempt;
|
||||
long maxAttempts;
|
||||
|
||||
Aws::String ToString() const
|
||||
{
|
||||
Aws::StringStream ss;
|
||||
if (ttl.WasParseSuccessful() && ttl != Aws::Utils::DateTime())
|
||||
{
|
||||
assert(attempt > 1);
|
||||
ss << "ttl=" << ttl.ToGmtString(Aws::Utils::DateFormat::ISO_8601_BASIC) << "; ";
|
||||
}
|
||||
ss << "attempt=" << attempt;
|
||||
if (maxAttempts > 0)
|
||||
{
|
||||
ss << "; max=" << maxAttempts;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
explicit operator Aws::String() const
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
};
|
||||
|
||||
Aws::String m_invocationId;
|
||||
Aws::Http::HttpMethod m_method;
|
||||
const Aws::AmazonWebServiceRequest* m_pRequest; // optional
|
||||
|
||||
RequestInfo m_requestInfo;
|
||||
Aws::String m_requestName;
|
||||
std::shared_ptr<Aws::Http::HttpRequest> m_httpRequest;
|
||||
AuthSchemeOption m_authSchemeOption;
|
||||
Aws::Endpoint::AWSEndpoint m_endpoint;
|
||||
|
||||
Aws::Crt::Optional<AwsCoreError> m_lastError;
|
||||
|
||||
size_t m_retryCount;
|
||||
Aws::Vector<void*> m_monitoringContexts;
|
||||
|
||||
ResponseHandlerFunc m_responseHandler;
|
||||
std::shared_ptr<Aws::Utils::Threading::Executor> m_pExecutor;
|
||||
std::shared_ptr<interceptor::InterceptorContext> m_interceptorContext;
|
||||
};
|
||||
} // namespace client
|
||||
} // namespace smithy
|
||||
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/auth/AuthSchemeOption.h>
|
||||
#include <smithy/identity/identity/AwsIdentity.h>
|
||||
#include <smithy/tracing/TelemetryProvider.h>
|
||||
#include <smithy/interceptor/Interceptor.h>
|
||||
#include <smithy/client/features/ChecksumInterceptor.h>
|
||||
|
||||
#include <aws/crt/Variant.h>
|
||||
#include <aws/core/client/ClientConfiguration.h>
|
||||
#include <aws/core/endpoint/EndpointParameter.h>
|
||||
#include <aws/core/http/HttpResponse.h>
|
||||
#include <aws/core/utils/FutureOutcome.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
#include <aws/core/utils/Outcome.h>
|
||||
|
||||
namespace Aws
|
||||
{
|
||||
namespace Utils
|
||||
{
|
||||
namespace RateLimits
|
||||
{
|
||||
class RateLimiterInterface;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Http
|
||||
{
|
||||
class HttpClient;
|
||||
}
|
||||
|
||||
namespace Client
|
||||
{
|
||||
class AWSErrorMarshaller;
|
||||
class RetryStrategy;
|
||||
}
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
namespace Threading
|
||||
{
|
||||
class Executor;
|
||||
}
|
||||
}
|
||||
|
||||
class AmazonWebServiceRequest;
|
||||
}
|
||||
|
||||
namespace Aws
|
||||
{
|
||||
namespace Endpoint
|
||||
{
|
||||
class AWSEndpoint;
|
||||
}
|
||||
}
|
||||
|
||||
namespace smithy {
|
||||
namespace client
|
||||
{
|
||||
class AwsSmithyClientAsyncRequestContext;
|
||||
/* Non-template base client class that contains main Aws Client Request pipeline logic */
|
||||
class SMITHY_API AwsSmithyClientBase
|
||||
{
|
||||
public:
|
||||
using HttpRequest = Aws::Http::HttpRequest;
|
||||
using HttpResponse = Aws::Http::HttpResponse;
|
||||
using CoreErrors = Aws::Client::CoreErrors;
|
||||
using AWSError = Aws::Client::AWSError<CoreErrors>;
|
||||
using ClientError = AWSError;
|
||||
using SigningError = AWSError;
|
||||
using SigningOutcome = Aws::Utils::FutureOutcome<std::shared_ptr<Aws::Http::HttpRequest>, SigningError>;
|
||||
using EndpointUpdateCallback = std::function<void(Aws::Endpoint::AWSEndpoint&)>;
|
||||
using HttpResponseOutcome = Aws::Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, AWSError>;
|
||||
using ResponseHandlerFunc = std::function<void(HttpResponseOutcome&&)>;
|
||||
using SelectAuthSchemeOptionOutcome = Aws::Utils::Outcome<AuthSchemeOption, AWSError>;
|
||||
using ResolveEndpointOutcome = Aws::Utils::Outcome<Aws::Endpoint::AWSEndpoint, AWSError>;
|
||||
|
||||
AwsSmithyClientBase(Aws::UniquePtr<Aws::Client::ClientConfiguration>&& clientConfig,
|
||||
Aws::String serviceName,
|
||||
std::shared_ptr<Aws::Http::HttpClient> httpClient,
|
||||
std::shared_ptr<Aws::Client::AWSErrorMarshaller> errorMarshaller) :
|
||||
m_clientConfig(std::move(clientConfig)),
|
||||
m_serviceName(std::move(serviceName)),
|
||||
m_userAgent(),
|
||||
m_httpClient(std::move(httpClient)),
|
||||
m_errorMarshaller(std::move(errorMarshaller)),
|
||||
m_interceptors{Aws::MakeShared<ChecksumInterceptor>("AwsSmithyClientBase")}
|
||||
{
|
||||
if (!m_clientConfig->retryStrategy)
|
||||
{
|
||||
assert(m_clientConfig->configFactories.retryStrategyCreateFn);
|
||||
m_clientConfig->retryStrategy = m_clientConfig->configFactories.retryStrategyCreateFn();
|
||||
}
|
||||
if (!m_clientConfig->executor)
|
||||
{
|
||||
assert(m_clientConfig->configFactories.executorCreateFn);
|
||||
m_clientConfig->executor = m_clientConfig->configFactories.executorCreateFn();
|
||||
}
|
||||
if (!m_clientConfig->writeRateLimiter)
|
||||
{
|
||||
assert(m_clientConfig->configFactories.writeRateLimiterCreateFn);
|
||||
m_clientConfig->writeRateLimiter = m_clientConfig->configFactories.writeRateLimiterCreateFn();
|
||||
}
|
||||
if (!m_clientConfig->readRateLimiter)
|
||||
{
|
||||
assert(m_clientConfig->configFactories.readRateLimiterCreateFn);
|
||||
m_clientConfig->readRateLimiter = m_clientConfig->configFactories.readRateLimiterCreateFn();
|
||||
}
|
||||
if (!m_clientConfig->telemetryProvider)
|
||||
{
|
||||
assert(m_clientConfig->configFactories.telemetryProviderCreateFn);
|
||||
m_clientConfig->telemetryProvider = m_clientConfig->configFactories.telemetryProviderCreateFn();
|
||||
}
|
||||
|
||||
m_userAgent = Aws::Client::ComputeUserAgentString(m_clientConfig.get());
|
||||
}
|
||||
|
||||
AwsSmithyClientBase(const AwsSmithyClientBase&) = delete;
|
||||
AwsSmithyClientBase(AwsSmithyClientBase&&) = delete;
|
||||
AwsSmithyClientBase& operator=(const AwsSmithyClientBase&) = delete;
|
||||
AwsSmithyClientBase& operator=(AwsSmithyClientBase&&) = delete;
|
||||
|
||||
virtual ~AwsSmithyClientBase() = default;
|
||||
|
||||
void MakeRequestAsync(Aws::AmazonWebServiceRequest const * const request,
|
||||
const char* requestName,
|
||||
Aws::Http::HttpMethod method,
|
||||
EndpointUpdateCallback&& endpointCallback,
|
||||
ResponseHandlerFunc&& responseHandler,
|
||||
std::shared_ptr<Aws::Utils::Threading::Executor> pExecutor) const;
|
||||
|
||||
HttpResponseOutcome MakeRequestSync(Aws::AmazonWebServiceRequest const * const request,
|
||||
const char* requestName,
|
||||
Aws::Http::HttpMethod method,
|
||||
EndpointUpdateCallback&& endpointCallback) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Transforms the AmazonWebServicesResult object into an HttpRequest.
|
||||
*/
|
||||
std::shared_ptr<Aws::Http::HttpRequest> BuildHttpRequest(const std::shared_ptr<AwsSmithyClientAsyncRequestContext>& pRequestCtx, const Aws::Http::URI& uri, Aws::Http::HttpMethod method) const;
|
||||
|
||||
|
||||
virtual void AttemptOneRequestAsync(std::shared_ptr<AwsSmithyClientAsyncRequestContext> pRequestCtx) const;
|
||||
|
||||
virtual void HandleAsyncReply(std::shared_ptr<AwsSmithyClientAsyncRequestContext> pRequestCtx,
|
||||
std::shared_ptr<Aws::Http::HttpResponse> httpResponse) const;
|
||||
|
||||
inline virtual const char* GetServiceClientName() const { return m_serviceName.c_str(); }
|
||||
inline virtual const std::shared_ptr<Aws::Http::HttpClient>& GetHttpClient() { return m_httpClient; }
|
||||
virtual void DisableRequestProcessing();
|
||||
|
||||
virtual ResolveEndpointOutcome ResolveEndpoint(const Aws::Endpoint::EndpointParameters& endpointParameters, EndpointUpdateCallback&& epCallback) const = 0;
|
||||
virtual SelectAuthSchemeOptionOutcome SelectAuthSchemeOption(const AwsSmithyClientAsyncRequestContext& ctx) const = 0;
|
||||
virtual SigningOutcome SignRequest(std::shared_ptr<HttpRequest> httpRequest, const AuthSchemeOption& targetAuthSchemeOption) const = 0;
|
||||
virtual bool AdjustClockSkew(HttpResponseOutcome& outcome, const AuthSchemeOption& authSchemeOption) const = 0;
|
||||
|
||||
protected:
|
||||
Aws::UniquePtr<Aws::Client::ClientConfiguration> m_clientConfig;
|
||||
Aws::String m_serviceName;
|
||||
Aws::String m_userAgent;
|
||||
|
||||
std::shared_ptr<Aws::Http::HttpClient> m_httpClient;
|
||||
std::shared_ptr<Aws::Client::AWSErrorMarshaller> m_errorMarshaller;
|
||||
Aws::Vector<std::shared_ptr<smithy::interceptor::Interceptor>> m_interceptors{};
|
||||
};
|
||||
} // namespace client
|
||||
} // namespace smithy
|
||||
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iomanip>
|
||||
#include <aws/core/http/HttpRequest.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <aws/core/http/HttpClient.h>
|
||||
#include <aws/core/utils/HashingUtils.h>
|
||||
#include <aws/core/utils/crypto/MD5.h>
|
||||
#include <aws/core/utils/logging/LogMacros.h>
|
||||
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
static const char AWS_SMITHY_CLIENT_UTILS_TAG[] = "AwsSmithyClientUtils";
|
||||
|
||||
class Utils
|
||||
{
|
||||
public:
|
||||
using HttpMethod = Aws::Http::HttpMethod;
|
||||
using HeaderValueCollection = Aws::Http::HeaderValueCollection;
|
||||
using DateTime = Aws::Utils::DateTime;
|
||||
using DateFormat = Aws::Utils::DateFormat;
|
||||
using ClientError = Aws::Client::AWSError<Aws::Client::CoreErrors>;
|
||||
|
||||
static void AppendHeaderValueToRequest(const std::shared_ptr<Aws::Http::HttpRequest>& httpRequest,
|
||||
const Aws::String& header,
|
||||
const Aws::String& value)
|
||||
{
|
||||
assert(httpRequest);
|
||||
assert(!header.empty());
|
||||
|
||||
if (!httpRequest->HasHeader(header.c_str()))
|
||||
{
|
||||
httpRequest->SetHeaderValue(header, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Aws::String contentEncoding = httpRequest->GetHeaderValue(header.c_str());
|
||||
contentEncoding.append(",").append(value);
|
||||
httpRequest->SetHeaderValue(header, contentEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
static void AddContentBodyToRequest(const std::shared_ptr<Aws::Http::HttpRequest>& httpRequest,
|
||||
const std::shared_ptr<Aws::IOStream>& body,
|
||||
const std::shared_ptr<Aws::Http::HttpClient>& httpClient,
|
||||
bool needsContentMd5,
|
||||
bool isChunked)
|
||||
{
|
||||
assert(httpRequest);
|
||||
|
||||
httpRequest->AddContentBody(body);
|
||||
|
||||
//If there is no body, we have a content length of 0
|
||||
//note: we also used to remove content-type, but S3 actually needs content-type on InitiateMultipartUpload and it isn't
|
||||
//forbidden by the spec. If we start getting weird errors related to this, make sure it isn't caused by this removal.
|
||||
if (!body)
|
||||
{
|
||||
AWS_LOGSTREAM_TRACE(AWS_SMITHY_CLIENT_UTILS_TAG, "No content body, content-length headers");
|
||||
|
||||
if (httpRequest->GetMethod() == HttpMethod::HTTP_POST || httpRequest->GetMethod() ==
|
||||
HttpMethod::HTTP_PUT)
|
||||
{
|
||||
httpRequest->SetHeaderValue(Aws::Http::CONTENT_LENGTH_HEADER, "0");
|
||||
}
|
||||
else
|
||||
{
|
||||
httpRequest->DeleteHeader(Aws::Http::CONTENT_LENGTH_HEADER);
|
||||
}
|
||||
}
|
||||
|
||||
//Add transfer-encoding:chunked to header
|
||||
if (body && isChunked && !httpRequest->HasHeader(Aws::Http::CONTENT_LENGTH_HEADER))
|
||||
{
|
||||
httpRequest->SetTransferEncoding(Aws::Http::CHUNKED_VALUE);
|
||||
}
|
||||
//in the scenario where we are adding a content body as a stream, the request object likely already
|
||||
//has a content-length header set and we don't want to seek the stream just to find this information.
|
||||
else if (body && !httpRequest->HasHeader(Aws::Http::CONTENT_LENGTH_HEADER))
|
||||
{
|
||||
assert(httpClient);
|
||||
if (!httpClient->SupportsChunkedTransferEncoding())
|
||||
{
|
||||
AWS_LOGSTREAM_WARN(AWS_SMITHY_CLIENT_UTILS_TAG,
|
||||
"This http client doesn't support transfer-encoding:chunked. " <<
|
||||
"The request may fail if it's not a seekable stream.");
|
||||
}
|
||||
AWS_LOGSTREAM_TRACE(AWS_SMITHY_CLIENT_UTILS_TAG,
|
||||
"Found body, but content-length has not been set, attempting to compute content-length");
|
||||
body->seekg(0, body->end);
|
||||
auto streamSize = body->tellg();
|
||||
body->seekg(0, body->beg);
|
||||
Aws::StringStream ss;
|
||||
ss << streamSize;
|
||||
httpRequest->SetContentLength(ss.str());
|
||||
}
|
||||
|
||||
if (needsContentMd5 && body && !httpRequest->HasHeader(Aws::Http::CONTENT_MD5_HEADER))
|
||||
{
|
||||
AWS_LOGSTREAM_TRACE(AWS_SMITHY_CLIENT_UTILS_TAG, "Found body, and content-md5 needs to be set" <<
|
||||
", attempting to compute content-md5");
|
||||
|
||||
//changing the internal state of the hash computation is not a logical state
|
||||
//change as far as constness goes for this class. Due to the platform specificness
|
||||
//of hash computations, we can't control the fact that computing a hash mutates
|
||||
//state on some platforms such as windows (but that isn't a concern of this class.
|
||||
|
||||
// TODO: check refactoring from:
|
||||
// auto md5HashResult = const_cast<AWSClient*>(this)->m_hash->Calculate(*body);
|
||||
Aws::Utils::Crypto::MD5 hash;
|
||||
auto md5HashResult = hash.Calculate(*body);
|
||||
body->clear();
|
||||
if (md5HashResult.IsSuccess())
|
||||
{
|
||||
httpRequest->SetHeaderValue(Aws::Http::CONTENT_MD5_HEADER,
|
||||
Aws::Utils::HashingUtils::Base64Encode(md5HashResult.GetResult()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool DoesResponseGenerateError(const std::shared_ptr<Aws::Http::HttpResponse>& response)
|
||||
{
|
||||
assert(response);
|
||||
if (response->HasClientError())
|
||||
return true;
|
||||
|
||||
static const int SUCCESS_RESPONSE_MIN = 200;
|
||||
static const int SUCCESS_RESPONSE_MAX = 299;
|
||||
|
||||
const int responseCode = static_cast<int>(response->GetResponseCode());
|
||||
return responseCode < SUCCESS_RESPONSE_MIN || responseCode > SUCCESS_RESPONSE_MAX;
|
||||
}
|
||||
|
||||
static Aws::Utils::DateTime GetServerTimeFromError(const ClientError& error)
|
||||
{
|
||||
const HeaderValueCollection& headers = error.GetResponseHeaders();
|
||||
auto awsDateHeaderIter = headers.find(Aws::Utils::StringUtils::ToLower(Aws::Http::AWS_DATE_HEADER));
|
||||
auto dateHeaderIter = headers.find(Aws::Utils::StringUtils::ToLower(Aws::Http::DATE_HEADER));
|
||||
if (awsDateHeaderIter != headers.end())
|
||||
{
|
||||
return DateTime(awsDateHeaderIter->second.c_str(), DateFormat::AutoDetect);
|
||||
}
|
||||
else if (dateHeaderIter != headers.end())
|
||||
{
|
||||
return DateTime(dateHeaderIter->second.c_str(), DateFormat::AutoDetect);
|
||||
}
|
||||
return DateTime();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/client/common/AwsSmithyClientUtils.h>
|
||||
#include <smithy/identity/auth/AuthSchemeOption.h>
|
||||
#include <smithy/identity/identity/AwsIdentity.h>
|
||||
#include <smithy/identity/resolver/AwsIdentityResolverBase.h>
|
||||
#include <smithy/identity/signer/AwsSignerBase.h>
|
||||
|
||||
#include <aws/core/utils/FutureOutcome.h>
|
||||
#include <aws/core/client/AWSError.h>
|
||||
#include <aws/core/http/HttpRequest.h>
|
||||
|
||||
#include <aws/crt/Variant.h>
|
||||
#include <aws/crt/Optional.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
static const char AWS_SMITHY_CLIENT_SIGNING_TAG[] = "AwsClientRequestSigning";
|
||||
//4 Minutes
|
||||
static const std::chrono::milliseconds TIME_DIFF_MAX = std::chrono::minutes(4);
|
||||
//-4 Minutes
|
||||
static const std::chrono::milliseconds TIME_DIFF_MIN = std::chrono::minutes(-4);
|
||||
|
||||
template <typename AuthSchemesVariantT>
|
||||
class AwsClientRequestSigning
|
||||
{
|
||||
public:
|
||||
using HttpRequest = Aws::Http::HttpRequest;
|
||||
using SigningError = Aws::Client::AWSError<Aws::Client::CoreErrors>;
|
||||
using SigningOutcome = Aws::Utils::FutureOutcome<std::shared_ptr<HttpRequest>, SigningError>;
|
||||
using HttpResponseOutcome = Aws::Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, Aws::Client::AWSError<Aws::Client::CoreErrors>>;
|
||||
|
||||
static SigningOutcome SignRequest(std::shared_ptr<HttpRequest> HTTPRequest, const AuthSchemeOption& authSchemeOption,
|
||||
const Aws::UnorderedMap<Aws::String, AuthSchemesVariantT>& authSchemes)
|
||||
{
|
||||
|
||||
auto authSchemeIt = authSchemes.find(authSchemeOption.schemeId);
|
||||
if (authSchemeIt == authSchemes.end())
|
||||
{
|
||||
assert(!"Auth scheme has not been found for a given auth option!");
|
||||
return (SigningError(Aws::Client::CoreErrors::CLIENT_SIGNING_FAILURE,
|
||||
"",
|
||||
"Requested AuthSchemeOption was not found within client Auth Schemes",
|
||||
false/*retryable*/));
|
||||
}
|
||||
|
||||
const AuthSchemesVariantT& authScheme = authSchemeIt->second;
|
||||
|
||||
return SignWithAuthScheme(std::move(HTTPRequest), authScheme, authSchemeOption);
|
||||
}
|
||||
|
||||
static bool AdjustClockSkew(HttpResponseOutcome& outcome, const AuthSchemeOption& authSchemeOption,
|
||||
const Aws::UnorderedMap<Aws::String, AuthSchemesVariantT>& authSchemes)
|
||||
{
|
||||
assert(!outcome.IsSuccess());
|
||||
AWS_LOGSTREAM_WARN(AWS_SMITHY_CLIENT_SIGNING_TAG, "If the signature check failed. This could be because of a time skew. Attempting to adjust the signer.");
|
||||
|
||||
using DateTime = Aws::Utils::DateTime;
|
||||
DateTime serverTime = smithy::client::Utils::GetServerTimeFromError(outcome.GetError());
|
||||
|
||||
auto authSchemeIt = authSchemes.find(authSchemeOption.schemeId);
|
||||
if (authSchemeIt == authSchemes.end())
|
||||
{
|
||||
assert(!"Auth scheme has not been found for a given auth option!");
|
||||
return false;
|
||||
}
|
||||
AuthSchemesVariantT authScheme = authSchemeIt->second;
|
||||
|
||||
ClockSkewVisitor visitor(outcome, serverTime, authSchemeOption);
|
||||
authScheme.Visit(visitor);
|
||||
|
||||
return visitor.m_resultShouldWait;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
struct SignerVisitor
|
||||
{
|
||||
SignerVisitor(std::shared_ptr<HttpRequest> httpRequest, const AuthSchemeOption& targetAuthSchemeOption)
|
||||
: m_httpRequest(std::move(httpRequest)), m_targetAuthSchemeOption(targetAuthSchemeOption)
|
||||
{
|
||||
}
|
||||
|
||||
const std::shared_ptr<HttpRequest> m_httpRequest;
|
||||
const AuthSchemeOption& m_targetAuthSchemeOption;
|
||||
|
||||
Aws::Crt::Optional<SigningOutcome> result;
|
||||
|
||||
template <typename AuthSchemeAlternativeT>
|
||||
void operator()(AuthSchemeAlternativeT& authScheme)
|
||||
{
|
||||
// Auth Scheme Variant alternative contains the requested auth option
|
||||
assert(strcmp(authScheme.schemeId, m_targetAuthSchemeOption.schemeId) == 0);
|
||||
|
||||
using IdentityT = typename std::remove_reference<decltype(authScheme)>::type::IdentityT;
|
||||
using IdentityResolver = IdentityResolverBase<IdentityT>;
|
||||
using Signer = AwsSignerBase<IdentityT>;
|
||||
|
||||
std::shared_ptr<IdentityResolver> identityResolver = authScheme.identityResolver();
|
||||
if (!identityResolver)
|
||||
{
|
||||
result.emplace(SigningError(Aws::Client::CoreErrors::CLIENT_SIGNING_FAILURE,
|
||||
"",
|
||||
"Auth scheme provided a nullptr identityResolver",
|
||||
false/*retryable*/));
|
||||
return;
|
||||
}
|
||||
|
||||
auto identityResult = identityResolver->getIdentity(m_targetAuthSchemeOption.identityProperties(), m_targetAuthSchemeOption.identityProperties());
|
||||
|
||||
if (!identityResult.IsSuccess())
|
||||
{
|
||||
result.emplace(identityResult.GetError());
|
||||
return;
|
||||
}
|
||||
auto identity = std::move(identityResult.GetResultWithOwnership());
|
||||
|
||||
std::shared_ptr<Signer> signer = authScheme.signer();
|
||||
if (!signer)
|
||||
{
|
||||
result.emplace(SigningError(Aws::Client::CoreErrors::CLIENT_SIGNING_FAILURE,
|
||||
"",
|
||||
"Auth scheme provided a nullptr signer",
|
||||
false/*retryable*/));
|
||||
return;
|
||||
}
|
||||
|
||||
result.emplace(signer->sign(m_httpRequest, *identity, m_targetAuthSchemeOption.signerProperties()));
|
||||
}
|
||||
};
|
||||
|
||||
static
|
||||
SigningOutcome SignWithAuthScheme(std::shared_ptr<HttpRequest> httpRequest, const AuthSchemesVariantT& authSchemesVariant,
|
||||
const AuthSchemeOption& targetAuthSchemeOption)
|
||||
{
|
||||
SignerVisitor visitor(httpRequest, targetAuthSchemeOption);
|
||||
AuthSchemesVariantT authSchemesVariantCopy(authSchemesVariant); // TODO: allow const visiting
|
||||
authSchemesVariantCopy.Visit(visitor);
|
||||
|
||||
if (!visitor.result)
|
||||
{
|
||||
return (SigningError(Aws::Client::CoreErrors::CLIENT_SIGNING_FAILURE,
|
||||
"",
|
||||
"Failed to sign with an unknown error",
|
||||
false/*retryable*/));
|
||||
}
|
||||
return std::move(*visitor.result);
|
||||
}
|
||||
|
||||
struct ClockSkewVisitor
|
||||
{
|
||||
using DateTime = Aws::Utils::DateTime;
|
||||
using DateFormat = Aws::Utils::DateFormat;
|
||||
using ClientError = Aws::Client::AWSError<Aws::Client::CoreErrors>;
|
||||
|
||||
ClockSkewVisitor(HttpResponseOutcome& outcome, const DateTime& serverTime, const AuthSchemeOption& targetAuthSchemeOption)
|
||||
: m_outcome(outcome), m_serverTime(serverTime), m_targetAuthSchemeOption(targetAuthSchemeOption)
|
||||
{
|
||||
}
|
||||
|
||||
bool m_resultShouldWait = false;
|
||||
HttpResponseOutcome& m_outcome;
|
||||
const Aws::Utils::DateTime& m_serverTime;
|
||||
const AuthSchemeOption& m_targetAuthSchemeOption;
|
||||
|
||||
template <typename AuthSchemeAlternativeT>
|
||||
void operator()(AuthSchemeAlternativeT& authScheme)
|
||||
{
|
||||
// Auth Scheme Variant alternative contains the requested auth option
|
||||
assert(strcmp(authScheme.schemeId, m_targetAuthSchemeOption.schemeId) == 0);
|
||||
|
||||
using IdentityT = typename std::remove_reference<decltype(authScheme)>::type::IdentityT;
|
||||
using Signer = AwsSignerBase<IdentityT>;
|
||||
|
||||
std::shared_ptr<Signer> signer = authScheme.signer();
|
||||
if (!signer)
|
||||
{
|
||||
AWS_LOGSTREAM_ERROR(AWS_SMITHY_CLIENT_SIGNING_TAG, "Failed to adjust signing clock skew. Signer is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto signingTimestamp = signer->GetSigningTimestamp();
|
||||
if (!m_serverTime.WasParseSuccessful() || m_serverTime == DateTime())
|
||||
{
|
||||
AWS_LOGSTREAM_DEBUG(AWS_SMITHY_CLIENT_SIGNING_TAG, "Date header was not found in the response, can't attempt to detect clock skew");
|
||||
return;
|
||||
}
|
||||
|
||||
AWS_LOGSTREAM_DEBUG(AWS_SMITHY_CLIENT_SIGNING_TAG, "Server time is " << m_serverTime.ToGmtString(DateFormat::RFC822) << ", while client time is " << DateTime::Now().ToGmtString(DateFormat::RFC822));
|
||||
auto diff = DateTime::Diff(m_serverTime, signingTimestamp);
|
||||
//only try again if clock skew was the cause of the error.
|
||||
if (diff >= TIME_DIFF_MAX || diff <= TIME_DIFF_MIN)
|
||||
{
|
||||
diff = DateTime::Diff(m_serverTime, DateTime::Now());
|
||||
AWS_LOGSTREAM_INFO(AWS_SMITHY_CLIENT_SIGNING_TAG, "Computed time difference as " << diff.count() << " milliseconds. Adjusting signer with the skew.");
|
||||
signer->SetClockSkew(diff);
|
||||
ClientError newError(m_outcome.GetError());
|
||||
newError.SetRetryableType(Aws::Client::RetryableType::RETRYABLE);
|
||||
|
||||
m_outcome = std::move(newError);
|
||||
m_resultShouldWait = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <smithy/interceptor/Interceptor.h>
|
||||
|
||||
#include <aws/core/AmazonWebServiceRequest.h>
|
||||
#include <aws/core/http/HttpRequest.h>
|
||||
#include <aws/core/http/HttpResponse.h>
|
||||
#include <aws/core/utils/HashingUtils.h>
|
||||
#include <aws/core/utils/crypto/MD5.h>
|
||||
#include <aws/core/utils/crypto/CRC32.h>
|
||||
#include <aws/core/utils/crypto/Sha256.h>
|
||||
#include <aws/core/utils/crypto/Sha1.h>
|
||||
#include <aws/core/utils/crypto/PrecalculatedHash.h>
|
||||
#include <aws/core/platform/Environment.h>
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
static const char AWS_SMITHY_CLIENT_CHECKSUM[] = "AwsSmithyClientChecksums";
|
||||
|
||||
static const char CHECKSUM_CONTENT_MD5_HEADER[] = "content-md5";
|
||||
|
||||
class ChecksumInterceptor: public smithy::interceptor::Interceptor
|
||||
{
|
||||
public:
|
||||
using HeaderValueCollection = Aws::Http::HeaderValueCollection;
|
||||
using HashingUtils = Aws::Utils::HashingUtils;
|
||||
using MD5 = Aws::Utils::Crypto::MD5;
|
||||
using CRC32 = Aws::Utils::Crypto::CRC32;
|
||||
using CRC32C = Aws::Utils::Crypto::CRC32C;
|
||||
using Sha256 = Aws::Utils::Crypto::Sha256;
|
||||
using Sha1 = Aws::Utils::Crypto::Sha1;
|
||||
using PrecalculatedHash = Aws::Utils::Crypto::PrecalculatedHash;
|
||||
|
||||
~ChecksumInterceptor() override = default;
|
||||
ChecksumInterceptor() = default;
|
||||
ChecksumInterceptor(const ChecksumInterceptor& other) = delete;
|
||||
ChecksumInterceptor(ChecksumInterceptor&& other) noexcept = default;
|
||||
ChecksumInterceptor& operator=(const ChecksumInterceptor& other) = delete;
|
||||
ChecksumInterceptor& operator=(ChecksumInterceptor&& other) noexcept = default;
|
||||
|
||||
static std::shared_ptr<Aws::IOStream> GetBodyStream(const Aws::AmazonWebServiceRequest& request)
|
||||
{
|
||||
if (request.GetBody() != nullptr)
|
||||
{
|
||||
return request.GetBody();
|
||||
}
|
||||
// Return an empty string stream for no body
|
||||
return Aws::MakeShared<Aws::StringStream>(AWS_SMITHY_CLIENT_CHECKSUM, "");
|
||||
}
|
||||
|
||||
ModifyRequestOutcome ModifyBeforeSigning(interceptor::InterceptorContext& context) override
|
||||
{
|
||||
const auto& httpRequest = context.GetTransmitRequest();
|
||||
const auto& request = context.GetModeledRequest();
|
||||
if (httpRequest == nullptr)
|
||||
{
|
||||
return Aws::Client::AWSError<Aws::Client::CoreErrors>{Aws::Client::CoreErrors::VALIDATION,
|
||||
"ValidationErrorException",
|
||||
"Checksum request validation missing request",
|
||||
false};
|
||||
}
|
||||
Aws::String checksumAlgorithmName = Aws::Utils::StringUtils::ToLower(
|
||||
request.GetChecksumAlgorithmName().c_str());
|
||||
if (request.GetServiceSpecificParameters())
|
||||
{
|
||||
auto requestChecksumOverride = request.GetServiceSpecificParameters()->parameterMap.find(
|
||||
"overrideChecksum");
|
||||
if (requestChecksumOverride != request.GetServiceSpecificParameters()->parameterMap.end())
|
||||
{
|
||||
checksumAlgorithmName = requestChecksumOverride->second;
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldSkipChecksum = request.GetServiceSpecificParameters() &&
|
||||
request.GetServiceSpecificParameters()->parameterMap.find("overrideChecksumDisable") !=
|
||||
request.GetServiceSpecificParameters()->parameterMap.end();
|
||||
|
||||
//Check if user has provided the checksum algorithm
|
||||
if (!checksumAlgorithmName.empty() && !shouldSkipChecksum)
|
||||
{
|
||||
// Check if user has provided a checksum value for the specified algorithm
|
||||
const Aws::String checksumType = "x-amz-checksum-" + checksumAlgorithmName;
|
||||
const HeaderValueCollection& headers = request.GetHeaders();
|
||||
const auto checksumHeader = headers.find(checksumType);
|
||||
bool checksumValueAndAlgorithmProvided = checksumHeader != headers.end();
|
||||
|
||||
// For non-streaming payload, the resolved checksum location is always header.
|
||||
// For streaming payload, the resolved checksum location depends on whether it is an unsigned payload, we let AwsAuthSigner decide it.
|
||||
if (request.IsStreaming() && checksumValueAndAlgorithmProvided)
|
||||
{
|
||||
const auto hash = Aws::MakeShared<PrecalculatedHash>(
|
||||
AWS_SMITHY_CLIENT_CHECKSUM, checksumHeader->second);
|
||||
httpRequest->SetRequestHash(checksumAlgorithmName, hash);
|
||||
}
|
||||
else if (checksumValueAndAlgorithmProvided)
|
||||
{
|
||||
httpRequest->SetHeaderValue(checksumType, checksumHeader->second);
|
||||
}
|
||||
else if (checksumAlgorithmName == "crc32")
|
||||
{
|
||||
if (request.IsStreaming())
|
||||
{
|
||||
httpRequest->SetRequestHash(checksumAlgorithmName,
|
||||
Aws::MakeShared<CRC32>(AWS_SMITHY_CLIENT_CHECKSUM));
|
||||
}
|
||||
else
|
||||
{
|
||||
httpRequest->SetHeaderValue(checksumType,
|
||||
HashingUtils::Base64Encode(
|
||||
HashingUtils::CalculateCRC32(*(GetBodyStream(request)))));
|
||||
}
|
||||
}
|
||||
else if (checksumAlgorithmName == "crc32c")
|
||||
{
|
||||
if (request.IsStreaming())
|
||||
{
|
||||
httpRequest->SetRequestHash(checksumAlgorithmName,
|
||||
Aws::MakeShared<CRC32C>(AWS_SMITHY_CLIENT_CHECKSUM));
|
||||
}
|
||||
else
|
||||
{
|
||||
httpRequest->SetHeaderValue(checksumType,
|
||||
HashingUtils::Base64Encode(
|
||||
HashingUtils::CalculateCRC32C(*(GetBodyStream(request)))));
|
||||
}
|
||||
}
|
||||
else if (checksumAlgorithmName == "sha256")
|
||||
{
|
||||
if (request.IsStreaming())
|
||||
{
|
||||
httpRequest->SetRequestHash(checksumAlgorithmName,
|
||||
Aws::MakeShared<Sha256>(AWS_SMITHY_CLIENT_CHECKSUM));
|
||||
}
|
||||
else
|
||||
{
|
||||
httpRequest->SetHeaderValue(checksumType,
|
||||
HashingUtils::Base64Encode(
|
||||
HashingUtils::CalculateSHA256(*(GetBodyStream(request)))));
|
||||
}
|
||||
}
|
||||
else if (checksumAlgorithmName == "sha1")
|
||||
{
|
||||
if (request.IsStreaming())
|
||||
{
|
||||
httpRequest->SetRequestHash(checksumAlgorithmName,
|
||||
Aws::MakeShared<Sha1>(AWS_SMITHY_CLIENT_CHECKSUM));
|
||||
}
|
||||
else
|
||||
{
|
||||
httpRequest->SetHeaderValue(checksumType,
|
||||
HashingUtils::Base64Encode(
|
||||
HashingUtils::CalculateSHA1(*(GetBodyStream(request)))));
|
||||
}
|
||||
}
|
||||
else if (checksumAlgorithmName == "md5" && headers.find(CHECKSUM_CONTENT_MD5_HEADER) == headers.end())
|
||||
{
|
||||
httpRequest->SetHeaderValue(CHECKSUM_CONTENT_MD5_HEADER,
|
||||
HashingUtils::Base64Encode(
|
||||
HashingUtils::CalculateMD5(*(GetBodyStream(request)))));
|
||||
}
|
||||
else
|
||||
{
|
||||
AWS_LOGSTREAM_WARN(AWS_SMITHY_CLIENT_CHECKSUM,
|
||||
"Checksum algorithm: " << checksumAlgorithmName <<
|
||||
"is not supported by SDK.");
|
||||
}
|
||||
}
|
||||
|
||||
// Response checksums
|
||||
if (request.ShouldValidateResponseChecksum())
|
||||
{
|
||||
for (const Aws::String& responseChecksumAlgorithmName : request.GetResponseChecksumAlgorithmNames())
|
||||
{
|
||||
checksumAlgorithmName = Aws::Utils::StringUtils::ToLower(responseChecksumAlgorithmName.c_str());
|
||||
|
||||
if (checksumAlgorithmName == "crc32c")
|
||||
{
|
||||
std::shared_ptr<CRC32C> crc32c = Aws::MakeShared<
|
||||
CRC32C>(AWS_SMITHY_CLIENT_CHECKSUM);
|
||||
httpRequest->AddResponseValidationHash("crc32c", crc32c);
|
||||
}
|
||||
else if (checksumAlgorithmName == "crc32")
|
||||
{
|
||||
std::shared_ptr<CRC32> crc32 = Aws::MakeShared<
|
||||
CRC32>(AWS_SMITHY_CLIENT_CHECKSUM);
|
||||
httpRequest->AddResponseValidationHash("crc32", crc32);
|
||||
}
|
||||
else if (checksumAlgorithmName == "sha1")
|
||||
{
|
||||
std::shared_ptr<Sha1> sha1 = Aws::MakeShared<Sha1>(
|
||||
AWS_SMITHY_CLIENT_CHECKSUM);
|
||||
httpRequest->AddResponseValidationHash("sha1", sha1);
|
||||
}
|
||||
else if (checksumAlgorithmName == "sha256")
|
||||
{
|
||||
std::shared_ptr<Sha256> sha256 = Aws::MakeShared<
|
||||
Sha256>(AWS_SMITHY_CLIENT_CHECKSUM);
|
||||
httpRequest->AddResponseValidationHash("sha256", sha256);
|
||||
}
|
||||
else
|
||||
{
|
||||
AWS_LOGSTREAM_WARN(AWS_SMITHY_CLIENT_CHECKSUM,
|
||||
"Checksum algorithm: " << checksumAlgorithmName <<
|
||||
" is not supported in validating response body yet.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return httpRequest;
|
||||
}
|
||||
|
||||
ModifyResponseOutcome ModifyBeforeDeserialization(interceptor::InterceptorContext& context) override
|
||||
{
|
||||
const auto httpRequest = context.GetTransmitRequest();
|
||||
const auto httpResponse = context.GetTransmitResponse();
|
||||
if (httpRequest == nullptr || httpResponse == nullptr)
|
||||
{
|
||||
return Aws::Client::AWSError<Aws::Client::CoreErrors>{Aws::Client::CoreErrors::VALIDATION,
|
||||
"ValidationErrorException",
|
||||
"Checksum response validation missing request or response",
|
||||
false};
|
||||
}
|
||||
for (const auto& hashIterator : httpRequest->GetResponseValidationHashes())
|
||||
{
|
||||
Aws::String checksumHeaderKey = Aws::String("x-amz-checksum-") + hashIterator.first;
|
||||
// TODO: If checksum ends with -#, then skip
|
||||
if (httpResponse->HasHeader(checksumHeaderKey.c_str()))
|
||||
{
|
||||
const Aws::String& checksumHeaderValue = httpResponse->GetHeader(checksumHeaderKey);
|
||||
if (HashingUtils::Base64Encode(hashIterator.second->GetHash().GetResult()) !=
|
||||
checksumHeaderValue)
|
||||
{
|
||||
auto error = Aws::Client::AWSError<Aws::Client::CoreErrors>{
|
||||
Aws::Client::CoreErrors::VALIDATION, "",
|
||||
"Response checksums mismatch",
|
||||
false/*retryable*/};
|
||||
error.SetResponseHeaders(httpResponse->GetHeaders());
|
||||
error.SetResponseCode(httpResponse->GetResponseCode());
|
||||
error.SetRemoteHostIpAddress(
|
||||
httpResponse->GetOriginatingRequest().GetResolvedRemoteHost());
|
||||
|
||||
AWS_LOGSTREAM_ERROR(AWS_SMITHY_CLIENT_CHECKSUM, error);
|
||||
return {error};
|
||||
}
|
||||
// Validate only a single checksum returned in an HTTP response
|
||||
break;
|
||||
}
|
||||
}
|
||||
return httpResponse;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/platform/Environment.h>
|
||||
#include <aws/core/http/HttpRequest.h>
|
||||
#include <iomanip>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
static const char SMITHY_AWS_LAMBDA_FUNCTION_NAME[] = "AWS_LAMBDA_FUNCTION_NAME";
|
||||
static const char SMITHY_X_AMZN_TRACE_ID[] = "_X_AMZN_TRACE_ID";
|
||||
|
||||
class RecursionDetection
|
||||
{
|
||||
public:
|
||||
static void AppendRecursionDetectionHeader(const std::shared_ptr<Aws::Http::HttpRequest>& ioRequest)
|
||||
{
|
||||
if (!ioRequest || ioRequest->HasHeader(Aws::Http::X_AMZN_TRACE_ID_HEADER))
|
||||
{
|
||||
return;
|
||||
}
|
||||
const Aws::String& awsLambdaFunctionName = Aws::Environment::GetEnv(SMITHY_AWS_LAMBDA_FUNCTION_NAME);
|
||||
if (awsLambdaFunctionName.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Aws::String xAmznTraceIdVal = Aws::Environment::GetEnv(SMITHY_X_AMZN_TRACE_ID);
|
||||
if (xAmznTraceIdVal.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Escape all non-printable ASCII characters by percent encoding
|
||||
Aws::OStringStream xAmznTraceIdValEncodedStr;
|
||||
for (const char ch : xAmznTraceIdVal)
|
||||
{
|
||||
if (ch >= 0x20 && ch <= 0x7e) // ascii chars [32-126] or [' ' to '~'] are not escaped
|
||||
{
|
||||
xAmznTraceIdValEncodedStr << ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A percent-encoded octet is encoded as a character triplet
|
||||
xAmznTraceIdValEncodedStr << '%' // consisting of the percent character "%"
|
||||
<< std::hex << std::setfill('0') << std::setw(2) << std::uppercase
|
||||
<< (size_t)ch
|
||||
//followed by the two hexadecimal digits representing that octet's numeric value
|
||||
<< std::dec << std::setfill(' ') << std::setw(0) << std::nouppercase;
|
||||
}
|
||||
}
|
||||
xAmznTraceIdVal = xAmznTraceIdValEncodedStr.str();
|
||||
|
||||
ioRequest->SetHeaderValue(Aws::Http::X_AMZN_TRACE_ID_HEADER, xAmznTraceIdVal);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/AmazonWebServiceRequest.h>
|
||||
#include <aws/core/client/RequestCompression.h>
|
||||
#include <aws/core/http/HttpClient.h>
|
||||
#include <aws/core/http/HttpRequest.h>
|
||||
#include <smithy/client/common/AwsSmithyClientUtils.h>
|
||||
#include <iomanip>
|
||||
#include <cassert>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
static const char AWS_CLIENT_REQUEST_COMPRESSION_LOG_TAG[] = "RequestPayloadCompression";
|
||||
|
||||
class RequestPayloadCompression
|
||||
{
|
||||
public:
|
||||
static void AddCompressedContentBodyToRequest(const Aws::AmazonWebServiceRequest* pRequest,
|
||||
const std::shared_ptr<Aws::Http::HttpRequest>& httpRequest,
|
||||
const Aws::Client::CompressionAlgorithm& compressionAlgorithm,
|
||||
const std::shared_ptr<Aws::Http::HttpClient>& httpClient)
|
||||
{
|
||||
if (Aws::Client::CompressionAlgorithm::NONE != compressionAlgorithm)
|
||||
{
|
||||
Aws::Client::RequestCompression rc;
|
||||
auto compressOutcome = rc.compress(pRequest->GetBody(), compressionAlgorithm);
|
||||
|
||||
if (compressOutcome.IsSuccess())
|
||||
{
|
||||
const Aws::String compressionAlgorithmId = Aws::Client::GetCompressionAlgorithmId(
|
||||
compressionAlgorithm);
|
||||
Utils::AppendHeaderValueToRequest(httpRequest, Aws::Http::CONTENT_ENCODING_HEADER,
|
||||
compressionAlgorithmId);
|
||||
Utils::AddContentBodyToRequest(httpRequest,
|
||||
compressOutcome.GetResult(),
|
||||
httpClient,
|
||||
pRequest->ShouldComputeContentMd5(),
|
||||
pRequest->IsStreaming() && pRequest->IsChunked() && httpClient->
|
||||
SupportsChunkedTransferEncoding());
|
||||
}
|
||||
else
|
||||
{
|
||||
AWS_LOGSTREAM_ERROR(AWS_CLIENT_REQUEST_COMPRESSION_LOG_TAG,
|
||||
"Failed to compress request, submitting uncompressed");
|
||||
Utils::AddContentBodyToRequest(httpRequest,
|
||||
pRequest->GetBody(),
|
||||
httpClient,
|
||||
pRequest->ShouldComputeContentMd5(),
|
||||
pRequest->IsStreaming() && pRequest->IsChunked() && httpClient->
|
||||
SupportsChunkedTransferEncoding());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
#include <aws/core/AmazonWebServiceResult.h>
|
||||
#include <aws/core/client/AWSError.h>
|
||||
#include <aws/core/utils/Outcome.h>
|
||||
#include <aws/core/utils/json/JsonSerializer.h>
|
||||
#include <smithy/tracing/TracingUtils.h>
|
||||
#include <smithy/tracing/TelemetryProvider.h>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
using TracingUtils = components::tracing::TracingUtils;
|
||||
using CoreErrors = Aws::Client::CoreErrors;
|
||||
using AWSError = Aws::Client::AWSError<CoreErrors>;
|
||||
using JsonValue = Aws::Utils::Json::JsonValue;
|
||||
using HttpResponseOutcome = Aws::Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, AWSError>;
|
||||
using JsonOutcome = Aws::Utils::Outcome<Aws::AmazonWebServiceResult<JsonValue>, AWSError>;
|
||||
using TelemetryProvider = components::tracing::TelemetryProvider;
|
||||
|
||||
class JsonOutcomeSerializer
|
||||
{
|
||||
public:
|
||||
explicit JsonOutcomeSerializer(const std::shared_ptr<TelemetryProvider>& telemetryProvider)
|
||||
: m_telemetryProvider(telemetryProvider)
|
||||
{
|
||||
}
|
||||
|
||||
JsonOutcomeSerializer(const JsonOutcomeSerializer& other) = delete;
|
||||
JsonOutcomeSerializer(JsonOutcomeSerializer&& other) noexcept = default;
|
||||
JsonOutcomeSerializer& operator=(const JsonOutcomeSerializer& other) = delete;
|
||||
JsonOutcomeSerializer& operator=(JsonOutcomeSerializer&& other) noexcept = default;
|
||||
virtual ~JsonOutcomeSerializer() = default;
|
||||
|
||||
JsonOutcome Deserialize(HttpResponseOutcome&& httpOutcome,
|
||||
const Aws::String& serviceName,
|
||||
const Aws::String& requestName) const
|
||||
{
|
||||
if (!httpOutcome.IsSuccess())
|
||||
{
|
||||
return TracingUtils::MakeCallWithTiming<JsonOutcome>(
|
||||
[&]() -> JsonOutcome {
|
||||
return JsonOutcome{std::move(httpOutcome)};
|
||||
},
|
||||
TracingUtils::SMITHY_CLIENT_DESERIALIZATION_METRIC,
|
||||
*m_telemetryProvider->getMeter(serviceName, {}),
|
||||
{{TracingUtils::SMITHY_METHOD_DIMENSION, requestName},
|
||||
{TracingUtils::SMITHY_SERVICE_DIMENSION, serviceName}});
|
||||
}
|
||||
|
||||
if (httpOutcome.GetResult()->GetResponseBody().good() &&
|
||||
httpOutcome.GetResult()->GetResponseBody().tellp() > 0)
|
||||
{
|
||||
JsonValue jsonValue(httpOutcome.GetResult()->GetResponseBody());
|
||||
if (!jsonValue.WasParseSuccessful()) {
|
||||
return TracingUtils::MakeCallWithTiming<JsonOutcome>(
|
||||
[&]() -> JsonOutcome {
|
||||
return JsonOutcome{AWSError(CoreErrors::UNKNOWN,
|
||||
"Json Parser Error",
|
||||
jsonValue.GetErrorMessage(),
|
||||
false)};
|
||||
},
|
||||
TracingUtils::SMITHY_CLIENT_DESERIALIZATION_METRIC,
|
||||
*m_telemetryProvider->getMeter(serviceName, {}),
|
||||
{{TracingUtils::SMITHY_METHOD_DIMENSION, requestName},
|
||||
{TracingUtils::SMITHY_SERVICE_DIMENSION, serviceName}});
|
||||
}
|
||||
|
||||
return TracingUtils::MakeCallWithTiming<JsonOutcome>(
|
||||
[&]() -> JsonOutcome {
|
||||
return JsonOutcome{Aws::AmazonWebServiceResult<JsonValue>(std::move(jsonValue),
|
||||
httpOutcome.GetResult()->GetHeaders(),
|
||||
httpOutcome.GetResult()->GetResponseCode())};
|
||||
},
|
||||
TracingUtils::SMITHY_CLIENT_DESERIALIZATION_METRIC,
|
||||
*m_telemetryProvider->getMeter(serviceName, {}),
|
||||
{{TracingUtils::SMITHY_METHOD_DIMENSION, requestName},
|
||||
{TracingUtils::SMITHY_SERVICE_DIMENSION, serviceName}});
|
||||
}
|
||||
|
||||
return TracingUtils::MakeCallWithTiming<JsonOutcome>(
|
||||
[&]() -> JsonOutcome {
|
||||
return JsonOutcome{Aws::AmazonWebServiceResult<JsonValue>(JsonValue(),
|
||||
httpOutcome.GetResult()->GetHeaders())};
|
||||
},
|
||||
TracingUtils::SMITHY_CLIENT_DESERIALIZATION_METRIC,
|
||||
*m_telemetryProvider->getMeter(serviceName, {}),
|
||||
{{TracingUtils::SMITHY_METHOD_DIMENSION, requestName},
|
||||
{TracingUtils::SMITHY_SERVICE_DIMENSION, serviceName}});
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<TelemetryProvider> m_telemetryProvider;
|
||||
};
|
||||
} // namespace client
|
||||
} // namespace smithy
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
#include <aws/core/AmazonWebServiceResult.h>
|
||||
#include <aws/core/client/AWSError.h>
|
||||
#include <aws/core/utils/Outcome.h>
|
||||
#include <aws/core/utils/xml/XmlSerializer.h>
|
||||
#include <smithy/tracing/TracingUtils.h>
|
||||
#include <smithy/tracing/TelemetryProvider.h>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
using TracingUtils = components::tracing::TracingUtils;
|
||||
using CoreErrors = Aws::Client::CoreErrors;
|
||||
using AWSError = Aws::Client::AWSError<CoreErrors>;
|
||||
using XmlDocument = Aws::Utils::Xml::XmlDocument;
|
||||
using HttpResponseOutcome = Aws::Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, AWSError>;
|
||||
using XmlServiceResult = Aws::AmazonWebServiceResult<XmlDocument>;
|
||||
using XmlOutcome = Aws::Utils::Outcome<XmlServiceResult, AWSError>;
|
||||
using TelemetryProvider = components::tracing::TelemetryProvider;
|
||||
|
||||
class XmlOutcomeSerializer
|
||||
{
|
||||
public:
|
||||
explicit XmlOutcomeSerializer(const std::shared_ptr<TelemetryProvider>& telemetryProvider)
|
||||
: m_telemetryProvider(telemetryProvider)
|
||||
{
|
||||
}
|
||||
|
||||
XmlOutcomeSerializer(const XmlOutcomeSerializer& other) = delete;
|
||||
XmlOutcomeSerializer(XmlOutcomeSerializer&& other) noexcept = default;
|
||||
XmlOutcomeSerializer& operator=(const XmlOutcomeSerializer& other) = delete;
|
||||
XmlOutcomeSerializer& operator=(XmlOutcomeSerializer&& other) noexcept = default;
|
||||
virtual ~XmlOutcomeSerializer() = default;
|
||||
|
||||
|
||||
XmlOutcome Deserialize(HttpResponseOutcome&& httpOutcome,
|
||||
const Aws::String& serviceName,
|
||||
const Aws::String& requestName) const
|
||||
{
|
||||
if (!httpOutcome.IsSuccess())
|
||||
{
|
||||
return TracingUtils::MakeCallWithTiming<XmlOutcome>(
|
||||
[&]() -> XmlOutcome {
|
||||
return {std::move(httpOutcome)};
|
||||
},
|
||||
TracingUtils::SMITHY_CLIENT_DESERIALIZATION_METRIC,
|
||||
*m_telemetryProvider->getMeter(serviceName, {}),
|
||||
{{TracingUtils::SMITHY_METHOD_DIMENSION, requestName}, {TracingUtils::SMITHY_SERVICE_DIMENSION, serviceName}});
|
||||
}
|
||||
|
||||
if (httpOutcome.GetResult()->GetResponseBody().good() &&
|
||||
httpOutcome.GetResult()->GetResponseBody().tellp() > 0)
|
||||
{
|
||||
return TracingUtils::MakeCallWithTiming<XmlOutcome>(
|
||||
[&]() -> XmlOutcome {
|
||||
XmlDocument xmlDoc = XmlDocument::CreateFromXmlStream(httpOutcome.GetResult()->GetResponseBody());
|
||||
|
||||
if (!xmlDoc.WasParseSuccessful())
|
||||
{
|
||||
AWS_LOGSTREAM_ERROR("XmlOutcomeSerializer", "Xml parsing for error failed with message " << xmlDoc.GetErrorMessage().c_str());
|
||||
return AWSError(CoreErrors::UNKNOWN,
|
||||
"Xml Parse Error",
|
||||
xmlDoc.GetErrorMessage(),
|
||||
false);
|
||||
}
|
||||
|
||||
return {XmlServiceResult(std::move(xmlDoc),
|
||||
httpOutcome.GetResult()->GetHeaders(),
|
||||
httpOutcome.GetResult()->GetResponseCode())};
|
||||
},
|
||||
TracingUtils::SMITHY_CLIENT_DESERIALIZATION_METRIC,
|
||||
*m_telemetryProvider->getMeter(serviceName, {}),
|
||||
{{TracingUtils::SMITHY_METHOD_DIMENSION, requestName}, {TracingUtils::SMITHY_SERVICE_DIMENSION, serviceName}});
|
||||
}
|
||||
|
||||
return {XmlServiceResult(XmlDocument(), httpOutcome.GetResult()->GetHeaders())};
|
||||
}
|
||||
private:
|
||||
std::shared_ptr<TelemetryProvider> m_telemetryProvider;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
} // namespace smithy
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/resolver/AwsIdentityResolverBase.h>
|
||||
#include <smithy/identity/signer/AwsSignerBase.h>
|
||||
|
||||
namespace smithy {
|
||||
template<typename IDENTITY_T>
|
||||
class AuthScheme
|
||||
{
|
||||
public:
|
||||
using IdentityT = IDENTITY_T;
|
||||
|
||||
template<std::size_t N>
|
||||
AuthScheme(char const (&iSchemeId)[N])
|
||||
{
|
||||
memcpy(schemeId, iSchemeId, N);
|
||||
}
|
||||
|
||||
char schemeId[32];
|
||||
|
||||
virtual ~AuthScheme() = default;
|
||||
|
||||
virtual std::shared_ptr<IdentityResolverBase<IdentityT>> identityResolver() = 0;
|
||||
|
||||
virtual std::shared_ptr<AwsSignerBase<IdentityT>> signer() = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/crt/Variant.h>
|
||||
|
||||
#include <aws/core/utils/DateTime.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
#include <aws/core/endpoint/EndpointParameter.h>
|
||||
|
||||
namespace smithy {
|
||||
/* AuthSchemeOption and AuthSchemeOptionResolver */
|
||||
class AuthSchemeOption
|
||||
{
|
||||
using PropertyBag = Aws::UnorderedMap<Aws::String, Aws::Crt::Variant<Aws::String, bool>>;
|
||||
using EndpointParameters = Aws::Vector<Aws::Endpoint::EndpointParameter>;
|
||||
/* note: AuthSchemeOption is not connected with AuthScheme by type system, only by the String of schemeId, this is in accordance with SRA */
|
||||
public:
|
||||
AuthSchemeOption(const char* id = nullptr): schemeId(id) {}
|
||||
virtual ~AuthSchemeOption() = default;
|
||||
|
||||
const char* schemeId = nullptr;
|
||||
|
||||
PropertyBag virtual identityProperties() const { return PropertyBag{}; };
|
||||
PropertyBag virtual signerProperties() const { return PropertyBag{}; };
|
||||
EndpointParameters virtual endpointParameters() const { return EndpointParameters{}; };
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/auth/AuthSchemeOption.h>
|
||||
#include <smithy/identity/signer/AwsSignerBase.h>
|
||||
|
||||
#include <aws/crt/Variant.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
|
||||
namespace smithy {
|
||||
/**
|
||||
* A base interface for code-generated interfaces for passing in the data required for determining the
|
||||
* authentication scheme. By default, this only includes the operation name.
|
||||
*/
|
||||
class DefaultAuthSchemeResolverParameters
|
||||
{
|
||||
public:
|
||||
Aws::String serviceName;
|
||||
Aws::String operation;
|
||||
Aws::Crt::Optional<Aws::String> region;
|
||||
|
||||
Aws::UnorderedMap<Aws::String, Aws::Crt::Variant<Aws::String,
|
||||
bool,
|
||||
Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy,
|
||||
Aws::Auth::AWSSigningAlgorithm > > additionalProperties;
|
||||
|
||||
};
|
||||
|
||||
template<typename ServiceAuthSchemeParametersT = DefaultAuthSchemeResolverParameters>
|
||||
class AuthSchemeResolverBase
|
||||
{
|
||||
public:
|
||||
using ServiceAuthSchemeParameters = ServiceAuthSchemeParametersT;
|
||||
|
||||
virtual ~AuthSchemeResolverBase() = default;
|
||||
// AuthScheme Resolver returns a list of AuthSchemeOptions for some reason, according to the SRA...
|
||||
virtual Aws::Vector<AuthSchemeOption> resolveAuthScheme(const ServiceAuthSchemeParameters& identityProperties) = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/auth/AuthScheme.h>
|
||||
#include <smithy/identity/auth/built-in/BearerTokenAuthSchemeOption.h>
|
||||
#include <smithy/identity/identity/AwsBearerTokenIdentityBase.h>
|
||||
#include <smithy/identity/resolver/AwsBearerTokenIdentityResolver.h>
|
||||
#include <smithy/identity/signer/built-in/BearerTokenSigner.h>
|
||||
namespace smithy
|
||||
{
|
||||
class BearerTokenAuthScheme : public AuthScheme<AwsBearerTokenIdentityBase>
|
||||
{
|
||||
public:
|
||||
using AwsCredentialIdentityResolverT = IdentityResolverBase<IdentityT>;
|
||||
using AwsCredentialSignerT = AwsSignerBase<IdentityT>;
|
||||
using BearerTokenAuthSchemeParameters = DefaultAuthSchemeResolverParameters;
|
||||
|
||||
// This allows to override the identity resolver
|
||||
explicit BearerTokenAuthScheme(
|
||||
std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver,
|
||||
const Aws::String &serviceName, const Aws::String ®ion)
|
||||
: AuthScheme("smithy.api#HTTPBearerAuth"),
|
||||
m_identityResolver{identityResolver},
|
||||
m_signer{Aws::MakeShared<smithy::BearerTokenSigner>(
|
||||
"BearerTokenAuthScheme", serviceName, region)}
|
||||
{
|
||||
assert(m_identityResolver);
|
||||
assert(m_signer);
|
||||
}
|
||||
|
||||
explicit BearerTokenAuthScheme(const Aws::String &serviceName,
|
||||
const Aws::String ®ion)
|
||||
: BearerTokenAuthScheme(
|
||||
Aws::MakeShared<DefaultAwsBearerTokenIdentityResolver>(
|
||||
"BearerTokenAuthScheme"),
|
||||
serviceName, region)
|
||||
{
|
||||
assert(m_identityResolver);
|
||||
|
||||
assert(m_signer);
|
||||
}
|
||||
|
||||
virtual ~BearerTokenAuthScheme() = default;
|
||||
|
||||
std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver() override
|
||||
{
|
||||
return m_identityResolver;
|
||||
}
|
||||
|
||||
std::shared_ptr<AwsCredentialSignerT> signer() override { return m_signer; }
|
||||
|
||||
protected:
|
||||
std::shared_ptr<AwsCredentialIdentityResolverT> m_identityResolver;
|
||||
std::shared_ptr<AwsCredentialSignerT> m_signer;
|
||||
};
|
||||
} // namespace smithy
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/auth/AuthSchemeOption.h>
|
||||
namespace smithy
|
||||
{
|
||||
struct BearerTokenAuthSchemeOption
|
||||
{
|
||||
static AuthSchemeOption bearerTokenAuthSchemeOption;
|
||||
};
|
||||
|
||||
AuthSchemeOption BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption =
|
||||
AuthSchemeOption("smithy.api#HTTPBearerAuth");
|
||||
} // namespace smithy
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/auth/AuthSchemeResolverBase.h>
|
||||
#include <smithy/identity/auth/built-in/BearerTokenAuthSchemeOption.h>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
template <typename ServiceAuthSchemeParametersT =
|
||||
DefaultAuthSchemeResolverParameters>
|
||||
class BearerTokenAuthSchemeResolver
|
||||
: public AuthSchemeResolverBase<ServiceAuthSchemeParametersT>
|
||||
{
|
||||
public:
|
||||
using ServiceAuthSchemeParameters = ServiceAuthSchemeParametersT;
|
||||
virtual ~BearerTokenAuthSchemeResolver() = default;
|
||||
|
||||
Aws::Vector<AuthSchemeOption> resolveAuthScheme(
|
||||
const ServiceAuthSchemeParameters &identityProperties) override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(identityProperties);
|
||||
return {BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption};
|
||||
}
|
||||
};
|
||||
} // namespace smithy
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/auth/AuthScheme.h>
|
||||
#include <smithy/identity/auth/built-in/SigV4AuthSchemeOption.h>
|
||||
|
||||
#include <smithy/identity/resolver/built-in/DefaultAwsCredentialIdentityResolver.h>
|
||||
|
||||
#include <smithy/identity/identity/AwsCredentialIdentityBase.h>
|
||||
#include <smithy/identity/signer/built-in/SigV4Signer.h>
|
||||
#include <smithy/identity/auth/built-in/SigV4AuthScheme.h>
|
||||
|
||||
|
||||
namespace smithy {
|
||||
constexpr char SIGV4[] = "aws.auth#sigv4";
|
||||
|
||||
class SigV4AuthScheme : public AuthScheme<AwsCredentialIdentityBase>
|
||||
{
|
||||
public:
|
||||
using AwsCredentialIdentityResolverT = IdentityResolverBase<IdentityT>;
|
||||
using AwsCredentialSignerT = AwsSignerBase<IdentityT>;
|
||||
using SigV4AuthSchemeParameters = DefaultAuthSchemeResolverParameters;
|
||||
|
||||
//This allows to override the identity resolver
|
||||
explicit SigV4AuthScheme(std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver,
|
||||
const Aws::String& serviceName,
|
||||
const Aws::String& region)
|
||||
: AuthScheme(SIGV4),
|
||||
m_identityResolver{identityResolver},
|
||||
m_signer{Aws::MakeShared<AwsSigV4Signer>("SigV4AuthScheme", serviceName, region)}
|
||||
{
|
||||
assert(m_identityResolver);
|
||||
assert(m_signer);
|
||||
}
|
||||
|
||||
//delegate constructor
|
||||
explicit SigV4AuthScheme(const Aws::String& serviceName,
|
||||
const Aws::String& region)
|
||||
: SigV4AuthScheme(Aws::MakeShared<DefaultAwsCredentialIdentityResolver>("SigV4AuthScheme"),
|
||||
serviceName,
|
||||
region)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~SigV4AuthScheme() = default;
|
||||
|
||||
std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver() override
|
||||
{
|
||||
return m_identityResolver;
|
||||
}
|
||||
|
||||
std::shared_ptr<AwsCredentialSignerT> signer() override
|
||||
{
|
||||
return m_signer;
|
||||
}
|
||||
protected:
|
||||
std::shared_ptr<AwsCredentialIdentityResolverT> m_identityResolver;
|
||||
std::shared_ptr<AwsCredentialSignerT> m_signer;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
#include <smithy/identity/auth/AuthSchemeOption.h>
|
||||
|
||||
namespace smithy {
|
||||
struct SigV4AuthSchemeOption
|
||||
{
|
||||
static SMITHY_API AuthSchemeOption sigV4AuthSchemeOption;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/auth/AuthSchemeResolverBase.h>
|
||||
#include <smithy/identity/auth/built-in/SigV4AuthSchemeOption.h>
|
||||
|
||||
|
||||
namespace smithy {
|
||||
template<typename ServiceAuthSchemeParametersT = DefaultAuthSchemeResolverParameters>
|
||||
class SigV4AuthSchemeResolver : public AuthSchemeResolverBase<ServiceAuthSchemeParametersT>
|
||||
{
|
||||
public:
|
||||
using ServiceAuthSchemeParameters = ServiceAuthSchemeParametersT;
|
||||
virtual ~SigV4AuthSchemeResolver() = default;
|
||||
|
||||
Aws::Vector<AuthSchemeOption> resolveAuthScheme(const ServiceAuthSchemeParameters& identityProperties) override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(identityProperties);
|
||||
return {SigV4AuthSchemeOption::sigV4AuthSchemeOption};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/auth/AuthScheme.h>
|
||||
#include <smithy/identity/auth/built-in/SigV4aAuthSchemeOption.h>
|
||||
|
||||
#include <smithy/identity/resolver/built-in/DefaultAwsCredentialIdentityResolver.h>
|
||||
|
||||
#include <smithy/identity/identity/AwsCredentialIdentityBase.h>
|
||||
#include <smithy/identity/signer/built-in/SigV4aSigner.h>
|
||||
|
||||
|
||||
namespace smithy {
|
||||
constexpr char SIGV4A[] = "aws.auth#sigv4a";
|
||||
|
||||
|
||||
class SigV4aAuthScheme : public AuthScheme<AwsCredentialIdentityBase>
|
||||
{
|
||||
public:
|
||||
using AwsCredentialIdentityResolverT = IdentityResolverBase<IdentityT>;
|
||||
using AwsCredentialSignerT = AwsSignerBase<IdentityT>;
|
||||
using SigV4aAuthSchemeParameters = DefaultAuthSchemeResolverParameters;
|
||||
|
||||
//This allows to override the identity resolver
|
||||
explicit SigV4aAuthScheme(std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver,
|
||||
const Aws::String& serviceName,
|
||||
const Aws::String& region)
|
||||
: AuthScheme(SIGV4A),
|
||||
m_identityResolver{identityResolver},
|
||||
m_signer{Aws::MakeShared<AwsSigV4aSigner>("SigV4aAuthScheme", serviceName, region)}
|
||||
{
|
||||
assert(m_identityResolver);
|
||||
assert(m_signer);
|
||||
}
|
||||
|
||||
explicit SigV4aAuthScheme(const Aws::String& serviceName,
|
||||
const Aws::String& region)
|
||||
: SigV4aAuthScheme(Aws::MakeShared<DefaultAwsCredentialIdentityResolver>("SigV4aAuthScheme"), serviceName, region)
|
||||
{
|
||||
assert(m_identityResolver);
|
||||
|
||||
assert(m_signer);
|
||||
}
|
||||
|
||||
virtual ~SigV4aAuthScheme() = default;
|
||||
|
||||
std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver() override
|
||||
{
|
||||
return m_identityResolver;
|
||||
}
|
||||
|
||||
std::shared_ptr<AwsCredentialSignerT> signer() override
|
||||
{
|
||||
return m_signer;
|
||||
}
|
||||
protected:
|
||||
std::shared_ptr<AwsCredentialIdentityResolverT> m_identityResolver;
|
||||
std::shared_ptr<AwsCredentialSignerT> m_signer;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
#include <smithy/identity/auth/AuthSchemeOption.h>
|
||||
|
||||
namespace smithy {
|
||||
struct SigV4aAuthSchemeOption
|
||||
{
|
||||
static SMITHY_API AuthSchemeOption sigV4aAuthSchemeOption;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/auth/AuthSchemeResolverBase.h>
|
||||
#include <smithy/identity/auth/built-in/SigV4aAuthSchemeOption.h>
|
||||
|
||||
|
||||
namespace smithy {
|
||||
template<typename ServiceAuthSchemeParametersT = DefaultAuthSchemeResolverParameters>
|
||||
class SigV4aAuthSchemeResolver : public AuthSchemeResolverBase<ServiceAuthSchemeParametersT>
|
||||
{
|
||||
public:
|
||||
using ServiceAuthSchemeParameters = ServiceAuthSchemeParametersT;
|
||||
virtual ~SigV4aAuthSchemeResolver() = default;
|
||||
|
||||
Aws::Vector<AuthSchemeOption> resolveAuthScheme(const ServiceAuthSchemeParameters& identityProperties) override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(identityProperties);
|
||||
return {SigV4aAuthSchemeOption::sigV4aAuthSchemeOption};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/identity/AwsBearerTokenIdentityBase.h>
|
||||
|
||||
namespace smithy {
|
||||
class AwsBearerTokenIdentity : public AwsBearerTokenIdentityBase {
|
||||
public:
|
||||
virtual const Aws::String &token() const override;
|
||||
|
||||
virtual Aws::Crt::Optional<AwsIdentity::DateTime>
|
||||
expiration() const override;
|
||||
|
||||
Aws::String &token() { return m_token; }
|
||||
|
||||
Aws::Crt::Optional<AwsIdentity::DateTime> &expiration()
|
||||
{
|
||||
return m_expiration;
|
||||
}
|
||||
|
||||
protected:
|
||||
Aws::String m_token;
|
||||
Aws::Crt::Optional<AwsIdentity::DateTime> m_expiration;
|
||||
};
|
||||
}
|
||||
|
||||
#include <smithy/identity/identity/impl/AwsBearerTokenIdentityImpl.h>
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/identity/AwsIdentity.h>
|
||||
|
||||
namespace smithy {
|
||||
class AwsBearerTokenIdentityBase : public AwsIdentity {
|
||||
public:
|
||||
virtual const Aws::String &token() const = 0;
|
||||
|
||||
virtual Aws::Crt::Optional<AwsIdentity::DateTime>
|
||||
expiration() const override = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/identity/AwsCredentialIdentityBase.h>
|
||||
|
||||
namespace smithy {
|
||||
class AwsCredentialIdentity : public AwsCredentialIdentityBase {
|
||||
public:
|
||||
AwsCredentialIdentity(const Aws::String& accessKeyId,
|
||||
const Aws::String& secretAccessKey,
|
||||
const Aws::Crt::Optional<Aws::String>& sessionToken,
|
||||
const Aws::Crt::Optional<AwsIdentity::DateTime>& expiration)
|
||||
: m_accessKeyId(accessKeyId), m_secretAccessKey(secretAccessKey),
|
||||
m_sessionToken(sessionToken), m_expiration(expiration) {}
|
||||
|
||||
Aws::String accessKeyId() const override;
|
||||
Aws::String secretAccessKey() const override;
|
||||
Aws::Crt::Optional<Aws::String> sessionToken() const override;
|
||||
Aws::Crt::Optional<AwsIdentity::DateTime> expiration() const override;
|
||||
|
||||
protected:
|
||||
Aws::String m_accessKeyId;
|
||||
Aws::String m_secretAccessKey;
|
||||
Aws::Crt::Optional<Aws::String> m_sessionToken;
|
||||
Aws::Crt::Optional<AwsIdentity::DateTime> m_expiration;
|
||||
};
|
||||
}
|
||||
|
||||
#include <smithy/identity/identity/impl/AwsCredentialIdentityImpl.h>
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/identity/AwsIdentity.h>
|
||||
|
||||
namespace smithy {
|
||||
class AwsCredentialIdentityBase : public AwsIdentity {
|
||||
public:
|
||||
virtual Aws::String accessKeyId() const = 0;
|
||||
virtual Aws::String secretAccessKey() const = 0;
|
||||
virtual Aws::Crt::Optional<Aws::String> sessionToken() const = 0;
|
||||
virtual Aws::Crt::Optional<AwsIdentity::DateTime> expiration() const override = 0 ;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/crt/Optional.h>
|
||||
|
||||
#include <aws/core/utils/DateTime.h>
|
||||
|
||||
namespace smithy {
|
||||
class AwsIdentity {
|
||||
public:
|
||||
using DateTime = Aws::Utils::DateTime;
|
||||
|
||||
virtual ~AwsIdentity(){};
|
||||
virtual Aws::Crt::Optional<DateTime> expiration() const {
|
||||
return Aws::Crt::Optional<DateTime>();
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/identity/AwsBearerTokenIdentity.h>
|
||||
|
||||
namespace smithy {
|
||||
const Aws::String &AwsBearerTokenIdentity::token() const { return m_token; }
|
||||
|
||||
Aws::Crt::Optional<AwsIdentity::DateTime>
|
||||
AwsBearerTokenIdentity::expiration() const
|
||||
{
|
||||
return m_expiration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/identity/AwsCredentialIdentity.h>
|
||||
|
||||
namespace smithy {
|
||||
inline Aws::String AwsCredentialIdentity::accessKeyId() const {
|
||||
return m_accessKeyId;
|
||||
}
|
||||
|
||||
inline Aws::String AwsCredentialIdentity::secretAccessKey() const {
|
||||
return m_secretAccessKey;
|
||||
}
|
||||
|
||||
inline Aws::Crt::Optional<Aws::String> AwsCredentialIdentity::sessionToken() const {
|
||||
return m_sessionToken;
|
||||
}
|
||||
|
||||
inline Aws::Crt::Optional<AwsIdentity::DateTime> AwsCredentialIdentity::expiration() const {
|
||||
return m_expiration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/auth/bearer-token-provider/AWSBearerTokenProviderBase.h>
|
||||
#include <aws/core/auth/bearer-token-provider/SSOBearerTokenProvider.h>
|
||||
#include <smithy/identity/identity/AwsBearerTokenIdentity.h>
|
||||
#include <smithy/identity/resolver/AwsIdentityResolverBase.h>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
|
||||
class AwsBearerTokenIdentityResolver
|
||||
: public IdentityResolverBase<AwsBearerTokenIdentityBase>
|
||||
{
|
||||
public:
|
||||
static const char BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG[];
|
||||
|
||||
using IdentityT = AwsBearerTokenIdentity;
|
||||
virtual ~AwsBearerTokenIdentityResolver() = default;
|
||||
|
||||
AwsBearerTokenIdentityResolver() = default;
|
||||
|
||||
AwsBearerTokenIdentityResolver(
|
||||
const Aws::Vector<
|
||||
std::shared_ptr<Aws::Auth::AWSBearerTokenProviderBase>>
|
||||
&providerChain)
|
||||
: m_providerChainLegacy{providerChain}
|
||||
{
|
||||
}
|
||||
|
||||
ResolveIdentityFutureOutcome
|
||||
getIdentity(const IdentityProperties &identityProperties,
|
||||
const AdditionalParameters &additionalParameters) override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(identityProperties);
|
||||
AWS_UNREFERENCED_PARAM(additionalParameters);
|
||||
for (auto &bearerTokenProvider : m_providerChainLegacy)
|
||||
{
|
||||
if (!bearerTokenProvider)
|
||||
{
|
||||
AWS_LOGSTREAM_FATAL(
|
||||
BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG,
|
||||
"Unexpected nullptr in "
|
||||
"DefaultBearerTokenProviderChain::m_providerChain");
|
||||
return Aws::Client::AWSError<Aws::Client::CoreErrors>(
|
||||
Aws::Client::CoreErrors::INVALID_PARAMETER_VALUE, "",
|
||||
"Unexpected nullptr in "
|
||||
"BearerTokenProviderChain::m_providerChain",
|
||||
false);
|
||||
}
|
||||
auto bearerToken = bearerTokenProvider->GetAWSBearerToken();
|
||||
if (!bearerToken.IsExpiredOrEmpty())
|
||||
{
|
||||
auto outcomePtr = Aws::MakeUnique<AwsBearerTokenIdentity>(
|
||||
BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG);
|
||||
outcomePtr->token() = bearerToken.GetToken();
|
||||
outcomePtr->expiration() = bearerToken.GetExpiration();
|
||||
return ResolveIdentityFutureOutcome(std::move(outcomePtr));
|
||||
}
|
||||
}
|
||||
|
||||
return Aws::Client::AWSError<Aws::Client::CoreErrors>(
|
||||
Aws::Client::CoreErrors::NOT_INITIALIZED, "",
|
||||
"No bearer token provider in chain found", false);
|
||||
}
|
||||
|
||||
void AddBearerTokenProvider(
|
||||
std::shared_ptr<Aws::Auth::AWSBearerTokenProviderBase> provider)
|
||||
{
|
||||
m_providerChainLegacy.emplace_back(std::move(provider));
|
||||
}
|
||||
|
||||
protected:
|
||||
Aws::Vector<std::shared_ptr<Aws::Auth::AWSBearerTokenProviderBase>>
|
||||
m_providerChainLegacy;
|
||||
};
|
||||
|
||||
class DefaultAwsBearerTokenIdentityResolver
|
||||
: public AwsBearerTokenIdentityResolver
|
||||
{
|
||||
public:
|
||||
using IdentityT = AwsBearerTokenIdentity;
|
||||
virtual ~DefaultAwsBearerTokenIdentityResolver() = default;
|
||||
|
||||
DefaultAwsBearerTokenIdentityResolver()
|
||||
: AwsBearerTokenIdentityResolver(
|
||||
{Aws::MakeShared<Aws::Auth::SSOBearerTokenProvider>(
|
||||
"SSOBearerTokenProvider")}){};
|
||||
};
|
||||
const char
|
||||
AwsBearerTokenIdentityResolver::BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG[] =
|
||||
"BearerTokenProvider";
|
||||
|
||||
} // namespace smithy
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/resolver/AwsIdentityResolverBase.h>
|
||||
|
||||
#include <smithy/identity/identity/AwsCredentialIdentity.h>
|
||||
|
||||
namespace smithy {
|
||||
class AwsCredentialIdentityResolver : public IdentityResolverBase<AwsCredentialIdentityBase> {
|
||||
public:
|
||||
using IdentityT = AwsCredentialIdentity;
|
||||
virtual ~AwsCredentialIdentityResolver() = default;
|
||||
|
||||
ResolveIdentityFutureOutcome getIdentity(const IdentityProperties& identityProperties, const AdditionalParameters& additionalParameters) override = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/crt/Optional.h>
|
||||
#include <aws/crt/Variant.h>
|
||||
|
||||
#include <aws/core/client/CoreErrors.h>
|
||||
#include <aws/core/utils/FutureOutcome.h>
|
||||
|
||||
#include <aws/core/utils/memory/stl/AWSString.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
|
||||
#include <aws/core/utils/DateTime.h>
|
||||
|
||||
namespace smithy {
|
||||
template<typename IDENTITY_T>
|
||||
class IdentityResolverBase {
|
||||
public:
|
||||
using IdentityT = IDENTITY_T;
|
||||
|
||||
virtual ~IdentityResolverBase(){};
|
||||
|
||||
using IdentityProperties = Aws::UnorderedMap<Aws::String, Aws::Crt::Variant<Aws::String, bool>>;
|
||||
// IdentityResolvers are asynchronous.
|
||||
using ResolveIdentityFutureOutcome = Aws::Utils::FutureOutcome<Aws::UniquePtr<IdentityT>, Aws::Client::AWSError<Aws::Client::CoreErrors>>;
|
||||
using AdditionalParameters = Aws::UnorderedMap<Aws::String, Aws::Crt::Variant<Aws::String, bool>>;
|
||||
|
||||
// Each Identity has one or more identity resolvers that are able to load the customer’s
|
||||
// Identity. An identity resolver might load the identity from a remote service (e.g. STS), a local
|
||||
// service (e.g. IMDS), local disk (e.g. a configuration file) or local memory (e.g. environment variables).
|
||||
virtual ResolveIdentityFutureOutcome getIdentity(const IdentityProperties& identityProperties, const AdditionalParameters& additionalParameters) = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/resolver/AwsCredentialIdentityResolver.h>
|
||||
|
||||
#include <aws/core/auth/AWSCredentials.h>
|
||||
#include <aws/core/auth/AWSCredentialsProviderChain.h>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
class AwsCredentialsProviderIdentityResolver : public AwsCredentialIdentityResolver
|
||||
{
|
||||
public:
|
||||
using SigV4AuthSchemeParameters = DefaultAuthSchemeResolverParameters;
|
||||
|
||||
explicit AwsCredentialsProviderIdentityResolver(const std::shared_ptr<Aws::Auth::AWSCredentialsProvider> credentialsProvider)
|
||||
: m_credentialsProvider(credentialsProvider)
|
||||
{
|
||||
}
|
||||
|
||||
AwsCredentialsProviderIdentityResolver(const AwsCredentialsProviderIdentityResolver& other) = delete;
|
||||
AwsCredentialsProviderIdentityResolver(AwsCredentialsProviderIdentityResolver&& other) noexcept = default;
|
||||
AwsCredentialsProviderIdentityResolver& operator=(const AwsCredentialsProviderIdentityResolver& other) = delete;
|
||||
AwsCredentialsProviderIdentityResolver& operator=(AwsCredentialsProviderIdentityResolver&& other) noexcept = default;
|
||||
~AwsCredentialsProviderIdentityResolver() override = default;
|
||||
|
||||
ResolveIdentityFutureOutcome getIdentity(const IdentityProperties& identityProperties,
|
||||
const AdditionalParameters& additionalParameters) override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(identityProperties);
|
||||
AWS_UNREFERENCED_PARAM(additionalParameters);
|
||||
|
||||
const auto fetchedCreds = m_credentialsProvider->GetAWSCredentials();
|
||||
|
||||
auto smithyCreds = Aws::MakeUnique<AwsCredentialIdentity>("DefaultAwsCredentialIdentityResolver",
|
||||
fetchedCreds.GetAWSAccessKeyId(), fetchedCreds.GetAWSSecretKey(),
|
||||
fetchedCreds.GetSessionToken(), fetchedCreds.GetExpiration());
|
||||
|
||||
return {std::move(smithyCreds)};
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Aws::Auth::AWSCredentialsProvider> m_credentialsProvider;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/resolver/AwsCredentialIdentityResolver.h>
|
||||
|
||||
#include <aws/core/auth/AWSCredentials.h>
|
||||
#include <aws/core/auth/AWSCredentialsProviderChain.h>
|
||||
|
||||
namespace smithy {
|
||||
constexpr char ALLOC_ID[] = "DefaultAwsCredentialIdentityResolver";
|
||||
/**
|
||||
* A smithy SigV4 AWS Credentials resolver wrapper on top of legacy SDK Credentials provider
|
||||
* TODO: refactor into own signer using smithy design
|
||||
*/
|
||||
class DefaultAwsCredentialIdentityResolver : public AwsCredentialIdentityResolver {
|
||||
protected:
|
||||
|
||||
mutable std::shared_ptr<Aws::Auth::AWSCredentialsProviderChain> legacyChain_sp;
|
||||
|
||||
public:
|
||||
using SigV4AuthSchemeParameters = DefaultAuthSchemeResolverParameters;
|
||||
|
||||
DefaultAwsCredentialIdentityResolver(): legacyChain_sp{Aws::MakeShared<Aws::Auth::DefaultAWSCredentialsProviderChain>(ALLOC_ID)}{
|
||||
|
||||
};
|
||||
|
||||
DefaultAwsCredentialIdentityResolver(const DefaultAwsCredentialIdentityResolver& other) = delete;
|
||||
DefaultAwsCredentialIdentityResolver(DefaultAwsCredentialIdentityResolver&& other) noexcept = default;
|
||||
DefaultAwsCredentialIdentityResolver& operator=(const DefaultAwsCredentialIdentityResolver& other) = delete;
|
||||
DefaultAwsCredentialIdentityResolver& operator=(DefaultAwsCredentialIdentityResolver&& other) noexcept = default;
|
||||
virtual ~DefaultAwsCredentialIdentityResolver() = default;
|
||||
|
||||
DefaultAwsCredentialIdentityResolver(std::shared_ptr<Aws::Auth::AWSCredentialsProviderChain> providerChain): legacyChain_sp{providerChain}
|
||||
{
|
||||
assert(legacyChain_sp);
|
||||
};
|
||||
|
||||
ResolveIdentityFutureOutcome getIdentity(const IdentityProperties& identityProperties, const AdditionalParameters& additionalParameters) override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(identityProperties);
|
||||
AWS_UNREFERENCED_PARAM(additionalParameters);
|
||||
|
||||
auto legacyCreds = legacyChain_sp->GetAWSCredentials();
|
||||
|
||||
auto smithyCreds = Aws::MakeUnique<AwsCredentialIdentity>("DefaultAwsCredentialIdentityResolver",
|
||||
legacyCreds.GetAWSAccessKeyId(),
|
||||
legacyCreds.GetAWSSecretKey(),
|
||||
legacyCreds.GetSessionToken().empty()? Aws::Crt::Optional<Aws::String>() : legacyCreds.GetSessionToken(),
|
||||
legacyCreds.GetExpiration());
|
||||
|
||||
return ResolveIdentityFutureOutcome(std::move(smithyCreds));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/resolver/AwsCredentialIdentityResolver.h>
|
||||
|
||||
#include <aws/core/auth/AWSCredentials.h>
|
||||
#include <aws/core/auth/AWSCredentialsProviderChain.h>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
class SimpleAwsCredentialIdentityResolver : public AwsCredentialIdentityResolver
|
||||
{
|
||||
public:
|
||||
using SigV4AuthSchemeParameters = DefaultAuthSchemeResolverParameters;
|
||||
|
||||
explicit SimpleAwsCredentialIdentityResolver(const Aws::Auth::AWSCredentials& credentials)
|
||||
: m_credentials(credentials)
|
||||
{
|
||||
}
|
||||
|
||||
SimpleAwsCredentialIdentityResolver(const SimpleAwsCredentialIdentityResolver& other) = delete;
|
||||
SimpleAwsCredentialIdentityResolver(SimpleAwsCredentialIdentityResolver&& other) noexcept = default;
|
||||
SimpleAwsCredentialIdentityResolver& operator=(const SimpleAwsCredentialIdentityResolver& other) = delete;
|
||||
SimpleAwsCredentialIdentityResolver& operator=(SimpleAwsCredentialIdentityResolver&& other) noexcept = default;
|
||||
virtual ~SimpleAwsCredentialIdentityResolver() = default;
|
||||
|
||||
ResolveIdentityFutureOutcome getIdentity(const IdentityProperties& identityProperties,
|
||||
const AdditionalParameters& additionalParameters) override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(identityProperties);
|
||||
AWS_UNREFERENCED_PARAM(additionalParameters);
|
||||
|
||||
auto smithyCreds = Aws::MakeUnique<AwsCredentialIdentity>("DefaultAwsCredentialIdentityResolver",
|
||||
m_credentials.GetAWSAccessKeyId(), m_credentials.GetAWSSecretKey(),
|
||||
m_credentials.GetSessionToken(), m_credentials.GetExpiration());
|
||||
|
||||
return {std::move(smithyCreds)};
|
||||
}
|
||||
|
||||
protected:
|
||||
Aws::Auth::AWSCredentials m_credentials;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <smithy/identity/identity/AwsIdentity.h>
|
||||
|
||||
#include <aws/crt/Variant.h>
|
||||
#include <aws/core/client/AWSError.h>
|
||||
#include <aws/core/http/HttpRequest.h>
|
||||
#include <aws/core/utils/FutureOutcome.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
|
||||
|
||||
namespace smithy {
|
||||
class AwsSignerCommon {
|
||||
public:
|
||||
virtual ~AwsSignerCommon() = default;
|
||||
/**
|
||||
* This handles detection of clock skew between clients and the server and adjusts the clock so that the next request will not
|
||||
* fail on the timestamp check.
|
||||
*/
|
||||
virtual void SetClockSkew(const std::chrono::milliseconds& clockSkew) { m_clockSkew = clockSkew; }
|
||||
/**
|
||||
* Gets the timestamp being used by the signer. This may include a clock skew if a clock skew has been detected.
|
||||
*/
|
||||
virtual Aws::Utils::DateTime GetSigningTimestamp() const { return Aws::Utils::DateTime::Now() + GetClockSkewOffset(); }
|
||||
|
||||
protected:
|
||||
virtual std::chrono::milliseconds GetClockSkewOffset() const { return m_clockSkew.load(); }
|
||||
std::atomic<std::chrono::milliseconds> m_clockSkew = {};
|
||||
};
|
||||
|
||||
template<typename IDENTITY_T>
|
||||
class AwsSignerBase : public AwsSignerCommon {
|
||||
public:
|
||||
using IdentityT = IDENTITY_T;
|
||||
static_assert(std::is_base_of<AwsIdentity, IDENTITY_T>::value, "Identity type should inherit AwsIdentity");
|
||||
using SigningProperties = Aws::UnorderedMap<Aws::String, Aws::Crt::Variant<Aws::String, bool>>;
|
||||
using AdditionalParameters = Aws::UnorderedMap<Aws::String, Aws::Crt::Variant<Aws::String, bool>>;
|
||||
using HttpRequest = Aws::Http::HttpRequest;
|
||||
using SigningError = Aws::Client::AWSError<Aws::Client::CoreErrors>;
|
||||
using SigningFutureOutcome = Aws::Utils::FutureOutcome<std::shared_ptr<HttpRequest>, SigningError>;
|
||||
|
||||
// signer may copy the original httpRequest or create a new one
|
||||
virtual SigningFutureOutcome sign(std::shared_ptr<HttpRequest> httpRequest, const IdentityT& identity, SigningProperties properties) = 0;
|
||||
|
||||
virtual ~AwsSignerBase() {};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/identity/AwsBearerTokenIdentityBase.h>
|
||||
#include <smithy/identity/signer/AwsSignerBase.h>
|
||||
|
||||
#include <aws/core/auth/signer/AWSAuthSignerHelper.h>
|
||||
#include <aws/core/http/HttpRequest.h>
|
||||
#include <aws/crt/http/HttpConnection.h>
|
||||
#include <aws/crt/http/HttpRequestResponse.h>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
static const char AUTHORIZATION_HEADER[] = "authorization";
|
||||
|
||||
class BearerTokenSigner : public AwsSignerBase<AwsBearerTokenIdentityBase>
|
||||
{
|
||||
|
||||
public:
|
||||
static const char LOGGING_TAG[];
|
||||
|
||||
using BearerTokenAuthSchemeParameters =
|
||||
smithy::DefaultAuthSchemeResolverParameters;
|
||||
explicit BearerTokenSigner(const Aws::String &serviceName,
|
||||
const Aws::String ®ion)
|
||||
: m_serviceName(serviceName), m_region(region)
|
||||
{
|
||||
}
|
||||
|
||||
SigningFutureOutcome
|
||||
sign(std::shared_ptr<HttpRequest> httpRequest,
|
||||
const smithy::AwsBearerTokenIdentityBase &identity,
|
||||
SigningProperties properties) override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(properties);
|
||||
|
||||
if (Aws::Http::Scheme::HTTPS != httpRequest->GetUri().GetScheme())
|
||||
{
|
||||
// Clients MUST always use TLS (https) or equivalent transport
|
||||
// security when making requests with bearer tokens.
|
||||
// https://datatracker.ietf.org/doc/html/rfc6750
|
||||
AWS_LOGSTREAM_ERROR(
|
||||
LOGGING_TAG,
|
||||
"HTTPS scheme must be used with a bearer token authorization");
|
||||
return SigningError(
|
||||
Aws::Client::CoreErrors::INVALID_PARAMETER_VALUE, "",
|
||||
"Failed to sign the request with bearer", false);
|
||||
}
|
||||
|
||||
httpRequest->SetHeaderValue(AUTHORIZATION_HEADER,
|
||||
"Bearer " + identity.token());
|
||||
|
||||
return SigningFutureOutcome(std::move(httpRequest));
|
||||
}
|
||||
|
||||
virtual ~BearerTokenSigner(){};
|
||||
|
||||
protected:
|
||||
Aws::String m_serviceName;
|
||||
Aws::String m_region;
|
||||
};
|
||||
|
||||
const char BearerTokenSigner::LOGGING_TAG[] = "BearerTokenSigner";
|
||||
} // namespace smithy
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/signer/AwsSignerBase.h>
|
||||
#include <smithy/identity/identity/AwsCredentialIdentityBase.h>
|
||||
|
||||
#include <aws/core/auth/signer/AWSAuthV4Signer.h>
|
||||
|
||||
#include <aws/core/auth/AWSCredentials.h>
|
||||
|
||||
namespace smithy {
|
||||
/**
|
||||
* A smithy SigV4 signer wrapper on top of legacy SDK SigV4 signer
|
||||
* TODO: refactor into own signer using smithy design
|
||||
*/
|
||||
class AwsSigV4Signer : public AwsSignerBase<AwsCredentialIdentityBase> {
|
||||
|
||||
public:
|
||||
using SigV4AuthSchemeParameters = DefaultAuthSchemeResolverParameters;
|
||||
explicit AwsSigV4Signer(const Aws::String& serviceName, const Aws::String& region)
|
||||
: m_serviceName(serviceName),
|
||||
m_region(region),
|
||||
legacySigner(nullptr, serviceName.c_str(), region, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Always)
|
||||
{
|
||||
}
|
||||
|
||||
SigningFutureOutcome sign(std::shared_ptr<HttpRequest> httpRequest, const AwsCredentialIdentityBase& identity, SigningProperties properties) override
|
||||
{
|
||||
const auto legacyCreds = [&identity]() -> Aws::Auth::AWSCredentials {
|
||||
if(identity.sessionToken().has_value() && identity.expiration().has_value())
|
||||
{
|
||||
return {identity.accessKeyId(), identity.secretAccessKey(), *identity.sessionToken(), *identity.expiration()};
|
||||
}
|
||||
if(identity.sessionToken().has_value())
|
||||
{
|
||||
return {identity.accessKeyId(), identity.secretAccessKey(), *identity.sessionToken()};
|
||||
}
|
||||
return {identity.accessKeyId(), identity.secretAccessKey()};
|
||||
}();
|
||||
|
||||
|
||||
|
||||
auto signPayloadIt = properties.find("SignPayload");
|
||||
bool signPayload = signPayloadIt != properties.end() ? signPayloadIt->second.get<Aws::String>() == "true" : false;
|
||||
|
||||
assert(httpRequest);
|
||||
bool success = legacySigner.SignRequestWithCreds(*httpRequest, legacyCreds, m_region.c_str(), m_serviceName.c_str(), signPayload);
|
||||
if (success)
|
||||
{
|
||||
return SigningFutureOutcome(std::move(httpRequest));
|
||||
}
|
||||
return SigningError(Aws::Client::CoreErrors::MEMORY_ALLOCATION, "", "Failed to sign the request with sigv4", false);
|
||||
}
|
||||
|
||||
virtual ~AwsSigV4Signer() {};
|
||||
protected:
|
||||
Aws::String m_serviceName;
|
||||
Aws::String m_region;
|
||||
Aws::Client::AWSAuthV4Signer legacySigner;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <smithy/identity/signer/AwsSignerBase.h>
|
||||
#include <smithy/identity/identity/AwsCredentialIdentityBase.h>
|
||||
#include <aws/core/auth/AWSCredentials.h>
|
||||
#include <aws/crt/auth/Credentials.h>
|
||||
|
||||
#include <aws/core/http/HttpRequest.h>
|
||||
#include <aws/core/auth/signer/AWSAuthSignerHelper.h>
|
||||
#include <aws/crt/http/HttpConnection.h>
|
||||
#include <aws/crt/http/HttpRequestResponse.h>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
namespace smithy {
|
||||
static const char* UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD";
|
||||
static const char* EMPTY_STRING_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
||||
static const char v4AsymmetricLogTag[] = "AWSAuthSymmetricV4Signer";
|
||||
static const char* USER_AGENT = "user-agent";
|
||||
static const char* X_AMZN_TRACE_ID = "x-amzn-trace-id";
|
||||
|
||||
/**
|
||||
* A smithy SigV4 signer wrapper on top of legacy SDK SigV4 signer
|
||||
* TODO: refactor into own signer using smithy design
|
||||
*/
|
||||
class AwsSigV4aSigner : public AwsSignerBase<AwsCredentialIdentityBase> {
|
||||
|
||||
public:
|
||||
using SigV4aAuthSchemeParameters = smithy::DefaultAuthSchemeResolverParameters;
|
||||
explicit AwsSigV4aSigner(const Aws::String& serviceName, const Aws::String& region)
|
||||
: m_serviceName(serviceName), m_region(region)
|
||||
{
|
||||
}
|
||||
|
||||
SigningFutureOutcome sign(std::shared_ptr<HttpRequest> httpRequest, const AwsCredentialIdentityBase& identity, SigningProperties properties) override
|
||||
{
|
||||
|
||||
auto signPayloadIt = properties.find("SignPayload");
|
||||
bool signPayload = signPayloadIt != properties.end() ? signPayloadIt->second.get<Aws::String>() == "true" : false;
|
||||
|
||||
assert(httpRequest);
|
||||
assert(identity.expiration().has_value());
|
||||
|
||||
auto &request = *httpRequest;
|
||||
|
||||
auto crtCredentials = Aws::MakeShared<Aws::Crt::Auth::Credentials>(v4AsymmetricLogTag,
|
||||
Aws::Crt::ByteCursorFromCString(identity.accessKeyId().c_str()),
|
||||
Aws::Crt::ByteCursorFromCString(identity.secretAccessKey().c_str()),
|
||||
Aws::Crt::ByteCursorFromCString((*identity.sessionToken()).c_str()),
|
||||
(*identity.expiration()).Seconds());
|
||||
|
||||
Aws::Crt::Auth::AwsSigningConfig awsSigningConfig;
|
||||
|
||||
bool success = createAwsSigningConfig(crtCredentials, request, awsSigningConfig, signPayload);
|
||||
|
||||
if(!success)
|
||||
{
|
||||
AWS_LOGSTREAM_ERROR(v4AsymmetricLogTag, "Failed to get Auth configuration");
|
||||
|
||||
return SigningError(Aws::Client::CoreErrors::MEMORY_ALLOCATION, "", "Failed to get Auth configuration", false);
|
||||
}
|
||||
|
||||
std::shared_ptr<Aws::Crt::Http::HttpRequest> crtHttpRequest = request.ToCrtHttpRequest();
|
||||
|
||||
auto sigv4HttpRequestSigner = Aws::MakeShared<Aws::Crt::Auth::Sigv4HttpRequestSigner>(v4AsymmetricLogTag);
|
||||
//This is an async call, so we need to wait till we have received an outcome
|
||||
Aws::String errorMessage;
|
||||
bool processed = false;
|
||||
//producer function
|
||||
sigv4HttpRequestSigner->SignRequest(crtHttpRequest, awsSigningConfig,
|
||||
[&request, &success, &errorMessage, &processed, this](const std::shared_ptr<Aws::Crt::Http::HttpRequest>& signedCrtHttpRequest, int errorCode) {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_cv.wait(lock, [&]{ return !processed; });
|
||||
success = (errorCode == AWS_ERROR_SUCCESS);
|
||||
if (success)
|
||||
{
|
||||
if (m_signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders)
|
||||
{
|
||||
for (size_t i = 0; i < signedCrtHttpRequest->GetHeaderCount(); i++)
|
||||
{
|
||||
Aws::Crt::Optional<Aws::Crt::Http::HttpHeader> httpHeader = signedCrtHttpRequest->GetHeader(i);
|
||||
request.SetHeaderValue(Aws::String(reinterpret_cast<const char*>(httpHeader->name.ptr), httpHeader->name.len),
|
||||
Aws::String(reinterpret_cast<const char*>(httpHeader->value.ptr), httpHeader->value.len));
|
||||
}
|
||||
}
|
||||
else if (m_signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams)
|
||||
{
|
||||
Aws::Http::URI newPath(reinterpret_cast<const char*>(signedCrtHttpRequest->GetPath()->ptr));
|
||||
request.GetUri().SetQueryString(newPath.GetQueryString());
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = "No action to take when signature type is neither \"HttpRequestViaHeaders\" nor \"HttpRequestViaQueryParams\"";
|
||||
AWS_LOGSTREAM_ERROR(v4AsymmetricLogTag, errorMessage);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Aws::OStringStream errStream;
|
||||
errStream << "Encountered internal error during signing process with AWS signature version 4 (Asymmetric):" << aws_error_str(errorCode);
|
||||
errorMessage = errStream.str();
|
||||
AWS_LOGSTREAM_ERROR(v4AsymmetricLogTag, errorMessage);
|
||||
}
|
||||
|
||||
processed = true;
|
||||
m_cv.notify_all();
|
||||
}
|
||||
);
|
||||
|
||||
//consumer
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_cv.wait(lock, [&]{ return processed; });
|
||||
|
||||
}
|
||||
|
||||
return success? SigningFutureOutcome(std::move(httpRequest)) : SigningError(Aws::Client::CoreErrors::MEMORY_ALLOCATION, "", "Failed to sign the request with sigv4", false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual ~AwsSigV4aSigner() {};
|
||||
protected:
|
||||
|
||||
bool createAwsSigningConfig(
|
||||
std::shared_ptr<Aws::Crt::Auth::Credentials>& crtCredentials,
|
||||
const Aws::Http::HttpRequest& request,
|
||||
Aws::Crt::Auth::AwsSigningConfig& awsSigningConfig,
|
||||
bool signBody) const
|
||||
{
|
||||
awsSigningConfig.SetSigningAlgorithm(static_cast<Aws::Crt::Auth::SigningAlgorithm>(Aws::Auth::AWSSigningAlgorithm::ASYMMETRIC_SIGV4));
|
||||
awsSigningConfig.SetSignatureType(m_signatureType);
|
||||
awsSigningConfig.SetRegion(m_region.c_str());
|
||||
awsSigningConfig.SetService(m_region.c_str());
|
||||
awsSigningConfig.SetSigningTimepoint(GetSigningTimestamp().UnderlyingTimestamp());
|
||||
awsSigningConfig.SetUseDoubleUriEncode(m_urlEscape);
|
||||
awsSigningConfig.SetShouldNormalizeUriPath(true);
|
||||
awsSigningConfig.SetOmitSessionToken(false);
|
||||
awsSigningConfig.SetShouldSignHeaderUserData(reinterpret_cast<void*>(const_cast<Aws::Set<Aws::String>*>(&m_unsignedHeaders)));
|
||||
awsSigningConfig.SetShouldSignHeaderCallback([](const Aws::Crt::ByteCursor *name, void *user_data) {
|
||||
Aws::Set<Aws::String>* unsignedHeaders = static_cast<Aws::Set<Aws::String>*>(user_data);
|
||||
Aws::String headerKey(reinterpret_cast<const char*>(name->ptr), name->len);
|
||||
return unsignedHeaders->find(Aws::Utils::StringUtils::ToLower(headerKey.c_str())) == unsignedHeaders->cend();
|
||||
});
|
||||
if (m_signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders)
|
||||
{
|
||||
Aws::String payloadHash(UNSIGNED_PAYLOAD);
|
||||
if(signBody || request.GetUri().GetScheme() != Aws::Http::Scheme::HTTPS)
|
||||
{
|
||||
if (!request.GetContentBody())
|
||||
{
|
||||
AWS_LOGSTREAM_DEBUG(v4AsymmetricLogTag, "Using cached empty string sha256 " << EMPTY_STRING_SHA256 << " because payload is empty.");
|
||||
payloadHash = EMPTY_STRING_SHA256;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The hash will be calculated from the payload during signing.
|
||||
payloadHash = {};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AWS_LOGSTREAM_DEBUG(v4AsymmetricLogTag, "Note: Http payloads are not being signed. signPayloads=" << signBody
|
||||
<< " http scheme=" << Aws::Http::SchemeMapper::ToString(request.GetUri().GetScheme()));
|
||||
}
|
||||
awsSigningConfig.SetSignedBodyValue(payloadHash.c_str());
|
||||
awsSigningConfig.SetSignedBodyHeader(m_includeSha256HashHeader ? Aws::Crt::Auth::SignedBodyHeaderType::XAmzContentSha256 : Aws::Crt::Auth::SignedBodyHeaderType::None);
|
||||
}
|
||||
else if (m_signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams)
|
||||
{
|
||||
if (ServiceRequireUnsignedPayload(m_serviceName))
|
||||
{
|
||||
awsSigningConfig.SetSignedBodyValue(UNSIGNED_PAYLOAD);
|
||||
}
|
||||
else
|
||||
{
|
||||
awsSigningConfig.SetSignedBodyValue(EMPTY_STRING_SHA256);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AWS_LOGSTREAM_ERROR(v4AsymmetricLogTag, "The signature type should be either \"HttpRequestViaHeaders\" or \"HttpRequestViaQueryParams\"");
|
||||
return false;
|
||||
}
|
||||
awsSigningConfig.SetExpirationInSeconds(static_cast<uint64_t>(m_expirationTimeInSeconds));
|
||||
awsSigningConfig.SetCredentials(crtCredentials);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ServiceRequireUnsignedPayload(const Aws::String& serviceName) const
|
||||
{
|
||||
// S3 uses a magic string (instead of the empty string) for its body hash for presigned URLs as outlined here:
|
||||
// https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
|
||||
// this is true for PUT, POST, GET, DELETE and HEAD operations.
|
||||
// However, other services (for example RDS) implement the specification as outlined here:
|
||||
// https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
// which states that body-less requests should use the empty-string SHA256 hash.
|
||||
return "s3" == serviceName || "s3-object-lambda" == serviceName;
|
||||
}
|
||||
|
||||
Aws::String m_serviceName;
|
||||
Aws::String m_region;
|
||||
//params that can be exposed later
|
||||
long long m_expirationTimeInSeconds{0};
|
||||
const bool m_includeSha256HashHeader{true};
|
||||
const bool m_urlEscape{true};
|
||||
const Aws::Set<Aws::String> m_unsignedHeaders{USER_AGENT,X_AMZN_TRACE_ID};
|
||||
const Aws::Crt::Auth::SignatureType m_signatureType{Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams};
|
||||
std::condition_variable m_cv;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
#include <smithy/interceptor/InterceptorContext.h>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
namespace interceptor
|
||||
{
|
||||
class Interceptor
|
||||
{
|
||||
public:
|
||||
virtual ~Interceptor() = default;
|
||||
|
||||
using ModifyRequestOutcome = Aws::Utils::Outcome<std::shared_ptr<Aws::Http::HttpRequest>, Aws::Client::AWSError<Aws::Client::CoreErrors>>;
|
||||
virtual ModifyRequestOutcome ModifyBeforeSigning(InterceptorContext& context) = 0;
|
||||
|
||||
using ModifyResponseOutcome = Aws::Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, Aws::Client::AWSError<Aws::Client::CoreErrors>>;
|
||||
virtual ModifyResponseOutcome ModifyBeforeDeserialization(InterceptorContext& context) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
#include <aws/core/utils/memory/stl/AWSString.h>
|
||||
#include <aws/core/AmazonWebServiceRequest.h>
|
||||
#include <aws/core/AmazonWebServiceResult.h>
|
||||
#include <aws/core/http/HttpRequest.h>
|
||||
#include <aws/core/http/HttpResponse.h>
|
||||
#include <aws/core/client/CoreErrors.h>
|
||||
|
||||
namespace smithy
|
||||
{
|
||||
namespace interceptor
|
||||
{
|
||||
class InterceptorContext
|
||||
{
|
||||
public:
|
||||
explicit InterceptorContext(const Aws::AmazonWebServiceRequest& m_modeled_request)
|
||||
: m_modeledRequest(m_modeled_request)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~InterceptorContext() = default;
|
||||
InterceptorContext(const InterceptorContext& other) = delete;
|
||||
InterceptorContext(InterceptorContext&& other) noexcept = delete;
|
||||
InterceptorContext& operator=(const InterceptorContext& other) = delete;
|
||||
InterceptorContext& operator=(InterceptorContext&& other) noexcept = delete;
|
||||
|
||||
const Aws::AmazonWebServiceRequest& GetModeledRequest() const
|
||||
{
|
||||
return m_modeledRequest;
|
||||
}
|
||||
|
||||
std::shared_ptr<Aws::Http::HttpRequest> GetTransmitRequest() const
|
||||
{
|
||||
return m_transmitRequest;
|
||||
}
|
||||
|
||||
void SetTransmitRequest(const std::shared_ptr<Aws::Http::HttpRequest>& transmitRequest)
|
||||
{
|
||||
m_transmitRequest = transmitRequest;
|
||||
}
|
||||
|
||||
std::shared_ptr<Aws::Http::HttpResponse> GetTransmitResponse() const
|
||||
{
|
||||
return m_transmitResponse;
|
||||
}
|
||||
|
||||
void SetTransmitResponse(const std::shared_ptr<Aws::Http::HttpResponse>& transmitResponse)
|
||||
{
|
||||
m_transmitResponse = transmitResponse;
|
||||
}
|
||||
|
||||
Aws::String GetAttribute(const Aws::String& key) const
|
||||
{
|
||||
return m_attributes.at(key);
|
||||
}
|
||||
|
||||
void SetAttribute(const Aws::String& key, const Aws::String& value)
|
||||
{
|
||||
m_attributes.insert({key, value});
|
||||
}
|
||||
|
||||
private:
|
||||
Aws::Map<Aws::String, Aws::String> m_attributes{};
|
||||
const Aws::AmazonWebServiceRequest& m_modeledRequest;
|
||||
std::shared_ptr<Aws::Http::HttpRequest> m_transmitRequest{nullptr};
|
||||
std::shared_ptr<Aws::Http::HttpResponse> m_transmitResponse{nullptr};
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
#include <aws/core/utils/memory/stl/AWSString.h>
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* A container that starts a async measurement
|
||||
* that has virtual function to stop it.
|
||||
*/
|
||||
class SMITHY_API GaugeHandle {
|
||||
public:
|
||||
virtual ~GaugeHandle() = default;
|
||||
|
||||
/**
|
||||
* Stop the measurement of the gauge.
|
||||
*/
|
||||
virtual void Stop() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Measures the current instantaneous value. Is used in
|
||||
* the implementation of a gauge handle to take an actual
|
||||
* measurement.
|
||||
*/
|
||||
class SMITHY_API AsyncMeasurement {
|
||||
public:
|
||||
virtual ~AsyncMeasurement() = default;
|
||||
|
||||
/**
|
||||
* A Functional interface of recording a value.
|
||||
* @param value the value of the measurement.
|
||||
* @param attributes the attributes or dimensions associate with this measurement.
|
||||
*/
|
||||
virtual void Record(double value, const Aws::Map<Aws::String, Aws::String> &attributes) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/utils/memory/stl/AWSString.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* Measures a value where the statistics are likely meaningful.
|
||||
*/
|
||||
class SMITHY_API Histogram {
|
||||
public:
|
||||
virtual ~Histogram() = default;
|
||||
|
||||
/**
|
||||
* Records a value to the histogram.
|
||||
*
|
||||
* @param value the value that be recorded in a statistical distribution.
|
||||
* @param attributes the attributes or dimensions associate with this measurement.
|
||||
*/
|
||||
virtual void record(double value, Aws::Map<Aws::String, Aws::String> attributes) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/tracing/Gauge.h>
|
||||
#include <smithy/tracing/MonotonicCounter.h>
|
||||
#include <smithy/tracing/UpDownCounter.h>
|
||||
#include <smithy/tracing/Histogram.h>
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* Entry point to creating instruments. An Instrument is responsible for taking measurements.
|
||||
* The returned entities will be responsible for taking measurements directly in code.
|
||||
*/
|
||||
class SMITHY_API Meter {
|
||||
public:
|
||||
virtual ~Meter() = default;
|
||||
|
||||
/**
|
||||
* Create a Gauge instrument that will measure a provided callback function.
|
||||
* @param name The metric name being recorded.
|
||||
* @param callback The callback function that will be recording the measurement
|
||||
* in a async runtime.
|
||||
* @param units The units of the measurement being recorded.
|
||||
* @param description The description of the measurement.
|
||||
* @return A handle to the gauge that has been created that has access to the
|
||||
* callback being used to record the metric.
|
||||
*/
|
||||
virtual Aws::UniquePtr<GaugeHandle> CreateGauge(Aws::String name,
|
||||
std::function<void(Aws::UniquePtr<AsyncMeasurement>)> callback,
|
||||
Aws::String units,
|
||||
Aws::String description) const = 0;
|
||||
|
||||
/**
|
||||
* Create a UpDownCounter that will measure a metric that can increase/decrease
|
||||
* in count.
|
||||
*
|
||||
* @param name The metric name being recorded.
|
||||
* @param units units The units of the measurement being recorded.
|
||||
* @param description The description of the measurement.
|
||||
* @return A UpDownCounter that can record the value of a count.
|
||||
*/
|
||||
virtual Aws::UniquePtr<UpDownCounter> CreateUpDownCounter(Aws::String name,
|
||||
Aws::String units,
|
||||
Aws::String description) const = 0;
|
||||
|
||||
/**
|
||||
* Create a Counter that will measure a metric that can only increase
|
||||
* in count.
|
||||
*
|
||||
* @param name The metric name being recorded.
|
||||
* @param units units The units of the measurement being recorded.
|
||||
* @param description The description of the measurement.
|
||||
* @return A Counter that can record the value of a count.
|
||||
*/
|
||||
virtual Aws::UniquePtr<MonotonicCounter> CreateCounter(Aws::String name,
|
||||
Aws::String units,
|
||||
Aws::String description) const = 0;
|
||||
|
||||
/**
|
||||
* Create a Histogram that will measure a metric that can be translated
|
||||
* into a statistical measurement.
|
||||
*
|
||||
* @param name The metric name being recorded.
|
||||
* @param units units The units of the measurement being recorded.
|
||||
* @param description The description of the measurement.
|
||||
* @return A Histogram that can measure a statistical value.
|
||||
*/
|
||||
virtual Aws::UniquePtr<Histogram> CreateHistogram(Aws::String name,
|
||||
Aws::String units,
|
||||
Aws::String description) const = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/utils/memory/stl/AWSString.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
#include <smithy/tracing/Meter.h>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* Entry point for metrics emission API. Will return a meter which in turn
|
||||
* can provide specific metric taking instruments.
|
||||
*/
|
||||
class SMITHY_API MeterProvider {
|
||||
public:
|
||||
virtual ~MeterProvider() = default;
|
||||
|
||||
/**
|
||||
* Provide a meter that will in turn provide instruments for metrics.
|
||||
* @param scope The scope that meter is used for.
|
||||
* @param attributes the attributes or dimensions associate with this measurement.
|
||||
* @return A Meter.
|
||||
*/
|
||||
virtual std::shared_ptr<Meter> GetMeter(Aws::String scope,
|
||||
Aws::Map<Aws::String, Aws::String> attributes) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/utils/memory/stl/AWSString.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* Measures a value that only ever increases.
|
||||
*/
|
||||
class SMITHY_API MonotonicCounter {
|
||||
public:
|
||||
virtual ~MonotonicCounter() = default;
|
||||
|
||||
/**
|
||||
* Adds a value to counter.
|
||||
* @param value the count to be added to the counter.
|
||||
* @param attributes the attributes or dimensions associate with this measurement.
|
||||
*/
|
||||
virtual void add(long value, Aws::Map<Aws::String, Aws::String> attributes) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
#include <smithy/tracing/MeterProvider.h>
|
||||
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* A no-op implementation of the Gauge handle that
|
||||
* is simply pass though
|
||||
*/
|
||||
class NoopGaugeHandle : public GaugeHandle {
|
||||
public:
|
||||
void Stop() override {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A no-op implementation of the UpDownCounter that
|
||||
* is simply pass though
|
||||
*/
|
||||
class NoopUpDownCounter : public UpDownCounter {
|
||||
void add(long value, Aws::Map<Aws::String, Aws::String> attributes) override {
|
||||
AWS_UNREFERENCED_PARAM(value);
|
||||
AWS_UNREFERENCED_PARAM(attributes);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A no-op implementation of the MonotonicCounter that
|
||||
* is simply pass though
|
||||
*/
|
||||
class NoopMonotonicCounter : public MonotonicCounter {
|
||||
void add(long value, Aws::Map<Aws::String, Aws::String> attributes) override {
|
||||
AWS_UNREFERENCED_PARAM(value);
|
||||
AWS_UNREFERENCED_PARAM(attributes);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A no-op implementation of the Histogram that
|
||||
* is simply pass though
|
||||
*/
|
||||
class NoopHistogram : public Histogram {
|
||||
public:
|
||||
void record(double value, Aws::Map<Aws::String, Aws::String> attributes) override {
|
||||
AWS_UNREFERENCED_PARAM(value);
|
||||
AWS_UNREFERENCED_PARAM(attributes);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A no-op implementation of the Meter that
|
||||
* is simply pass though
|
||||
*/
|
||||
class NoopMeter : public Meter {
|
||||
public:
|
||||
Aws::UniquePtr<GaugeHandle> CreateGauge(Aws::String name,
|
||||
std::function<void(Aws::UniquePtr<AsyncMeasurement>)> callback,
|
||||
Aws::String units,
|
||||
Aws::String description) const override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(name);
|
||||
AWS_UNREFERENCED_PARAM(callback);
|
||||
AWS_UNREFERENCED_PARAM(units);
|
||||
AWS_UNREFERENCED_PARAM(description);
|
||||
return Aws::MakeUnique<NoopGaugeHandle>("NO_OP");
|
||||
}
|
||||
|
||||
Aws::UniquePtr<UpDownCounter> CreateUpDownCounter(Aws::String name,
|
||||
Aws::String units,
|
||||
Aws::String description) const override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(name);
|
||||
AWS_UNREFERENCED_PARAM(units);
|
||||
AWS_UNREFERENCED_PARAM(description);
|
||||
return Aws::MakeUnique<NoopUpDownCounter>("NO_OP");
|
||||
}
|
||||
|
||||
Aws::UniquePtr<MonotonicCounter> CreateCounter(Aws::String name,
|
||||
Aws::String units,
|
||||
Aws::String description) const override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(name);
|
||||
AWS_UNREFERENCED_PARAM(units);
|
||||
AWS_UNREFERENCED_PARAM(description);
|
||||
return Aws::MakeUnique<NoopMonotonicCounter>("NO_OP");
|
||||
}
|
||||
|
||||
Aws::UniquePtr<Histogram> CreateHistogram(Aws::String name,
|
||||
Aws::String units,
|
||||
Aws::String description) const override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(name);
|
||||
AWS_UNREFERENCED_PARAM(units);
|
||||
AWS_UNREFERENCED_PARAM(description);
|
||||
return Aws::MakeUnique<NoopHistogram>("NO_OP");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A no-op implementation of the MeterProvider that
|
||||
* is simply pass though
|
||||
*/
|
||||
class NoopMeterProvider : public MeterProvider {
|
||||
public:
|
||||
std::shared_ptr<Meter>
|
||||
GetMeter(Aws::String scope,Aws::Map<Aws::String,Aws::String> attributes) override
|
||||
{
|
||||
AWS_UNREFERENCED_PARAM(scope);
|
||||
AWS_UNREFERENCED_PARAM(attributes);
|
||||
return Aws::MakeShared<NoopMeter>("NO_OP");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
|
||||
#include <utility>
|
||||
#include <smithy/tracing/NoopTracerProvider.h>
|
||||
#include <smithy/tracing/NoopMeterProvider.h>
|
||||
#include <smithy/tracing/TelemetryProvider.h>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* A no-op implementation of TelemetryProvider that
|
||||
* is simply pass though container of telemetry functionality
|
||||
*/
|
||||
class SMITHY_API NoopTelemetryProvider {
|
||||
public:
|
||||
static Aws::UniquePtr<TelemetryProvider> CreateProvider() {
|
||||
return Aws::MakeUnique<TelemetryProvider>("NO_OP",
|
||||
Aws::MakeUnique<NoopTracerProvider>("NO_OP", Aws::MakeUnique<NoopTracer>("NO_OP")),
|
||||
Aws::MakeUnique<NoopMeterProvider>("NO_OP"),
|
||||
[]() -> void {},
|
||||
[]() -> void {});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
#include <smithy/tracing/TracerProvider.h>
|
||||
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* A no-op implementation of TraceSpan that is pass through.
|
||||
*/
|
||||
class NoopTracerSpan : public TraceSpan {
|
||||
public:
|
||||
NoopTracerSpan(const Aws::String &name) : TraceSpan(name) {}
|
||||
|
||||
void emitEvent(Aws::String name, const Aws::Map<Aws::String, Aws::String> &attributes) override {
|
||||
AWS_UNREFERENCED_PARAM(name);
|
||||
AWS_UNREFERENCED_PARAM(attributes);
|
||||
}
|
||||
|
||||
void setAttribute(Aws::String key, Aws::String value) override {
|
||||
AWS_UNREFERENCED_PARAM(key);
|
||||
AWS_UNREFERENCED_PARAM(value);
|
||||
}
|
||||
|
||||
void setStatus(TraceSpanStatus status) override {
|
||||
AWS_UNREFERENCED_PARAM(status);
|
||||
}
|
||||
|
||||
void end() override {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A no-op implementation of Tracer that is pass through.
|
||||
*/
|
||||
class NoopTracer : public Tracer {
|
||||
public:
|
||||
std::shared_ptr<TraceSpan> CreateSpan(Aws::String name,
|
||||
const Aws::Map<Aws::String, Aws::String> &attributes,
|
||||
SpanKind spanKind) override {
|
||||
AWS_UNREFERENCED_PARAM(attributes);
|
||||
AWS_UNREFERENCED_PARAM(spanKind);
|
||||
return Aws::MakeShared<NoopTracerSpan>("NO_OP", name);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A no-op implementation of NoopTracerProvider that is pass through.
|
||||
*/
|
||||
class NoopTracerProvider : public TracerProvider {
|
||||
public:
|
||||
explicit NoopTracerProvider(std::shared_ptr<NoopTracer> tracer) : m_tracer(std::move(tracer)) {}
|
||||
|
||||
std::shared_ptr<Tracer> GetTracer(Aws::String scope,
|
||||
const Aws::Map<Aws::String, Aws::String> &attributes) override {
|
||||
AWS_UNREFERENCED_PARAM(scope);
|
||||
AWS_UNREFERENCED_PARAM(attributes);
|
||||
return m_tracer;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<NoopTracer> m_tracer;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
#include <smithy/tracing/TracerProvider.h>
|
||||
#include <smithy/tracing/MeterProvider.h>
|
||||
#include <aws/core/utils/memory/AWSMemory.h>
|
||||
#include <utility>
|
||||
#include <mutex>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* A Utility holder class that manages the creation and
|
||||
* management of telemetry related operations.
|
||||
*/
|
||||
class SMITHY_API TelemetryProvider {
|
||||
public:
|
||||
/**
|
||||
* Creates a Telemetry provider with given providers and a init
|
||||
* and shutdown function that is run during its ctor/dtor.
|
||||
* @param tracerProvider The TracerProvider to be used in the SDK.
|
||||
* @param meterProvider The MeterProvider to be used in the SDK.
|
||||
* @param init The initialization function that will be run at creation.
|
||||
* @param shutdown The shutdown function that will be run at destruction.
|
||||
*/
|
||||
TelemetryProvider(Aws::UniquePtr<TracerProvider> tracerProvider,
|
||||
Aws::UniquePtr<MeterProvider> meterProvider,
|
||||
std::function<void()> init,
|
||||
std::function<void()> shutdown) :
|
||||
m_tracerProvider(std::move(tracerProvider)),
|
||||
m_meterProvider(std::move(meterProvider)),
|
||||
m_init(std::move(init)),
|
||||
m_shutdown(std::move(shutdown))
|
||||
{
|
||||
RunInit();
|
||||
}
|
||||
|
||||
virtual ~TelemetryProvider() {
|
||||
RunShutDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a Tracer used to create spans.
|
||||
*
|
||||
* @param scope The scope of the Tracer that is being used.
|
||||
* @param attributes the attributes or dimensions associate with this measurement.
|
||||
* @return A reference to a Tracer instance.
|
||||
*/
|
||||
std::shared_ptr<Tracer>
|
||||
getTracer(Aws::String scope, const Aws::Map<Aws::String, Aws::String> &attributes) {
|
||||
return m_tracerProvider->GetTracer(std::move(scope), attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a Meter used to create metrics.
|
||||
*
|
||||
* @param scope The scope of the Meter that is being used.
|
||||
* @param attributes the attributes or dimensions associate with this measurement.
|
||||
* @return A reference to a Meter instance.
|
||||
*/
|
||||
std::shared_ptr<Meter>
|
||||
getMeter(Aws::String scope, const Aws::Map<Aws::String, Aws::String> &attributes) {
|
||||
return m_meterProvider->GetMeter(std::move(scope), attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs initialization of the Tracer Provider and the MeterProvider. Will only
|
||||
* be run once during initialization.
|
||||
*/
|
||||
void RunInit() {
|
||||
std::call_once(m_initFlag, m_init);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs shutdown of the Tracer Provider and the MeterProvider. Will only
|
||||
* be run once during destruction.
|
||||
*/
|
||||
void RunShutDown() {
|
||||
std::call_once(m_shutdownFlag, m_shutdown);
|
||||
}
|
||||
|
||||
private:
|
||||
std::once_flag m_initFlag;
|
||||
std::once_flag m_shutdownFlag;
|
||||
const Aws::UniquePtr<TracerProvider> m_tracerProvider;
|
||||
const Aws::UniquePtr<MeterProvider> m_meterProvider;
|
||||
const std::function<void()> m_init;
|
||||
const std::function<void()> m_shutdown;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/utils/memory/stl/AWSString.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* Status of the span.
|
||||
*/
|
||||
enum class TraceSpanStatus {
|
||||
UNSET,
|
||||
OK,
|
||||
FAULT,
|
||||
};
|
||||
|
||||
/**
|
||||
* The basic unit of a "Trace". Represents a time period during which events
|
||||
* occur. Child spans and events can take place within trace. It is a hierarchy
|
||||
* and ledger of timing and events during a operation.
|
||||
*/
|
||||
class SMITHY_API TraceSpan {
|
||||
public:
|
||||
/**
|
||||
* Create a Span
|
||||
* @param name The name of the span.
|
||||
*/
|
||||
TraceSpan(Aws::String name) : m_name(std::move(name)) {}
|
||||
|
||||
virtual ~TraceSpan() = default;
|
||||
|
||||
/**
|
||||
* Emit a event associated with the span.
|
||||
* @param name The name of the event.
|
||||
* @param attributes the attributes or dimensions associate with this measurement.
|
||||
*/
|
||||
virtual void emitEvent(Aws::String name, const Aws::Map<Aws::String, Aws::String> &attributes) = 0;
|
||||
|
||||
/**
|
||||
* Set a Attribute to span.
|
||||
* @param key The key of the dimension/attribute.
|
||||
* @param value The value of the dimension/attribute.
|
||||
*/
|
||||
virtual void setAttribute(Aws::String key, Aws::String value) = 0;
|
||||
|
||||
/**
|
||||
* Set the statue of the span.
|
||||
* @param status The status to be assigned.
|
||||
*/
|
||||
virtual void setStatus(TraceSpanStatus status) = 0;
|
||||
|
||||
/**
|
||||
* End the span and mark as finished.
|
||||
*/
|
||||
virtual void end() = 0;
|
||||
|
||||
private:
|
||||
Aws::String m_name;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/tracing/TraceSpan.h>
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
#include <memory>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* The kind of span being created.
|
||||
*/
|
||||
enum class SpanKind {
|
||||
INTERNAL,
|
||||
CLIENT,
|
||||
SERVER,
|
||||
};
|
||||
|
||||
/**
|
||||
* Entry point for creating a Span. Any new spans will
|
||||
* be created from this.
|
||||
*/
|
||||
class SMITHY_API Tracer {
|
||||
public:
|
||||
virtual ~Tracer() = default;
|
||||
|
||||
/**
|
||||
* Creates a span.
|
||||
*
|
||||
* @param name Name of the span.
|
||||
* @param attributes the attributes or dimensions associate with this measurement.
|
||||
* @param spanKind The kind of the span.
|
||||
* @return A instance of a span.
|
||||
*/
|
||||
virtual std::shared_ptr<TraceSpan> CreateSpan(Aws::String name,
|
||||
const Aws::Map<Aws::String, Aws::String> &attributes,
|
||||
SpanKind spanKind) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <smithy/tracing/Tracer.h>
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* Entry point for creating Tracer instances.
|
||||
*/
|
||||
class SMITHY_API TracerProvider {
|
||||
public:
|
||||
virtual ~TracerProvider() = default;
|
||||
|
||||
/**
|
||||
* Returns a reference to a Tracer instance.
|
||||
* @param scope The scope of the Tracer that is being used.
|
||||
* @param attributes the attributes or dimensions associate with this measurement.
|
||||
* @return A reference to a Tracer instance.
|
||||
*/
|
||||
virtual std::shared_ptr<Tracer> GetTracer(Aws::String scope, const Aws::Map<Aws::String, Aws::String> &attributes) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/monitoring/HttpClientMetrics.h>
|
||||
#include <aws/core/utils/logging/LogMacros.h>
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
#include <smithy/tracing/Meter.h>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* A utility class for common tracing activities.
|
||||
*/
|
||||
class SMITHY_API TracingUtils {
|
||||
public:
|
||||
TracingUtils() = default;
|
||||
|
||||
static const char COUNT_METRIC_TYPE[];
|
||||
static const char MICROSECOND_METRIC_TYPE[];
|
||||
static const char BYTES_PER_SECOND_METRIC_TYPE[];
|
||||
static const char SMITHY_CLIENT_DURATION_METRIC[];
|
||||
static const char SMITHY_CLIENT_ENDPOINT_RESOLUTION_METRIC[];
|
||||
static const char SMITHY_CLIENT_DESERIALIZATION_METRIC[];
|
||||
static const char SMITHY_CLIENT_SIGNING_METRIC[];
|
||||
static const char SMITHY_CLIENT_SERIALIZATION_METRIC[];
|
||||
static const char SMITHY_CLIENT_SERVICE_CALL_METRIC[];
|
||||
static const char SMITHY_CLIENT_SERVICE_BACKOFF_DELAY_METRIC[];
|
||||
static const char SMITHY_CLIENT_SERVICE_ATTEMPTS_METRIC[];
|
||||
static const char SMITHY_METHOD_AWS_VALUE[];
|
||||
static const char SMITHY_SERVICE_DIMENSION[];
|
||||
static const char SMITHY_METHOD_DIMENSION[];
|
||||
static const char SMITHY_SYSTEM_DIMENSION[];
|
||||
static const char SMITHY_METRICS_DNS_DURATION[];
|
||||
static const char SMITHY_METRICS_CONNECT_DURATION[];
|
||||
static const char SMITHY_METRICS_SSL_DURATION[];
|
||||
static const char SMITHY_METRICS_DOWNLOAD_SPEED_METRIC[];
|
||||
static const char SMITHY_METRICS_UPLOAD_SPEED_METRIC[];
|
||||
static const char SMITHY_METRICS_UNKNOWN_METRIC[];
|
||||
|
||||
/**
|
||||
* Will run a function and emit the duration of that function in millisecond timing to the
|
||||
* meter provided as a Histogram metrics. Will return the result af the function.
|
||||
* @tparam T The type that is being returned from the function.
|
||||
* @param func A function that returns T.
|
||||
* @param metricName The name of the metric that is being captured by the function.
|
||||
* @param meter The meter making the measurement.
|
||||
* @param attributes The attributes or dimensions associate with this measurement.
|
||||
* @param description The description of the measurement.
|
||||
* @return the result of func.
|
||||
*/
|
||||
template<typename T>
|
||||
static T MakeCallWithTiming(std::function<T()> func,
|
||||
const Aws::String &metricName,
|
||||
const Meter &meter,
|
||||
Aws::Map<Aws::String, Aws::String>&& attributes,
|
||||
const Aws::String &description = "")
|
||||
{
|
||||
auto before = std::chrono::steady_clock::now();
|
||||
auto returnValue = func();
|
||||
auto after = std::chrono::steady_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(after - before).count();
|
||||
auto histogram = meter.CreateHistogram(metricName, MICROSECOND_METRIC_TYPE, description);
|
||||
if (!histogram) {
|
||||
AWS_LOG_ERROR("TracingUtil", "Failed to create histogram");
|
||||
return {};
|
||||
}
|
||||
histogram->record((double) duration, std::forward<Aws::Map<Aws::String, Aws::String>>(attributes));
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will run a function and emit the duration of that function in millisecond timing to the
|
||||
* meter provided as a Histogram metrics.
|
||||
* @param func a function that does not return anything but will be measured.
|
||||
* @param metricName The name of the metric that is being captured by the function.
|
||||
* @param meter The meter making the measurement.
|
||||
* @param attributes The attributes or dimensions associate with this measurement.
|
||||
* @param description The description of the measurement.
|
||||
*/
|
||||
static void MakeCallWithTiming(std::function<void(void)> func,
|
||||
Aws::String metricName,
|
||||
const Meter &meter,
|
||||
Aws::Map<Aws::String, Aws::String>&& attributes,
|
||||
Aws::String description = "")
|
||||
{
|
||||
auto before = std::chrono::steady_clock::now();
|
||||
func();
|
||||
auto after = std::chrono::steady_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(after - before).count();
|
||||
auto histogram = meter.CreateHistogram(std::move(metricName), MICROSECOND_METRIC_TYPE, std::move(description));
|
||||
if (!histogram) {
|
||||
AWS_LOG_ERROR("TracingUtil", "Failed to create histogram");
|
||||
return;
|
||||
}
|
||||
histogram->record((double) duration, std::forward<Aws::Map<Aws::String, Aws::String>>(attributes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits http metrics to a specified meter.
|
||||
* @param metrics A http metrics collection that we will emit.
|
||||
* @param meter The meter used for metrics emissions.
|
||||
* @param attributes The attributes or dimensions associate with this measurement.
|
||||
* @param description The description of the measurement.
|
||||
*/
|
||||
static void EmitCoreHttpMetrics(const Aws::Monitoring::HttpClientMetricsCollection &metrics,
|
||||
const Meter &meter,
|
||||
Aws::Map<Aws::String, Aws::String>&& attributes,
|
||||
Aws::String description = "")
|
||||
{
|
||||
for (auto const &entry: metrics) {
|
||||
auto smithyMetric = ConvertCoreMetricToSmithy(entry.first);
|
||||
if (smithyMetric.first != SMITHY_METRICS_UNKNOWN_METRIC) {
|
||||
auto histogram = meter.CreateHistogram(std::move(smithyMetric.first),
|
||||
smithyMetric.second,
|
||||
std::move(description));
|
||||
if (!histogram) {
|
||||
AWS_LOG_ERROR("TracingUtil", "Failed to create histogram");
|
||||
}
|
||||
histogram->record((double) entry.second, attributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the string Representation of a Core metric to a smithy metric.
|
||||
* @param name the metric name.
|
||||
* @return A tuple of metric name to measurement unit.
|
||||
*/
|
||||
static std::pair<Aws::String, Aws::String> ConvertCoreMetricToSmithy(const Aws::String &name) {
|
||||
//TODO: Make static map, Aws::Map cannot be made static with a customer memory manager as of the moment.
|
||||
Aws::Map<int, std::pair<Aws::String, Aws::String>> metricsTypeToName =
|
||||
{
|
||||
std::pair<int, std::pair<Aws::String, Aws::String>>(
|
||||
static_cast<int>(Aws::Monitoring::HttpClientMetricsType::DnsLatency),
|
||||
std::make_pair(SMITHY_METRICS_DNS_DURATION, MICROSECOND_METRIC_TYPE)),
|
||||
std::pair<int, std::pair<Aws::String, Aws::String>>(
|
||||
static_cast<int>(Aws::Monitoring::HttpClientMetricsType::ConnectLatency),
|
||||
std::make_pair(SMITHY_METRICS_CONNECT_DURATION, MICROSECOND_METRIC_TYPE)),
|
||||
std::pair<int, std::pair<Aws::String, Aws::String>>(
|
||||
static_cast<int>(Aws::Monitoring::HttpClientMetricsType::SslLatency),
|
||||
std::make_pair(SMITHY_METRICS_SSL_DURATION, MICROSECOND_METRIC_TYPE)),
|
||||
std::pair<int, std::pair<Aws::String, Aws::String>>(
|
||||
static_cast<int>(Aws::Monitoring::HttpClientMetricsType::DownloadSpeed),
|
||||
std::make_pair(SMITHY_METRICS_DOWNLOAD_SPEED_METRIC, BYTES_PER_SECOND_METRIC_TYPE)),
|
||||
std::pair<int, std::pair<Aws::String, Aws::String>>(
|
||||
static_cast<int>(Aws::Monitoring::HttpClientMetricsType::UploadSpeed),
|
||||
std::make_pair(SMITHY_METRICS_UPLOAD_SPEED_METRIC, BYTES_PER_SECOND_METRIC_TYPE)),
|
||||
};
|
||||
|
||||
auto metricType = Aws::Monitoring::GetHttpClientMetricTypeByName(name);
|
||||
auto it = metricsTypeToName.find(static_cast<int>(metricType));
|
||||
if (it == metricsTypeToName.end()) {
|
||||
return std::make_pair(SMITHY_METRICS_UNKNOWN_METRIC, "unknown");
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/utils/memory/stl/AWSString.h>
|
||||
#include <aws/core/utils/memory/stl/AWSMap.h>
|
||||
#include <smithy/Smithy_EXPORTS.h>
|
||||
|
||||
namespace smithy {
|
||||
namespace components {
|
||||
namespace tracing {
|
||||
/**
|
||||
* Measures a value that goes up or down.
|
||||
*/
|
||||
class SMITHY_API UpDownCounter {
|
||||
public:
|
||||
virtual ~UpDownCounter() = default;
|
||||
|
||||
/**
|
||||
* Adds a value to counter.
|
||||
* @param value the count to be added to the counter.
|
||||
* @param attributes the attributes or dimensions associate with this measurement.
|
||||
*/
|
||||
virtual void add(long value, Aws::Map<Aws::String, Aws::String> attributes) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user