diff --git a/generated/src/aws-cpp-sdk-s3/include/aws/s3/S3Client.h b/generated/src/aws-cpp-sdk-s3/include/aws/s3/S3Client.h index 07e5d85e49d..48dfc32eca7 100644 --- a/generated/src/aws-cpp-sdk-s3/include/aws/s3/S3Client.h +++ b/generated/src/aws-cpp-sdk-s3/include/aws/s3/S3Client.h @@ -10,8 +10,10 @@ #include #include #include -#include +#include #include +#include +#include #include #include @@ -48,8 +50,8 @@ namespace Aws */ class AWS_S3_API S3Client : public smithy::client::AwsSmithyClientT, - Aws::Crt::Variant, + smithy::SigV4MultiAuthSchemeResolver<>, + Aws::Crt::Variant, S3EndpointProviderBase, smithy::client::XmlOutcomeSerializer, smithy::client::XmlOutcome, diff --git a/generated/src/aws-cpp-sdk-s3/source/S3Client.cpp b/generated/src/aws-cpp-sdk-s3/source/S3Client.cpp index 9e1e900787d..ac61f52bcf8 100644 --- a/generated/src/aws-cpp-sdk-s3/source/S3Client.cpp +++ b/generated/src/aws-cpp-sdk-s3/source/S3Client.cpp @@ -161,9 +161,11 @@ S3Client::S3Client(const S3::S3ClientConfiguration& clientConfiguration, Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), endpointProvider ? endpointProvider : Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG), { - {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, Aws::MakeShared(ALLOCATION_TAG)), GetServiceName(), clientConfiguration.region}}, + {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, + {smithy::S3ExpressSigV4AuthSchemeOption::s3ExpressSigV4AuthSchemeOption.schemeId, smithy::S3ExpressSigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, + {smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption.schemeId, smithy::SigV4aAuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, }) {} @@ -176,9 +178,11 @@ S3Client::S3Client(const AWSCredentials& credentials, Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), endpointProvider ? endpointProvider : Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG), { - {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, credentials), GetServiceName(), clientConfiguration.region}}, + {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, Aws::MakeShared(ALLOCATION_TAG, credentials) ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, + {smithy::S3ExpressSigV4AuthSchemeOption::s3ExpressSigV4AuthSchemeOption.schemeId, smithy::S3ExpressSigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, Aws::MakeShared(ALLOCATION_TAG, credentials) ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, + {smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption.schemeId, smithy::SigV4aAuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, Aws::MakeShared(ALLOCATION_TAG, credentials) ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, }) {} @@ -191,9 +195,11 @@ S3Client::S3Client(const std::shared_ptr& credentialsPro Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), endpointProvider ? endpointProvider : Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG), { - {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{ Aws::MakeShared(ALLOCATION_TAG, *this, credentialsProvider), GetServiceName(), clientConfiguration.region}} + {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, credentialsProvider ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, + {smithy::S3ExpressSigV4AuthSchemeOption::s3ExpressSigV4AuthSchemeOption.schemeId, smithy::S3ExpressSigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, credentialsProvider ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, + {smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption.schemeId, smithy::SigV4aAuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, credentialsProvider ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, }) {} @@ -209,10 +215,11 @@ S3Client::S3Client(const Client::ClientConfiguration& clientConfiguration, Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG), { - {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme(Aws::MakeShared(ALLOCATION_TAG, *this), - Aws::MakeShared( ALLOCATION_TAG, GetServiceName(), clientConfiguration.region, signPayloads, false))}, + {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, + {smithy::S3ExpressSigV4AuthSchemeOption::s3ExpressSigV4AuthSchemeOption.schemeId, smithy::S3ExpressSigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, + {smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption.schemeId, smithy::SigV4aAuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, }) { } @@ -230,10 +237,11 @@ S3Client::S3Client( Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG), { - {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme(Aws::MakeShared(ALLOCATION_TAG, credentials), - Aws::MakeShared( ALLOCATION_TAG, GetServiceName(), clientConfiguration.region, signPayloads, false))}, + {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, Aws::MakeShared(ALLOCATION_TAG, credentials) ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, + {smithy::S3ExpressSigV4AuthSchemeOption::s3ExpressSigV4AuthSchemeOption.schemeId, smithy::S3ExpressSigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, Aws::MakeShared(ALLOCATION_TAG, credentials) ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, + {smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption.schemeId, smithy::SigV4aAuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, Aws::MakeShared(ALLOCATION_TAG, credentials) ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, }) { } @@ -251,10 +259,11 @@ S3Client::S3Client( Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG), { - {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme(Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), - Aws::MakeShared( ALLOCATION_TAG, GetServiceName(), clientConfiguration.region, signPayloads, false))}, + {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, credentialsProvider ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, + {smithy::S3ExpressSigV4AuthSchemeOption::s3ExpressSigV4AuthSchemeOption.schemeId, smithy::S3ExpressSigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, credentialsProvider ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, + {smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption.schemeId, smithy::SigV4aAuthScheme{Aws::MakeShared(ALLOCATION_TAG, *this, credentialsProvider ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, }) { } diff --git a/generated/src/aws-cpp-sdk-s3/source/S3ExpressIdentityResolver.cpp b/generated/src/aws-cpp-sdk-s3/source/S3ExpressIdentityResolver.cpp index 3153e2ef59c..02bff5c55e5 100644 --- a/generated/src/aws-cpp-sdk-s3/source/S3ExpressIdentityResolver.cpp +++ b/generated/src/aws-cpp-sdk-s3/source/S3ExpressIdentityResolver.cpp @@ -7,7 +7,9 @@ #include #include #include - +#include +#include +#include #include #include @@ -22,7 +24,7 @@ namespace{ const char S3_EXPRESS_IDENTITY_PROVIDER[] = "S3ExpressIdentityProvider"; const int DEFAULT_CACHE_SIZE = 100; } -S3ExpressIdentityResolver::S3ExpressIdentityResolver(const S3Client& s3Client) : m_s3Client(s3Client) {} +S3ExpressIdentityResolver::S3ExpressIdentityResolver(const S3Client& s3Client) : m_s3Client(s3Client), m_credsProvider(Aws::MakeShared("S3ExpressIdentityResolver")) {} S3ExpressIdentityResolver::S3ExpressIdentityResolver(const S3Client& s3Client, std::shared_ptr credentialProvider): m_s3Client{s3Client},m_credsProvider{credentialProvider}{ @@ -50,11 +52,11 @@ S3ExpressIdentityResolver::ResolveIdentityFutureOutcome S3ExpressIdentityResolve }); } - //if signer name is not s3 express, get from credential provider - auto signerName = params->parameterMap.find("signerName"); + //if signer name is not s3 express as set in signer properties, get from credential provider + auto signerName = params->parameterMap.find(smithy::AUTH_SCHEME_PROPERTY); if (signerName != params->parameterMap.end()) { - if (signerName->second != "s3express") + if (signerName->second != smithy::S3_EXPRESS_SIGNER_NAME) { if(!m_credsProvider) { @@ -65,7 +67,7 @@ S3ExpressIdentityResolver::ResolveIdentityFutureOutcome S3ExpressIdentityResolve return ResolveIdentityFutureOutcome(Aws::MakeUnique("DefaultAwsCredentialIdentityResolver", AwsCredentialIdentity{creds.GetAWSAccessKeyId(), creds.GetAWSSecretKey(), creds.GetSessionToken(), creds.GetExpiration()})); } } - + auto identity = Aws::MakeUnique("DefaultAwsCredentialIdentityResolver", GetS3ExpressIdentity(params)); return ResolveIdentityFutureOutcome(std::move(identity)); @@ -126,11 +128,13 @@ AwsCredentialIdentity DefaultS3ExpressIdentityResolver::GetS3ExpressIdentity(con std::lock_guard lock(*GetMutexForBucketName(bucketNameIter->second)); AwsCredentialIdentity identity; auto isInCache = m_credentialsCache->Get(bucketNameIter->second, identity); - if (!isInCache || (identity.expiration().has_value() && (identity.expiration().value() - minutes(1) < Aws::Utils::DateTime::Now())) || !identity.expiration().has_value()) { + if (!isInCache || (identity.expiration().has_value() && (identity.expiration().value() - minutes(1) < Aws::Utils::DateTime::Now())) ) { identity = S3ExpressIdentityResolver::GetCredentialsFromBucket(bucketNameIter->second); - m_credentialsCache->Put(bucketNameIter->second, - identity, - std::chrono::milliseconds(identity.expiration().value().Millis() - Aws::Utils::DateTime::Now().Millis())); + if (identity.expiration().has_value()) { + m_credentialsCache->Put(bucketNameIter->second, + identity, + std::chrono::milliseconds(identity.expiration().value().Millis() - Aws::Utils::DateTime::Now().Millis())); + } } return identity; } @@ -171,11 +175,13 @@ AwsCredentialIdentity DefaultAsyncS3ExpressIdentityResolver::GetS3ExpressIdentit std::lock_guard lock(*GetMutexForBucketName(bucketNameIter->second)); AwsCredentialIdentity identity; auto isInCache = m_credentialsCache->Get(bucketNameIter->second, identity); - if (!isInCache || (identity.expiration().has_value() && (identity.expiration().value() - minutes(1) < Aws::Utils::DateTime::Now())) || !identity.expiration().has_value()) { + if (!isInCache || (identity.expiration().has_value() && (identity.expiration().value() - minutes(1) < Aws::Utils::DateTime::Now())) ) { identity = S3ExpressIdentityResolver::GetCredentialsFromBucket(bucketNameIter->second); - m_credentialsCache->Put(bucketNameIter->second, - identity, - std::chrono::milliseconds(identity.expiration().value().Millis() - Aws::Utils::DateTime::Now().Millis())); + if (identity.expiration().has_value()) { + m_credentialsCache->Put(bucketNameIter->second, + identity, + std::chrono::milliseconds(identity.expiration().value().Millis() - Aws::Utils::DateTime::Now().Millis())); + } } return identity; } diff --git a/src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClient.h b/src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClient.h index cf5c9bc446d..b6b4f7dd966 100644 --- a/src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClient.h +++ b/src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClient.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace smithy { namespace client @@ -80,7 +81,7 @@ namespace client } AwsSmithyClientT& operator=(const AwsSmithyClientT& other) - { + { if(this != &other) { AwsSmithyClientBase::deepCopy(Aws::MakeUnique(ServiceNameT, other.m_clientConfiguration), @@ -150,6 +151,20 @@ namespace client } } } + + //resolve endpoint once to fetch auth schemes + Aws::Endpoint::EndpointParameters epParams = ctx.m_pRequest ? ctx.m_pRequest->GetEndpointContextParams() : Aws::Endpoint::EndpointParameters(); + auto epResolutionOutcome = this->ResolveEndpoint(epParams, [](Aws::Endpoint::AWSEndpoint&){}); + if (epResolutionOutcome.IsSuccess()) + { + auto endpoint = std::move(epResolutionOutcome.GetResultWithOwnership()); + if (endpoint.GetAttributes()) + { + auto authSchemeName = endpoint.GetAttributes()->authScheme.GetName(); + identityParams.additionalProperties.insert({smithy::AUTH_SCHEME_PROPERTY, Aws::String(authSchemeName.c_str())}); + } + } + Aws::Vector authSchemeOptions = m_authSchemeResolver->resolveAuthScheme(identityParams); auto authSchemeOptionIt = std::find_if(authSchemeOptions.begin(), authSchemeOptions.end(), @@ -192,6 +207,7 @@ namespace client Aws::Http::HttpMethod method, const Aws::String& region, const Aws::String& serviceName, + const Aws::String& signerName, long long expirationInSeconds, const Aws::Http::HeaderValueCollection& customizedHeaders, const std::shared_ptr serviceSpecificParameters) const @@ -205,7 +221,7 @@ namespace client AwsSmithyClientAsyncRequestContext ctx; auto authSchemeOptionOutcome = SelectAuthSchemeOption( ctx); auto authSchemeOption = std::move(authSchemeOptionOutcome.GetResultWithOwnership()); - if (AwsClientRequestSigning::PreSignRequest(request, authSchemeOption, m_authSchemes, region, serviceName, expirationInSeconds).IsSuccess()) + if (AwsClientRequestSigning::PreSignRequest(request, authSchemeOption, m_authSchemes, region, serviceName, signerName, expirationInSeconds).IsSuccess()) { return request->GetURIString(); } @@ -223,8 +239,10 @@ namespace client const Aws::Http::URI& uri = endpoint.GetURI(); auto signerRegionOverride = region; auto signerServiceNameOverride = serviceName; - + //signer name is needed for some identity resolvers + Aws::String signerName = Aws::Auth::SIGV4_SIGNER; if (endpoint.GetAttributes()) { + signerName = endpoint.GetAttributes()->authScheme.GetName().empty() ? signerName : endpoint.GetAttributes()->authScheme.GetName(); if (endpoint.GetAttributes()->authScheme.GetSigningRegion()) { signerRegionOverride = endpoint.GetAttributes()->authScheme.GetSigningRegion()->c_str(); } @@ -235,8 +253,7 @@ namespace client signerServiceNameOverride = endpoint.GetAttributes()->authScheme.GetSigningName()->c_str(); } } - - return GeneratePresignedUrl(uri, method, signerRegionOverride, signerServiceNameOverride, expirationInSeconds, customizedHeaders, serviceSpecificParameters); + return GeneratePresignedUrl(uri, method, signerRegionOverride, signerServiceNameOverride, signerName, expirationInSeconds, customizedHeaders, serviceSpecificParameters); } protected: diff --git a/src/aws-cpp-sdk-core/include/smithy/client/common/AwsSmithyRequestSigning.h b/src/aws-cpp-sdk-core/include/smithy/client/common/AwsSmithyRequestSigning.h index cb80d98d4c7..83a06585b20 100644 --- a/src/aws-cpp-sdk-core/include/smithy/client/common/AwsSmithyRequestSigning.h +++ b/src/aws-cpp-sdk-core/include/smithy/client/common/AwsSmithyRequestSigning.h @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -61,6 +62,7 @@ namespace smithy const Aws::UnorderedMap& authSchemes, const Aws::String& region, const Aws::String& serviceName, + const Aws::String& signerName, long long expirationTimeInSeconds) { @@ -76,7 +78,7 @@ namespace smithy const AuthSchemesVariantT& authScheme = authSchemeIt->second; - PreSignerVisitor visitor(httpRequest, authSchemeOption, region, serviceName, expirationTimeInSeconds); + PreSignerVisitor visitor(httpRequest, authSchemeOption, region, serviceName, signerName, expirationTimeInSeconds); AuthSchemesVariantT authSchemesVariantCopy(authScheme); authSchemesVariantCopy.Visit(visitor); @@ -184,11 +186,13 @@ namespace smithy const AuthSchemeOption& targetAuthSchemeOption, const Aws::String& region, const Aws::String& serviceName, + const Aws::String& signerName, long long expirationTimeInSeconds) : m_httpRequest(std::move(httpRequest)), m_targetAuthSchemeOption(targetAuthSchemeOption) , m_region(region), m_serviceName(serviceName), + m_signerName(signerName), m_expirationTimeInSeconds(expirationTimeInSeconds) {} @@ -196,6 +200,7 @@ namespace smithy const AuthSchemeOption& m_targetAuthSchemeOption; const Aws::String& m_region; const Aws::String& m_serviceName; + const Aws::String& m_signerName; const long long m_expirationTimeInSeconds; Aws::Crt::Optional result; @@ -216,8 +221,13 @@ namespace smithy return; } + Aws::UnorderedMap> additonalIdentityProperties; + if(!m_signerName.empty()) { + additonalIdentityProperties.emplace(smithy::AUTH_SCHEME_PROPERTY,Aws::Crt::Variant{m_signerName} ); + } + auto identityResult = - identityResolver->getIdentity(m_targetAuthSchemeOption.identityProperties(), m_targetAuthSchemeOption.identityProperties()); + identityResolver->getIdentity(m_targetAuthSchemeOption.identityProperties(), additonalIdentityProperties); if (!identityResult.IsSuccess()) { result.emplace(identityResult.GetError()); diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/auth/AuthSchemeOption.h b/src/aws-cpp-sdk-core/include/smithy/identity/auth/AuthSchemeOption.h index 6fe5f8b6be4..f9a286efe29 100644 --- a/src/aws-cpp-sdk-core/include/smithy/identity/auth/AuthSchemeOption.h +++ b/src/aws-cpp-sdk-core/include/smithy/identity/auth/AuthSchemeOption.h @@ -25,13 +25,17 @@ namespace smithy { PropertyBag virtual identityProperties() const { return m_identityProperties; }; PropertyBag virtual signerProperties() const { return m_signerProperties; }; - bool addIdentityProperty( const Aws::String& key,const Aws::Crt::Variant& value) { + void putIdentityProperty( const Aws::String& key,const Aws::Crt::Variant& value) { auto it = m_identityProperties.emplace(key, value); - return it.second; + if(!it.second) { + it.first->second = value; + } }; - bool addSignerProperty( const Aws::String& key,const Aws::Crt::Variant& value) { + void putSignerProperty( const Aws::String& key,const Aws::Crt::Variant& value) { auto it = m_signerProperties.emplace(key, value); - return it.second; + if(!it.second) { + it.first->second = value; + } }; EndpointParameters virtual endpointParameters() const { return EndpointParameters{}; }; diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/S3ExpressSigV4AuthScheme.h b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/S3ExpressSigV4AuthScheme.h new file mode 100644 index 00000000000..754aa43f81b --- /dev/null +++ b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/S3ExpressSigV4AuthScheme.h @@ -0,0 +1,88 @@ +/** +* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include +#include +#include +#include +#include + + + +namespace smithy { + constexpr char SIGV4_EXPRESS[] = "sigv4-s3express"; + + class S3ExpressSigV4AuthScheme : public AuthScheme + { + public: + using AwsCredentialIdentityResolverT = IdentityResolverBase; + using AwsCredentialSignerT = AwsSignerBase; + using S3ExpressSigV4AuthSchemeParameters = DefaultAuthSchemeResolverParameters; + + //This allows to override the identity resolver + explicit S3ExpressSigV4AuthScheme(std::shared_ptr identityResolver, + const Aws::String& serviceName, + const Aws::String& region) + : AuthScheme(SIGV4_EXPRESS), + m_identityResolver{identityResolver}, + m_signer{Aws::MakeShared>("S3ExpressSigV4AuthScheme", serviceName, region)} + { + assert(m_identityResolver); + assert(m_signer); + } + + //delegate constructor + explicit S3ExpressSigV4AuthScheme(std::shared_ptr identityResolver, + const Aws::String& serviceName, + const Aws::String& region, + Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy policy, + bool urlEscapePath) + : AuthScheme(SIGV4_EXPRESS), + m_identityResolver{identityResolver}, + m_signer{Aws::MakeShared>("S3ExpressSigV4AuthScheme", serviceName, region, policy, urlEscapePath)} + { + assert(m_identityResolver); + assert(m_signer); + } + + //delegate constructor + explicit S3ExpressSigV4AuthScheme(const Aws::String& serviceName, + const Aws::String& region) + : S3ExpressSigV4AuthScheme(Aws::MakeShared("S3ExpressSigV4AuthScheme"), + serviceName, + region) + { + } + + //For legacy constructors, signing requires additonal input parameters + explicit S3ExpressSigV4AuthScheme(const Aws::String& serviceName, + const Aws::String& region, + Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy policy, + bool urlEscapePath) + : S3ExpressSigV4AuthScheme(Aws::MakeShared("S3ExpressSigV4AuthScheme"), + serviceName, + region, + policy, + urlEscapePath) + { + } + + virtual ~S3ExpressSigV4AuthScheme() = default; + + std::shared_ptr identityResolver() override + { + return m_identityResolver; + } + + std::shared_ptr signer() override + { + return m_signer; + } + protected: + std::shared_ptr m_identityResolver; + std::shared_ptr m_signer; + }; +} diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/S3ExpressSigV4AuthSchemeOption.h b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/S3ExpressSigV4AuthSchemeOption.h new file mode 100644 index 00000000000..f7d1dab9a5d --- /dev/null +++ b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/S3ExpressSigV4AuthSchemeOption.h @@ -0,0 +1,15 @@ +/** +* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include +#include + +namespace smithy { + struct S3ExpressSigV4AuthSchemeOption + { + static SMITHY_API AuthSchemeOption s3ExpressSigV4AuthSchemeOption; + }; +} \ No newline at end of file diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/SigV4MultiAuthResolver.h b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/SigV4MultiAuthResolver.h new file mode 100644 index 00000000000..b6d10c50dc9 --- /dev/null +++ b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/SigV4MultiAuthResolver.h @@ -0,0 +1,45 @@ +/** +* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace smithy { + template + class SigV4MultiAuthSchemeResolver : public AuthSchemeResolverBase + { + public: + using ServiceAuthSchemeParameters = ServiceAuthSchemeParametersT; + virtual ~SigV4MultiAuthSchemeResolver() = default; + + Aws::Vector resolveAuthScheme(const ServiceAuthSchemeParameters& identityProperties) override + { + //use resolved endpoint params to return + auto authSchemeNameIt = identityProperties.additionalProperties.find(smithy::AUTH_SCHEME_PROPERTY); + if(authSchemeNameIt != identityProperties.additionalProperties.end()) + { + auto authSchemeName = authSchemeNameIt->second.template get().c_str(); + if(strcmp(authSchemeName,Aws::Auth::ASYMMETRIC_SIGV4_SIGNER) == 0) + { + return {SigV4aAuthSchemeOption::sigV4aAuthSchemeOption}; + } + else if(strcmp(authSchemeName,Aws::Auth::SIGV4_SIGNER) == 0) + { + return {SigV4AuthSchemeOption::sigV4AuthSchemeOption}; + } + else if(strcmp(authSchemeName,smithy::S3_EXPRESS_SIGNER_NAME) == 0) + { + return {S3ExpressSigV4AuthSchemeOption::s3ExpressSigV4AuthSchemeOption}; + } + } + return {SigV4AuthSchemeOption::sigV4AuthSchemeOption}; + } + }; +} \ No newline at end of file diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/SigV4aAuthScheme.h b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/SigV4aAuthScheme.h index 05bd83e8fb0..9d7b7cbd9e4 100644 --- a/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/SigV4aAuthScheme.h +++ b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/SigV4aAuthScheme.h @@ -41,10 +41,16 @@ namespace smithy { : SigV4aAuthScheme(Aws::MakeShared("SigV4aAuthScheme"), serviceName, region) { assert(m_identityResolver); - assert(m_signer); } + //legacy constructors + explicit SigV4aAuthScheme(std::shared_ptr identityResolver, const Aws::String& serviceName, const Aws::String& region, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy policy, bool urlEscape) + : AuthScheme(SIGV4A), + m_identityResolver{identityResolver}, + m_signer{Aws::MakeShared("SigV4aAuthScheme", serviceName, region, policy, urlEscape)}{} + + /* for some services, there can be a different variant of v4 signer. This constructor allows to specify the signer type abiding by the constraints of the authscheme diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/S3ExpressSigner.h b/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/S3ExpressSigner.h index 9fdb6754725..4e1a6759ab5 100644 --- a/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/S3ExpressSigner.h +++ b/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/S3ExpressSigner.h @@ -13,6 +13,7 @@ namespace smithy { static const char *S3_EXPRESS_HEADER = "x-amz-s3session-token"; static const char *S3_EXPRESS_QUERY_PARAM = "X-Amz-S3session-Token"; + static const char *S3_EXPRESS_SIGNER_NAME = "S3ExpressSigner"; template struct IsValidS3ExpressSigner : std::false_type {}; @@ -23,7 +24,7 @@ namespace smithy { template <> struct IsValidS3ExpressSigner : std::true_type {}; - //Ensuring S3 Express Signer can be derived from Sigv4 and Sigv4a variants + //Ensuring S3 Express Signer can use Sigv4 or Sigv4a signing algorithm template class S3ExpressSigner : public std::enable_if::value, BASECLASS>::type { @@ -32,29 +33,24 @@ namespace smithy { using SigningProperties = typename BASECLASS::SigningProperties; using SigningError = typename BASECLASS::SigningError; explicit S3ExpressSigner(const Aws::String& serviceName, const Aws::String& region) - : BASECLASS(serviceName, region),legacySigner(nullptr, serviceName.c_str(), region, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Always) + : BASECLASS(serviceName, region) { } - explicit S3ExpressSigner(const Aws::String& serviceName, const Aws::String& region, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy policy) - : BASECLASS(serviceName, region, policy),legacySigner(nullptr, serviceName.c_str(), region, policy) + explicit S3ExpressSigner(const Aws::String& serviceName, const Aws::String& region, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy policy, bool escapeUrl) + : BASECLASS(serviceName, region, policy, escapeUrl) { } - SigningFutureOutcome sign(std::shared_ptr httpRequest, const AwsCredentialIdentityBase& identity, SigningProperties properties) override + SigningFutureOutcome sign(std::shared_ptr httpRequest, const AwsCredentialIdentityBase& identity, SigningProperties properties) override { //if legacy signer, ie if signer name not s3express auto signerNameOverride = properties.find("signerName"); - if(signerNameOverride != properties.end() ) + //check for region, service name override + if(signerNameOverride != properties.end() && signerNameOverride->second.template get() != S3_EXPRESS_SIGNER_NAME) { - std::cout<<"signerNameOverride="<second.template get()<second.template get() != "S3ExpressSigner") - { - return AwsSigV4Signer::sign(httpRequest, identity, properties); - } - const auto requestId = Aws::GetWithDefault(httpRequest->GetServiceSpecificParameters()->parameterMap, Aws::String("dedupeId"), Aws::String(Aws::Utils::UUID::RandomUUID())); @@ -69,12 +65,12 @@ namespace smithy { } putRequestId(requestId); httpRequest->SetHeaderValue(S3_EXPRESS_HEADER, identity.sessionToken().value()); - auto isSigned = AwsSigV4Signer::sign(httpRequest, identity, properties); + auto isSigned = BASECLASS::sign(httpRequest, identity, properties); deleteRequestId(requestId); return SigningFutureOutcome(std::move(httpRequest)); } - SigningFutureOutcome presign(std::shared_ptr httpRequest, const AwsCredentialIdentityBase& identity, SigningProperties properties, const Aws::String& region, const Aws::String& serviceName, long long expirationTimeInSeconds) override + SigningFutureOutcome presign(std::shared_ptr httpRequest, const AwsCredentialIdentityBase& identity, SigningProperties properties, const Aws::String& region, const Aws::String& serviceName, long long expirationTimeInSeconds) override { const auto requestId = Aws::GetWithDefault(httpRequest->GetServiceSpecificParameters()->parameterMap, Aws::String("dedupeId"), @@ -89,7 +85,7 @@ namespace smithy { } putRequestId(requestId); httpRequest->AddQueryStringParameter(S3_EXPRESS_QUERY_PARAM, identity.sessionToken().value()); - auto isSigned = AwsSigV4Signer::presign(httpRequest, identity, properties, region, serviceName, expirationTimeInSeconds); + auto isSigned = BASECLASS::presign(httpRequest, identity, properties, region, serviceName, expirationTimeInSeconds); deleteRequestId(requestId); return SigningFutureOutcome(std::move(httpRequest)); @@ -112,8 +108,6 @@ namespace smithy { } mutable std::set m_requestsProcessing; - mutable std::mutex m_requestProcessing; - Aws::Client::AWSAuthV4Signer legacySigner; - + mutable std::mutex m_requestProcessing; }; } diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SigV4Signer.h b/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SigV4Signer.h index b5b80166ff3..5799770d44e 100644 --- a/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SigV4Signer.h +++ b/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SigV4Signer.h @@ -50,13 +50,18 @@ namespace smithy { return {identity.accessKeyId(), identity.secretAccessKey()}; }(); - - auto signPayloadIt = properties.find("SignPayload"); bool signPayload = signPayloadIt != properties.end() ? signPayloadIt->second.get() == "true" : false; + auto signerRegionOverrideIt = properties.find("signerRegionOverride"); + auto region = signerRegionOverrideIt != properties.end() ? signerRegionOverrideIt->second.get().c_str() : m_region.c_str(); + + auto signerServiceNameOverrideIt = properties.find("signerServiceNameOverride"); + auto svcName = signerServiceNameOverrideIt != properties.end() ? signerServiceNameOverrideIt->second.get().c_str() : m_serviceName.c_str(); + + assert(httpRequest); - bool success = legacySigner.SignRequestWithCreds(*httpRequest, legacyCreds, m_region.c_str(), m_serviceName.c_str(), (signPayload || true )); + bool success = legacySigner.SignRequestWithCreds(*httpRequest, legacyCreds, region, svcName, signPayload); if (success) { return SigningFutureOutcome(std::move(httpRequest)); diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SigV4aSigner.h b/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SigV4aSigner.h index 675ed5b5a72..f1e2f8417e5 100644 --- a/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SigV4aSigner.h +++ b/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SigV4aSigner.h @@ -43,15 +43,21 @@ namespace smithy { { } + explicit AwsSigV4aSigner(const Aws::String& serviceName, const Aws::String& region, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy policy, bool urlEscape) + : m_serviceName(serviceName), m_region(region), m_policy(Aws::MakeShared("AwsSigV4aSigner", policy)), m_urlEscape{urlEscape} + { + } + SigningFutureOutcome sign(std::shared_ptr httpRequest, const AwsCredentialIdentityBase& identity, SigningProperties properties) override { - return sign(httpRequest, identity, properties, m_region, m_serviceName, m_expirationTimeInSeconds); + return sign(httpRequest, identity, properties, m_region, m_serviceName, m_expirationTimeInSeconds, Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders); } SigningFutureOutcome presign(std::shared_ptr httpRequest, const AwsCredentialIdentityBase& identity, SigningProperties properties, const Aws::String& region, const Aws::String& serviceName, long long expirationTimeInSeconds) override { Aws::String signingRegion = !region.empty() ? region : m_region; Aws::String signingServiceName = !serviceName.empty() ? serviceName : m_serviceName; + Aws::Crt::Auth::SignatureType signatureType = Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams; const auto credentials = [&identity]() -> Aws::Auth::AWSCredentials { if(identity.sessionToken().has_value() && identity.expiration().has_value()) @@ -70,7 +76,7 @@ namespace smithy { { return SigningFutureOutcome(std::move(httpRequest)) ; } - return sign(httpRequest, identity, properties, signingRegion, signingServiceName, expirationTimeInSeconds); + return sign(httpRequest, identity, properties, signingRegion, signingServiceName, expirationTimeInSeconds, signatureType); } virtual ~AwsSigV4aSigner() {}; @@ -78,14 +84,17 @@ namespace smithy { bool createAwsSigningConfig( std::shared_ptr& crtCredentials, - const Aws::Http::HttpRequest& request, + const Aws::Http::HttpRequest& request, + const Aws::String& serviceName, + const Aws::String& region, Aws::Crt::Auth::AwsSigningConfig& awsSigningConfig, - bool signBody) const + bool signBody, + Aws::Crt::Auth::SignatureType signatureType) const { awsSigningConfig.SetSigningAlgorithm(static_cast(Aws::Auth::AWSSigningAlgorithm::ASYMMETRIC_SIGV4)); - awsSigningConfig.SetSignatureType(m_signatureType); - awsSigningConfig.SetRegion(m_region.c_str()); - awsSigningConfig.SetService(m_region.c_str()); + awsSigningConfig.SetSignatureType(signatureType); + awsSigningConfig.SetRegion(serviceName.c_str()); + awsSigningConfig.SetService(region.c_str()); awsSigningConfig.SetSigningTimepoint(GetSigningTimestamp().UnderlyingTimestamp()); awsSigningConfig.SetUseDoubleUriEncode(m_urlEscape); awsSigningConfig.SetShouldNormalizeUriPath(true); @@ -96,7 +105,7 @@ namespace smithy { Aws::String headerKey(reinterpret_cast(name->ptr), name->len); return unsignedHeaders->find(Aws::Utils::StringUtils::ToLower(headerKey.c_str())) == unsignedHeaders->cend(); }); - if (m_signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders) + if (signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders) { Aws::String payloadHash(UNSIGNED_PAYLOAD); if(signBody || request.GetUri().GetScheme() != Aws::Http::Scheme::HTTPS) @@ -120,9 +129,9 @@ namespace smithy { 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) + else if (signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams) { - if (ServiceRequireUnsignedPayload(m_serviceName)) + if (ServiceRequireUnsignedPayload(serviceName)) { awsSigningConfig.SetSignedBodyValue(UNSIGNED_PAYLOAD); } @@ -142,16 +151,43 @@ namespace smithy { } - SigningFutureOutcome sign(std::shared_ptr httpRequest, const AwsCredentialIdentityBase& identity, SigningProperties properties, const Aws::String& regionOverride, const Aws::String& serviceName, long long expirationTimeInSeconds) + SigningFutureOutcome sign(std::shared_ptr httpRequest, const AwsCredentialIdentityBase& identity, SigningProperties properties, const Aws::String& region, const Aws::String& svcName, long long expirationTimeInSeconds, + Aws::Crt::Auth::SignatureType signatureType) { + assert(httpRequest); + assert(identity.expiration().has_value()); + + 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() == "true" : false; - assert(httpRequest); - assert(identity.expiration().has_value()); + auto signerRegionOverrideIt = properties.find("signerRegionOverride"); + auto regionOverride = signerRegionOverrideIt != properties.end() ? signerRegionOverrideIt->second.get().c_str() : region.c_str(); + + auto signerServiceNameOverrideIt = properties.find("signerServiceNameOverride"); + auto serviceName = signerServiceNameOverrideIt != properties.end() ? signerServiceNameOverrideIt->second.get().c_str() : svcName.c_str(); auto &request = *httpRequest; + + //don't sign anonymous requests + if (legacyCreds.GetAWSAccessKeyId().empty() || legacyCreds.GetAWSSecretKey().empty()) + { + return SigningFutureOutcome(std::move(httpRequest)); + } + + httpRequest->SetSigningAccessKey(legacyCreds.GetAWSAccessKeyId()); + httpRequest->SetSigningRegion(regionOverride); auto crtCredentials = Aws::MakeShared(v4AsymmetricLogTag, Aws::Crt::ByteCursorFromCString(identity.accessKeyId().c_str()), @@ -161,7 +197,7 @@ namespace smithy { Aws::Crt::Auth::AwsSigningConfig awsSigningConfig; - bool success = createAwsSigningConfig(crtCredentials, request, awsSigningConfig, signPayload); + bool success = createAwsSigningConfig(crtCredentials, request, serviceName, regionOverride, awsSigningConfig, signPayload, signatureType); if(!success) { @@ -170,8 +206,8 @@ namespace smithy { return SigningError(Aws::Client::CoreErrors::MEMORY_ALLOCATION, "", "Failed to get Auth configuration", false); } - awsSigningConfig.SetRegion(regionOverride.c_str()); - awsSigningConfig.SetService(serviceName.c_str()); + awsSigningConfig.SetRegion(regionOverride); + awsSigningConfig.SetService(serviceName); awsSigningConfig.SetExpirationInSeconds(expirationTimeInSeconds); std::shared_ptr crtHttpRequest = request.ToCrtHttpRequest(); @@ -182,13 +218,13 @@ namespace smithy { bool processed = false; //producer function sigv4HttpRequestSigner->SignRequest(crtHttpRequest, awsSigningConfig, - [&request, &success, &errorMessage, &processed, this](const std::shared_ptr& signedCrtHttpRequest, int errorCode) { + [&request, &success, &errorMessage, &processed, this, signatureType](const std::shared_ptr& signedCrtHttpRequest, int errorCode) { std::unique_lock lock(m_mutex); m_cv.wait(lock, [&]{ return !processed; }); success = (errorCode == AWS_ERROR_SUCCESS); if (success) { - if (m_signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders) + if (signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders) { for (size_t i = 0; i < signedCrtHttpRequest->GetHeaderCount(); i++) { @@ -197,7 +233,7 @@ namespace smithy { Aws::String(reinterpret_cast(httpHeader->value.ptr), httpHeader->value.len)); } } - else if (m_signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams) + else if (signatureType == Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams) { Aws::Http::URI newPath(reinterpret_cast(signedCrtHttpRequest->GetPath()->ptr)); request.GetUri().SetQueryString(newPath.GetQueryString()); @@ -252,7 +288,7 @@ namespace smithy { const bool m_includeSha256HashHeader{true}; const bool m_urlEscape{true}; const Aws::Set m_unsignedHeaders{USER_AGENT,X_AMZN_TRACE_ID}; - const Aws::Crt::Auth::SignatureType m_signatureType{Aws::Crt::Auth::SignatureType::HttpRequestViaQueryParams}; + const Aws::Crt::Auth::SignatureType m_signatureType{Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders}; std::condition_variable m_cv; std::mutex m_mutex; }; diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SignerProperties.h b/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SignerProperties.h new file mode 100644 index 00000000000..7e611a305d4 --- /dev/null +++ b/src/aws-cpp-sdk-core/include/smithy/identity/signer/built-in/SignerProperties.h @@ -0,0 +1,11 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +namespace smithy { + static const char *AUTH_SCHEME_PROPERTY = "signerName"; + static const char *SIGNER_REGION_PROPERTY = "signerRegionOverride"; + static const char *SIGNER_SERVICE_NAME_ = "signerServiceNameOverride"; +} diff --git a/src/aws-cpp-sdk-core/source/auth/signer/AWSAuthV4Signer.cpp b/src/aws-cpp-sdk-core/source/auth/signer/AWSAuthV4Signer.cpp index 47d1109cadf..a09a2f973c8 100644 --- a/src/aws-cpp-sdk-core/source/auth/signer/AWSAuthV4Signer.cpp +++ b/src/aws-cpp-sdk-core/source/auth/signer/AWSAuthV4Signer.cpp @@ -51,6 +51,7 @@ namespace Aws { const char SIGV4_SIGNER[] = "SignatureV4"; const char ASYMMETRIC_SIGV4_SIGNER[] = "AsymmetricSignatureV4"; + static const char *S3_EXPRESS_HEADER = "x-amz-s3session-token"; } } @@ -209,7 +210,8 @@ bool AWSAuthV4Signer::SignRequestWithCreds(Aws::Http::HttpRequest& request, cons 0 /* expirationTimeInSeconds doesn't matter for HttpRequestViaHeaders */, Aws::Crt::Auth::SignatureType::HttpRequestViaHeaders); } - if (!credentials.GetSessionToken().empty()) + //additional check is needed for s3 header since this is invoked by s3 signer + if (!credentials.GetSessionToken().empty() && !request.HasHeader(S3_EXPRESS_HEADER)) { request.SetAwsSessionToken(credentials.GetSessionToken()); } diff --git a/src/aws-cpp-sdk-core/source/smithy/client/AwsSmithyClientBase.cpp b/src/aws-cpp-sdk-core/source/smithy/client/AwsSmithyClientBase.cpp index 2073829208e..71409bae15d 100644 --- a/src/aws-cpp-sdk-core/source/smithy/client/AwsSmithyClientBase.cpp +++ b/src/aws-cpp-sdk-core/source/smithy/client/AwsSmithyClientBase.cpp @@ -19,6 +19,9 @@ #include "smithy/tracing/TracingUtils.h" #include #include +#include +#include + using namespace smithy::client; using namespace smithy::interceptor; using namespace smithy::components::tracing; @@ -193,34 +196,20 @@ void AwsSmithyClientBase::MakeRequestAsync(Aws::AmazonWebServiceRequest const* c auto epResolutionOutcome = this->ResolveEndpoint(std::move(epParams), std::move(endpointCallback)); if (!epResolutionOutcome.IsSuccess()) { - pExecutor->Submit([epResolutionOutcome, responseHandler]() mutable + auto epOutcome = ResolveEndpointOutcome(Aws::Client::AWSError{ + Aws::Client::CoreErrors::ENDPOINT_RESOLUTION_FAILURE, + epResolutionOutcome.GetError().GetExceptionName(), + epResolutionOutcome.GetError().GetMessage(), + false}); + + pExecutor->Submit([epOutcome, responseHandler]() mutable { - responseHandler(std::move(epResolutionOutcome)); + responseHandler(std::move(epOutcome)); } ); return; } pRequestCtx->m_endpoint = std::move(epResolutionOutcome.GetResultWithOwnership()); - - //get signer Name from end point and pass this info - if (pRequestCtx->m_endpoint.GetAttributes()) { - auto signerName = pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetName(); - pRequestCtx->m_authSchemeOption.addIdentityProperty("signerName", Aws::Crt::Variant(signerName)); - pRequestCtx->m_authSchemeOption.addSignerProperty("signerName", Aws::Crt::Variant(signerName)); - if (pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningRegion()) { - auto signerRegionOverride = pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningRegion(); - pRequestCtx->m_authSchemeOption.addSignerProperty("signerRegionOverride", Aws::Crt::Variant(Aws::String(signerRegionOverride->c_str()))); - } - if (pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) { - auto signerRegionOverride = pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningRegionSet(); - pRequestCtx->m_authSchemeOption.addSignerProperty("signerRegionOverride", Aws::Crt::Variant(Aws::String(signerRegionOverride->c_str()))); - } - if (pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningName()) { - auto signerServiceNameOverride = pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningName(); - pRequestCtx->m_authSchemeOption.addSignerProperty("signerServiceNameOverride", Aws::Crt::Variant(Aws::String(signerServiceNameOverride->c_str()))); - } - } - if (!Aws::Utils::IsValidHost(pRequestCtx->m_endpoint.GetURI().GetAuthority())) { AWS_LOGSTREAM_ERROR(AWS_SMITHY_CLIENT_LOG, "Invalid DNS Label found in URI host"); @@ -249,6 +238,26 @@ void AwsSmithyClientBase::AttemptOneRequestAsync(std::shared_ptrm_responseHandler; auto pExecutor = pRequestCtx->m_pExecutor; + //get signer Name from end point and pass this info + //This is extracted here so that on retry with correct region, signer region override is honored + if (pRequestCtx->m_endpoint.GetAttributes()) { + auto signerName = pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetName(); + pRequestCtx->m_authSchemeOption.putIdentityProperty("signerName", Aws::Crt::Variant(signerName)); + pRequestCtx->m_authSchemeOption.putSignerProperty("signerName", Aws::Crt::Variant(signerName)); + if (pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningRegion()) { + auto signerRegionOverride = pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningRegion(); + pRequestCtx->m_authSchemeOption.putSignerProperty("signerRegionOverride", Aws::Crt::Variant(Aws::String(signerRegionOverride->c_str()))); + } + if (pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningRegionSet()) { + auto signerRegionOverride = pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningRegionSet(); + pRequestCtx->m_authSchemeOption.putSignerProperty("signerRegionOverride", Aws::Crt::Variant(Aws::String(signerRegionOverride->c_str()))); + } + if (pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningName()) { + auto signerServiceNameOverride = pRequestCtx->m_endpoint.GetAttributes()->authScheme.GetSigningName(); + pRequestCtx->m_authSchemeOption.putSignerProperty("signerServiceNameOverride", Aws::Crt::Variant(Aws::String(signerServiceNameOverride->c_str()))); + } + } + TracingUtils::MakeCallWithTiming( [&]() -> void { pRequestCtx->m_httpRequest = BuildHttpRequest(pRequestCtx, pRequestCtx->m_endpoint.GetURI(), pRequestCtx->m_method); @@ -516,7 +525,7 @@ void AwsSmithyClientBase::HandleAsyncReply(std::shared_ptrExtractEndpoint(outcome.GetError()); - if (newEndpoint.empty()) { + if (!newEndpoint.empty()) { Aws::Http::URI newUri = pRequestCtx->m_endpoint.GetURI(); newUri.SetAuthority(newEndpoint); pRequestCtx->m_endpoint.SetURI(newUri); diff --git a/src/aws-cpp-sdk-core/source/smithy/identity/AuthSchemeOption.cpp b/src/aws-cpp-sdk-core/source/smithy/identity/AuthSchemeOption.cpp index 354f61254ca..3a36ee1a35d 100644 --- a/src/aws-cpp-sdk-core/source/smithy/identity/AuthSchemeOption.cpp +++ b/src/aws-cpp-sdk-core/source/smithy/identity/AuthSchemeOption.cpp @@ -4,8 +4,10 @@ */ #include #include - +#include using namespace smithy; AuthSchemeOption SigV4AuthSchemeOption::sigV4AuthSchemeOption = AuthSchemeOption("aws.auth#sigv4"); -AuthSchemeOption SigV4aAuthSchemeOption::sigV4aAuthSchemeOption = AuthSchemeOption("aws.auth#sigv4a"); \ No newline at end of file +AuthSchemeOption SigV4aAuthSchemeOption::sigV4aAuthSchemeOption = AuthSchemeOption("aws.auth#sigv4a"); +AuthSchemeOption S3ExpressSigV4AuthSchemeOption::s3ExpressSigV4AuthSchemeOption = AuthSchemeOption("sigv4-s3express"); + diff --git a/tests/aws-cpp-sdk-core-tests/smithy/client/SmithyClientTest.cpp b/tests/aws-cpp-sdk-core-tests/smithy/client/SmithyClientTest.cpp index 32e6bb80fb6..bcffb8115c6 100644 --- a/tests/aws-cpp-sdk-core-tests/smithy/client/SmithyClientTest.cpp +++ b/tests/aws-cpp-sdk-core-tests/smithy/client/SmithyClientTest.cpp @@ -305,7 +305,7 @@ TEST_F(SmithyClientTest, testSigV4a) { EXPECT_EQ(res2.IsSuccess(), true); - EXPECT_TRUE(res2.GetResult()->GetSigningAccessKey().empty()); + EXPECT_TRUE(!res2.GetResult()->GetSigningAccessKey().empty()); EXPECT_FALSE(res2.GetResult()->GetUri().GetURIString(true).empty()); diff --git a/tests/aws-cpp-sdk-s3-integration-tests/BucketAndObjectOperationTest.cpp b/tests/aws-cpp-sdk-s3-integration-tests/BucketAndObjectOperationTest.cpp index 29238b284ff..4d51153bcbb 100644 --- a/tests/aws-cpp-sdk-s3-integration-tests/BucketAndObjectOperationTest.cpp +++ b/tests/aws-cpp-sdk-s3-integration-tests/BucketAndObjectOperationTest.cpp @@ -2603,63 +2603,4 @@ namespace AWS_EXPECT_SUCCESS(headOutcome); EXPECT_EQ(headOutcome.GetResult().GetContentEncoding(), "gzip"); } - - -void DownloadFile(const Aws::String& bucket_name, const Aws::String& object_key, const Aws::String& destination_file) -{ - auto Limiter = Aws::MakeShared>(ALLOCATION_TAG, 50000000); - - ClientConfiguration config; - config.region = Aws::Region::US_WEST_2; - config.scheme = Scheme::HTTPS; - config.connectTimeoutMs = 30000; - config.requestTimeoutMs = 30000; - config.readRateLimiter = Limiter; - config.writeRateLimiter = Limiter; - config.executor = Aws::MakeShared(ALLOCATION_TAG, 4); - config.enableHttpClientTrace = true; - - Aws::S3::S3Client s3_client(config); - - - // Open the destination file for writing - std::ofstream output_file(destination_file.c_str(), std::ios::binary); - - if (!output_file) { - std::cerr << "Failed to open destination file." << std::endl; - return; - } - - // Create a GetObjectRequest with the byte range - Aws::S3::Model::GetObjectRequest get_object_request; - get_object_request.SetBucket(bucket_name); - get_object_request.SetKey(object_key); - auto start = std::chrono::high_resolution_clock::now(); - auto get_object_outcome = s3_client.GetObject(get_object_request); - auto stop = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(stop - start); - - if (get_object_outcome.IsSuccess()) { - // Write the part to the destination file - auto& retrieved_file = get_object_outcome.GetResultWithOwnership().GetBody(); - std::ofstream output_file(destination_file, std::ios::binary); - output_file << retrieved_file.rdbuf(); // Write the stream content to the file - std::cout << "File downloaded to " << destination_file << std::endl; - - } else { - std::cerr << "Failed to download file: " << get_object_outcome.GetError().GetMessage() << std::endl; - } - - std::cout<<"took "< SchemeIdMapping = ImmutableMap.of( "aws.auth#sigv4", "smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption", - "aws.auth#sigv4a", "smithy::SigV4AuthSchemeOption::sigV4aAuthSchemeOption", + "aws.auth#sigv4a", "smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption", "bearer", "smithy::BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption", - "v4", "smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption" + "v4", "smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption", + "sigv4-s3express", "smithy::S3ExpressSigV4AuthSchemeOption::s3ExpressSigV4AuthSchemeOption" ); private static final Map ResolverMapping = ImmutableMap.of( diff --git a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/generators/cpp/s3/S3RestXmlCppClientGenerator.java b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/generators/cpp/s3/S3RestXmlCppClientGenerator.java index a6646e86548..a7605db2571 100644 --- a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/generators/cpp/s3/S3RestXmlCppClientGenerator.java +++ b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/generators/cpp/s3/S3RestXmlCppClientGenerator.java @@ -450,7 +450,7 @@ protected SdkFileEntry generateClientHeaderFile(final ServiceModel serviceModel) } VelocityContext context = createContext(serviceModel); context.put("CppViewHelper", CppViewHelper.class); - context.put("AuthSchemeResolver", "SigV4AuthSchemeResolver"); + context.put("AuthSchemeResolver", "SigV4MultiAuthSchemeResolver"); context.put("AuthSchemeVariants", serviceModel.getAuthSchemes().stream().map(this::mapAuthSchemes).collect(Collectors.joining(","))); @@ -481,7 +481,7 @@ protected List generateClientSourceFile(final List s VelocityContext context = createContext(serviceModels.get(i)); context.put("CppViewHelper", CppViewHelper.class); context.put("TemplateOverride", templateOverride); - context.put("AuthSchemeResolver", "SigV4AuthSchemeResolver"); + context.put("AuthSchemeResolver", "SigV4MultiAuthSchemeResolver"); context.put("AuthSchemeMapEntries", createAuthSchemeMapEntries(serviceModels.get(i))); final String fileName; diff --git a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java index 396f0f37d77..b890c35e8bc 100644 --- a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java +++ b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java @@ -18,6 +18,8 @@ import com.google.common.collect.ImmutableSet; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import lombok.Data; import lombok.Value; @@ -26,6 +28,8 @@ import java.util.*; import java.util.stream.Collectors; import software.amazon.smithy.jmespath.JmespathExpression; +import com.google.gson.JsonParser; + public class C2jModelToGeneratorModelTransformer { @@ -146,6 +150,100 @@ public C2jModelToGeneratorModelTransformer(C2jServiceModel c2jServiceModel, bool this.standalone = standalone; } + //dfs + protected static void findNestedField(JsonElement element, String targetField, List results) { + if (element == null || element.isJsonNull()) { + return; + } + + if (element.isJsonObject()) { + JsonObject obj = element.getAsJsonObject(); + + if (obj.has(targetField)) { + JsonElement targetElement = obj.get(targetField); + + results.add(targetElement); + //assumption is target field wont contain internal target fields + return; + } + + //recurse + obj.entrySet().stream().forEach(entry -> { + findNestedField(entry.getValue(), targetField, results); + }); + + } else if (element.isJsonArray()) { + element.getAsJsonArray().forEach(entry -> + { + findNestedField(entry, targetField, results); + }); + } + } + + protected void updateAuthSchemesFromEndpointRules(ServiceModel serviceModel, String rawjson) + { + Set authSchemeSet = new HashSet<>(serviceModel.getAuthSchemes()); + + // parse the JSON into a JsonElement tree + JsonElement jsonElement = JsonParser.parseString(rawjson); + + // search for the "authSchemes" field in endpoint rules recursively to get all authschemes + List authSchemes = new ArrayList<>(); + findNestedField(jsonElement, "authSchemes", authSchemes); + // extract authschemes + authSchemes.stream() + .filter(entry -> entry.isJsonArray()) // check if the element is a JsonArray + .map(JsonElement::getAsJsonArray) // convert to JsonArray + .forEach(arrelem -> { + arrelem.forEach(entry -> { // iterate over each element in the JsonArray + // array element with key "name" has the auth scheme name as value + if (entry.isJsonObject() && entry.getAsJsonObject().has("name")) { + JsonElement elem = entry.getAsJsonObject().get("name"); + if (elem.isJsonPrimitive() && elem.getAsJsonPrimitive().isString()) { + String authscheme = elem.getAsString(); + if(AuthSchemeNameMapping.containsKey(authscheme)) { + authscheme = AuthSchemeNameMapping.get(authscheme); + } + if (!authSchemeSet.contains(authscheme)) { + serviceModel.getAuthSchemes().add(authscheme); + authSchemeSet.add(authscheme); + } + } + } + }); + }); + } + + + protected void updateAuthSchemesFromOperations(ServiceModel serviceModel) + { + Set authSchemeSet = new HashSet<>(serviceModel.getAuthSchemes()); + + serviceModel.getOperations().values().forEach(operation -> { + if (operation.getAuth() == null) { + return; + } + operation.getAuth().forEach(authScheme -> { + if(AuthSchemeNameMapping.containsKey(authScheme)) { + authScheme = AuthSchemeNameMapping.get(authScheme); + } + // only add if it's not already present in the authSchemeSet + if (!authSchemeSet.contains(authScheme)) { + serviceModel.getAuthSchemes().add(authScheme); + authSchemeSet.add(authScheme); + } + }); + }); + } + //auth schemes can be named differently in endpoints/operations, this is a mapping + private static final Map AuthSchemeNameMapping = ImmutableMap.of( + "v4", "aws.auth#sigv4", + "sigv4", "aws.auth#sigv4", + "sigv4a","aws.auth#sigv4a" + ); + + + public ServiceModel convert() { ServiceModel serviceModel = ServiceModel.builder().build(); serviceModel.setMetadata(convertMetadata()); @@ -159,7 +257,7 @@ public ServiceModel convert() { { serviceModel.setAuthSchemes(Arrays.asList(c2jServiceModel.getMetadata().getSignatureVersion())); } - + convertShapes(); convertOperations(); removeIgnoredOperations(); @@ -168,6 +266,7 @@ public ServiceModel convert() { serviceModel.setShapes(shapes); serviceModel.setOperations(operations); + //for operations with context params, extract using jmespath expression and populate in endpoint params serviceModel.setServiceErrors(allErrors); serviceModel.getMetadata().setHasEndpointTrait(hasEndpointTrait); @@ -199,7 +298,8 @@ public ServiceModel convert() { serviceModel.setEndpointRuleSetModel(c2jServiceModel.getEndpointRuleSetModel()); serviceModel.setEndpointTests(c2jServiceModel.getEndpointTests()); serviceModel.setClientContextParams(c2jServiceModel.getClientContextParams()); - + updateAuthSchemesFromEndpointRules(serviceModel, c2jServiceModel.getEndpointRules()); + updateAuthSchemesFromOperations(serviceModel); return serviceModel; } diff --git a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientSourceInit.vm b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientSourceInit.vm index 0886fb14ebe..0ade07be87d 100644 --- a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientSourceInit.vm +++ b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientSourceInit.vm @@ -51,7 +51,7 @@ ${className}::${className}(const ${clientConfiguration}& clientConfiguration, { #foreach($entry in $AuthSchemeMapEntries) #if($serviceModel.metadata.serviceId == "S3") - {${entry}{Aws::MakeShared(ALLOCATION_TAG, *this), GetServiceName(), clientConfiguration.region}}, + {${entry}{Aws::MakeShared(ALLOCATION_TAG, *this), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, #else {${entry}{GetServiceName(), clientConfiguration.region}}, #end @@ -71,7 +71,11 @@ ${className}::${className}(const AWSCredentials& credentials, Aws::MakeShared>(ALLOCATION_TAG), { #foreach($entry in $AuthSchemeMapEntries) +#if($serviceModel.metadata.serviceId == "S3") + {${entry}{Aws::MakeShared(ALLOCATION_TAG, *this, Aws::MakeShared(ALLOCATION_TAG, credentials) ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, +#else {${entry}{Aws::MakeShared(ALLOCATION_TAG, credentials), GetServiceName(), clientConfiguration.region}}, +#end #end }) {} @@ -89,7 +93,7 @@ ${className}::${className}(const std::shared_ptr& creden { #foreach($entry in $AuthSchemeMapEntries) #if($serviceModel.metadata.serviceId == "S3") - {${entry}{ Aws::MakeShared(ALLOCATION_TAG, *this, credentialsProvider), GetServiceName(), clientConfiguration.region}} + {${entry}{Aws::MakeShared(ALLOCATION_TAG, *this, credentialsProvider ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), clientConfiguration.payloadSigningPolicy, false}}, #else {${entry}{ Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), GetServiceName(), clientConfiguration.region}} #end @@ -112,8 +116,9 @@ ${className}::${className}(const Client::ClientConfiguration& clientConfiguratio Aws::MakeShared<${metadata.classNamePrefix}EndpointProvider>(ALLOCATION_TAG), Aws::MakeShared>(ALLOCATION_TAG), { - {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme(Aws::MakeShared(ALLOCATION_TAG, *this), - Aws::MakeShared( ALLOCATION_TAG, GetServiceName(), clientConfiguration.region, signPayloads, false))}, +#foreach($entry in $AuthSchemeMapEntries) + {${entry}{Aws::MakeShared(ALLOCATION_TAG, *this), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, +#end }) { } @@ -133,8 +138,9 @@ ${className}::${className}( Aws::MakeShared<${metadata.classNamePrefix}EndpointProvider>(ALLOCATION_TAG), Aws::MakeShared>(ALLOCATION_TAG), { - {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme(Aws::MakeShared(ALLOCATION_TAG, credentials), - Aws::MakeShared( ALLOCATION_TAG, GetServiceName(), clientConfiguration.region, signPayloads, false))}, +#foreach($entry in $AuthSchemeMapEntries) + {${entry}{Aws::MakeShared(ALLOCATION_TAG, *this, Aws::MakeShared(ALLOCATION_TAG, credentials) ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, +#end }) { } @@ -154,8 +160,9 @@ ${className}::${className}( Aws::MakeShared<${metadata.classNamePrefix}EndpointProvider>(ALLOCATION_TAG), Aws::MakeShared>(ALLOCATION_TAG), { - {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme(Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), - Aws::MakeShared( ALLOCATION_TAG, GetServiceName(), clientConfiguration.region, signPayloads, false))}, +#foreach($entry in $AuthSchemeMapEntries) + {${entry}{Aws::MakeShared(ALLOCATION_TAG, *this, credentialsProvider ), GetServiceName(), Aws::Region::ComputeSignerRegion(clientConfiguration.region), signPayloads, false}}, +#end }) { } diff --git a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ClientHeader.vm b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ClientHeader.vm index 913ac5105f3..7d46c5abd65 100644 --- a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ClientHeader.vm +++ b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ClientHeader.vm @@ -19,8 +19,10 @@ \#include \#include \#include -\#include +\#include \#include +\#include +\#include \#include \#include diff --git a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ExpressIdentityProviderHeader.vm b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ExpressIdentityProviderHeader.vm index a698cad6245..cf5a3c4d3f8 100644 --- a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ExpressIdentityProviderHeader.vm +++ b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ExpressIdentityProviderHeader.vm @@ -27,7 +27,9 @@ namespace ${rootNamespace} { ResolveIdentityFutureOutcome getIdentity( const IdentityProperties& identityProperties, const AdditionalParameters& additionalParameters) override; - + virtual smithy::AwsCredentialIdentity GetS3ExpressIdentity(const std::shared_ptr &serviceSpecificParameters) = 0; + smithy::AwsCredentialIdentity GetCredentialsFromBucket(const Aws::String& bucketName) const; + private: const Aws::S3::S3Client& m_s3Client; mutable std::mutex m_bucketNameMapMutex; @@ -35,7 +37,6 @@ namespace ${rootNamespace} { protected: std::shared_ptr GetMutexForBucketName(const Aws::String& bucketName); - ResolveIdentityFutureOutcome getCredentialsFromBucket(const Aws::String& bucketName) const; mutable std::shared_ptr m_credsProvider; }; @@ -51,9 +52,7 @@ namespace ${rootNamespace} { DefaultS3ExpressIdentityResolver& operator=(const DefaultS3ExpressIdentityResolver& other) = delete; DefaultS3ExpressIdentityResolver& operator=(DefaultS3ExpressIdentityResolver&& other) noexcept = delete; virtual ~DefaultS3ExpressIdentityResolver() override = default; - ResolveIdentityFutureOutcome getIdentity( - const IdentityProperties& identityProperties, - const AdditionalParameters& additionalParameters) override; + smithy::AwsCredentialIdentity GetS3ExpressIdentity(const std::shared_ptr &serviceSpecificParameters) override; private: mutable std::shared_ptr> m_credentialsCache; @@ -75,12 +74,9 @@ namespace ${rootNamespace} { DefaultAsyncS3ExpressIdentityResolver& operator=( const DefaultAsyncS3ExpressIdentityResolver& other) = delete; DefaultAsyncS3ExpressIdentityResolver& operator=(DefaultAsyncS3ExpressIdentityResolver&& other) noexcept = delete; - virtual ~DefaultAsyncS3ExpressIdentityResolver() override; - - ResolveIdentityFutureOutcome getIdentity( - const IdentityProperties& identityProperties, - const AdditionalParameters& additionalParameters) override; + smithy::AwsCredentialIdentity GetS3ExpressIdentity(const std::shared_ptr &serviceSpecificParameters) override; + private: void refreshIdentities(std::chrono::minutes refreshPeriod); diff --git a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ExpressIdentityProviderSource.vm b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ExpressIdentityProviderSource.vm index 959ada497de..1808bf1a7e8 100644 --- a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ExpressIdentityProviderSource.vm +++ b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyS3ExpressIdentityProviderSource.vm @@ -7,7 +7,8 @@ \#include \#include \#include - +\#include +\#include \#include \#include @@ -22,7 +23,7 @@ namespace{ const char S3_EXPRESS_IDENTITY_PROVIDER[] = "S3ExpressIdentityProvider"; const int DEFAULT_CACHE_SIZE = 100; } -S3ExpressIdentityResolver::S3ExpressIdentityResolver(const S3Client& s3Client) : m_s3Client(s3Client) {} +S3ExpressIdentityResolver::S3ExpressIdentityResolver(const S3Client& s3Client) : m_s3Client(s3Client), m_credsProvider(Aws::MakeShared("S3ExpressIdentityResolver")) {} S3ExpressIdentityResolver::S3ExpressIdentityResolver(const S3Client& s3Client, std::shared_ptr credentialProvider): m_s3Client{s3Client},m_credsProvider{credentialProvider}{ @@ -31,32 +32,44 @@ S3ExpressIdentityResolver::S3ExpressIdentityResolver(const S3Client& s3Client, s S3ExpressIdentityResolver::ResolveIdentityFutureOutcome S3ExpressIdentityResolver::getIdentity( const IdentityProperties& identityProperties, const AdditionalParameters& additionalParameters){ - - AWS_UNREFERENCED_PARAM(identityProperties); - if(m_credsProvider) - { - auto legacyCreds = m_credsProvider->GetAWSCredentials(); - auto smithyCreds = Aws::MakeUnique("S3ExpressIdentityResolver", - legacyCreds.GetAWSAccessKeyId(), - legacyCreds.GetAWSSecretKey(), - legacyCreds.GetSessionToken().empty()? Aws::Crt::Optional() : legacyCreds.GetSessionToken(), - legacyCreds.GetExpiration()); - - return ResolveIdentityFutureOutcome(std::move(smithyCreds)); - } - - // find bucket name - auto bucketNameIter = additionalParameters.find("bucketName"); - if (bucketNameIter == additionalParameters.end()) { - AWS_LOGSTREAM_ERROR(S3_EXPRESS_IDENTITY_PROVIDER, "Failed to find BucketName in IdentityProperties"); - return S3ExpressIdentityResolver::ResolveIdentityFutureOutcome(Aws::Client::AWSError{ - Aws::Client::CoreErrors::INVALID_PARAMETER_VALUE, "", "Failed to find BucketName in IdentityProperties", - false /*retryable*/}); - } - - auto bucketName = bucketNameIter->second.get(); + const auto params = Aws::MakeShared(S3_EXPRESS_IDENTITY_PROVIDER); + for (const auto& paramMap: {identityProperties, additionalParameters}) + { + TransformAndInsert, String>(paramMap, + params->parameterMap, + [](const Aws::Crt::Variant& value) -> Aws::String + { + if (value.holds_alternative()) + { + return value.get() ? "true" : "false"; + } + if (value.holds_alternative()) + { + return value.get(); + } + return {}; + }); + } - return getCredentialsFromBucket(bucketName); + //if signer name is not s3 express as set in signer properties, get from credential provider + auto signerName = params->parameterMap.find("signerName"); + if (signerName != params->parameterMap.end()) + { + if (signerName->second != smithy::S3_EXPRESS_SIGNER_NAME) + { + if(!m_credsProvider) + { + AWS_LOGSTREAM_ERROR(S3_EXPRESS_IDENTITY_PROVIDER, "Failed to make S3Express Connect Call") + return ResolveIdentityFutureOutcome(); + } + auto creds = m_credsProvider->GetAWSCredentials(); + return ResolveIdentityFutureOutcome(Aws::MakeUnique("DefaultAwsCredentialIdentityResolver", AwsCredentialIdentity{creds.GetAWSAccessKeyId(), creds.GetAWSSecretKey(), creds.GetSessionToken(), creds.GetExpiration()})); + } + } + + auto identity = Aws::MakeUnique("DefaultAwsCredentialIdentityResolver", GetS3ExpressIdentity(params)); + + return ResolveIdentityFutureOutcome(std::move(identity)); } std::shared_ptr S3ExpressIdentityResolver::GetMutexForBucketName(const Aws::String& bucketName) { @@ -70,32 +83,26 @@ std::shared_ptr S3ExpressIdentityResolver::GetMutexForBucketName(con return bucketMutex; } -S3ExpressIdentityResolver::ResolveIdentityFutureOutcome S3ExpressIdentityResolver::getCredentialsFromBucket(const Aws::String& bucketName) const { +AwsCredentialIdentity S3ExpressIdentityResolver::GetCredentialsFromBucket(const Aws::String& bucketName) const { auto outcome = m_s3Client.CreateSession(Model::CreateSessionRequest().WithBucket(bucketName)); // If we fail the connect call return empty credentials and log an error message. if (!outcome.IsSuccess()) { - AWS_LOGSTREAM_ERROR(S3_EXPRESS_IDENTITY_PROVIDER, "Failed to make S3Express Connect Call"); - - return S3ExpressIdentityResolver::ResolveIdentityFutureOutcome(Aws::Client::AWSError{ - Aws::Client::CoreErrors::INTERNAL_FAILURE, "", "Failed to make S3Express Connect Call", - false /*retryable*/}); + AWS_LOGSTREAM_ERROR(S3_EXPRESS_IDENTITY_PROVIDER, "Failed to make S3Express Connect Call") + return {"", "", {""}, {}}; } auto result = outcome.GetResult(); - const auto& credentials = result.GetCredentials(); + const auto &credentials = result.GetCredentials(); // if expiry is present, use it, otherwise default to 5 minutes expiry auto expiry = [&]() -> Aws::Utils::DateTime { - if (credentials.ExpirationHasBeenSet()) { - return credentials.GetExpiration(); - } - return Aws::Utils::DateTime::Now() + minutes(5); + if (credentials.ExpirationHasBeenSet()) { + return credentials.GetExpiration(); + } + return Aws::Utils::DateTime::Now() + minutes(5); }(); - - auto smithyCreds = Aws::MakeUnique( - "DefaultAwsCredentialIdentityResolver", credentials.GetAccessKeyId(), credentials.GetSecretAccessKey(), - credentials.GetSessionToken().empty() ? Aws::Crt::Optional() : credentials.GetSessionToken(), - expiry); - - return S3ExpressIdentityResolver::ResolveIdentityFutureOutcome(std::move(smithyCreds)); + return {credentials.GetAccessKeyId(), + credentials.GetSecretAccessKey(), + credentials.GetSessionToken(), + expiry}; } DefaultS3ExpressIdentityResolver::DefaultS3ExpressIdentityResolver(const S3Client& s3Client) @@ -111,55 +118,24 @@ DefaultS3ExpressIdentityResolver::DefaultS3ExpressIdentityResolver(const S3Clien S3ExpressIdentityResolver{s3Client,credentialProvider}, m_credentialsCache{Aws::MakeShared>(S3_EXPRESS_IDENTITY_PROVIDER, DEFAULT_CACHE_SIZE)}{}; -DefaultS3ExpressIdentityResolver::ResolveIdentityFutureOutcome DefaultS3ExpressIdentityResolver::getIdentity(const IdentityProperties& identityProperties, - const AdditionalParameters& additionalParameters){ - - AWS_UNREFERENCED_PARAM(identityProperties); - //if provider is set, then credentials from the provider is used - if(m_credsProvider) - { - auto legacyCreds = m_credsProvider->GetAWSCredentials(); - auto smithyCreds = Aws::MakeUnique("S3ExpressIdentityResolver", - legacyCreds.GetAWSAccessKeyId(), - legacyCreds.GetAWSSecretKey(), - legacyCreds.GetSessionToken().empty()? Aws::Crt::Optional() : legacyCreds.GetSessionToken(), - legacyCreds.GetExpiration()); - - return ResolveIdentityFutureOutcome(std::move(smithyCreds)); - } - - auto bucketNameIter = additionalParameters.find("bucketName"); - if (bucketNameIter == additionalParameters.end()) { - - AWS_LOGSTREAM_ERROR(S3_EXPRESS_IDENTITY_PROVIDER, "Failed to find BucketName in IdentityProperties"); - return ResolveIdentityFutureOutcome(Aws::Client::AWSError{ - Aws::Client::CoreErrors::INVALID_PARAMETER_VALUE, "", "Failed to find BucketName in IdentityProperties", - false /*retryable*/}); - } - - auto bucketName = bucketNameIter->second.get(); - std::lock_guard lock(*GetMutexForBucketName(bucketName)); - Aws::UniquePtr smithyCreds; - AwsCredentialIdentity identity; - auto isInCache = m_credentialsCache->Get(bucketName, identity); - - if (!isInCache || (identity.expiration().has_value() && identity.expiration().value() - minutes(1) < Aws::Utils::DateTime::Now())) { - ResolveIdentityFutureOutcome outcome = S3ExpressIdentityResolver::getCredentialsFromBucket(bucketName); - - smithyCreds = Aws::MakeUnique("DefaultAwsCredentialIdentityResolver", - outcome.GetResult()->accessKeyId(), - outcome.GetResult()->secretAccessKey(), - outcome.GetResult()->sessionToken(), - outcome.GetResult()->expiration()); - m_credentialsCache->Put(bucketName, *smithyCreds, - std::chrono::milliseconds(identity.expiration().value().Millis() - Aws::Utils::DateTime::Now().Millis())); - } - - smithyCreds = Aws::MakeUnique("DefaultAwsCredentialIdentityResolver", - identity.accessKeyId(), identity.secretAccessKey(), - identity.sessionToken(), identity.expiration()); - - return ResolveIdentityFutureOutcome(std::move(smithyCreds)); +AwsCredentialIdentity DefaultS3ExpressIdentityResolver::GetS3ExpressIdentity(const std::shared_ptr &serviceSpecificParameters) { + auto bucketNameIter = serviceSpecificParameters->parameterMap.find("bucketName"); + if (bucketNameIter == serviceSpecificParameters->parameterMap.end()) { + AWS_LOGSTREAM_ERROR(S3_EXPRESS_IDENTITY_PROVIDER, "property bucketName Required to make call") + return {"", "", {""}, {}}; + } + std::lock_guard lock(*GetMutexForBucketName(bucketNameIter->second)); + AwsCredentialIdentity identity; + auto isInCache = m_credentialsCache->Get(bucketNameIter->second, identity); + if (!isInCache || (identity.expiration().has_value() && (identity.expiration().value() - minutes(1) < Aws::Utils::DateTime::Now())) ) { + identity = S3ExpressIdentityResolver::GetCredentialsFromBucket(bucketNameIter->second); + if (identity.expiration().has_value()) { + m_credentialsCache->Put(bucketNameIter->second, + identity, + std::chrono::milliseconds(identity.expiration().value().Millis() - Aws::Utils::DateTime::Now().Millis())); + } + } + return identity; } DefaultAsyncS3ExpressIdentityResolver::DefaultAsyncS3ExpressIdentityResolver( @@ -188,40 +164,25 @@ DefaultAsyncS3ExpressIdentityResolver::~DefaultAsyncS3ExpressIdentityResolver(){ m_backgroundRefreshThread->join(); } -DefaultAsyncS3ExpressIdentityResolver::ResolveIdentityFutureOutcome DefaultAsyncS3ExpressIdentityResolver::getIdentity( - const IdentityProperties& identityProperties, const AdditionalParameters& additionalParameters){ - AWS_UNREFERENCED_PARAM(identityProperties); - auto bucketNameIter = additionalParameters.find("bucketName"); - if (bucketNameIter == additionalParameters.end()) { - AWS_LOGSTREAM_ERROR(S3_EXPRESS_IDENTITY_PROVIDER, "Failed to find BucketName in IdentityProperties"); - return ResolveIdentityFutureOutcome(Aws::Client::AWSError{ - Aws::Client::CoreErrors::INVALID_PARAMETER_VALUE, "", "Failed to find BucketName in IdentityProperties", - false /*retryable*/}); +AwsCredentialIdentity DefaultAsyncS3ExpressIdentityResolver::GetS3ExpressIdentity(const std::shared_ptr &serviceSpecificParameters){ + auto bucketNameIter = serviceSpecificParameters->parameterMap.find("bucketName"); + if (bucketNameIter == serviceSpecificParameters->parameterMap.end()) { + AWS_LOGSTREAM_ERROR(S3_EXPRESS_IDENTITY_PROVIDER, "property bucketName Required to make call") + return {"", "", {""}, {}}; } - - auto bucketName = bucketNameIter->second.get(); - threadSafeKeyInsert(bucketName); - std::lock_guard lock(*GetMutexForBucketName(bucketName)); - Aws::UniquePtr smithyCreds; + threadSafeKeyInsert(bucketNameIter->second); + std::lock_guard lock(*GetMutexForBucketName(bucketNameIter->second)); AwsCredentialIdentity identity; - auto isInCache = m_credentialsCache->Get(bucketName, identity); - if (!isInCache) { - ResolveIdentityFutureOutcome outcome = S3ExpressIdentityResolver::getCredentialsFromBucket(bucketName); - - smithyCreds = Aws::MakeUnique("DefaultAwsCredentialIdentityResolver", - outcome.GetResult()->accessKeyId(), - outcome.GetResult()->secretAccessKey(), - outcome.GetResult()->sessionToken(), - outcome.GetResult()->expiration()); - m_credentialsCache->Put(bucketName, *smithyCreds, - std::chrono::milliseconds(identity.expiration().value().Millis() - Aws::Utils::DateTime::Now().Millis())); + auto isInCache = m_credentialsCache->Get(bucketNameIter->second, identity); + if (!isInCache || (identity.expiration().has_value() && (identity.expiration().value() - minutes(1) < Aws::Utils::DateTime::Now())) ) { + identity = S3ExpressIdentityResolver::GetCredentialsFromBucket(bucketNameIter->second); + if (identity.expiration().has_value()) { + m_credentialsCache->Put(bucketNameIter->second, + identity, + std::chrono::milliseconds(identity.expiration().value().Millis() - Aws::Utils::DateTime::Now().Millis())); + } } - - smithyCreds = Aws::MakeUnique("DefaultAwsCredentialIdentityResolver", - identity.accessKeyId(), identity.secretAccessKey(), - identity.sessionToken(), identity.expiration()); - - return ResolveIdentityFutureOutcome(std::move(smithyCreds)); + return identity; } void DefaultAsyncS3ExpressIdentityResolver::threadSafeKeyEmpty() { @@ -240,32 +201,27 @@ void DefaultAsyncS3ExpressIdentityResolver::threadSafeKeyInsert(const Aws::Strin } void DefaultAsyncS3ExpressIdentityResolver::refreshIdentities(std::chrono::minutes refreshPeriod) { - auto filterUnusedKeys = [&](const Aws::String& bucketName, const CacheValueType& valueType) -> bool { - std::lock_guard lock(*GetMutexForBucketName(bucketName)); - AWS_UNREFERENCED_PARAM(valueType); - return !threadSafeKeyHas(bucketName); + auto filterUnusedKeys = [&](const Aws::String &bucketName, const CacheValueType &valueType) -> bool { + std::lock_guard lock(*GetMutexForBucketName(bucketName)); + AWS_UNREFERENCED_PARAM(valueType); + return !threadSafeKeyHas(bucketName); }; - auto refreshIdentityWhenCloseToExpiry = [&](const Aws::String& bucketName, const CacheValueType& valueType) - -> CacheValueType { - std::lock_guard lock(*GetMutexForBucketName(bucketName)); - if (valueType.val.expiration().has_value() && - (duration_cast(refreshPeriod).count() < valueType.val.expiration().value().Millis()) && - (valueType.val.expiration().value() - refreshPeriod < Aws::Utils::DateTime::Now())) { - auto outcome = S3ExpressIdentityResolver::getCredentialsFromBucket(bucketName); - - if (outcome.IsSuccess() && outcome.GetResult()->expiration().has_value()) { - return {outcome.GetResult()->expiration().value(), - AwsCredentialIdentity{outcome.GetResult()->accessKeyId(), outcome.GetResult()->secretAccessKey(), - outcome.GetResult()->sessionToken(), outcome.GetResult()->expiration()}}; + auto refreshIdentityWhenCloseToExpiry = [&](const Aws::String &bucketName, + const CacheValueType &valueType) -> CacheValueType { + std::lock_guard lock(*GetMutexForBucketName(bucketName)); + if ((!valueType.val.expiration().has_value()) || + (duration_cast(refreshPeriod).count() < valueType.val.expiration().value().Millis() && + valueType.val.expiration().value() - refreshPeriod < Aws::Utils::DateTime::Now())) { + auto updatedIdentity = this->S3ExpressIdentityResolver::GetCredentialsFromBucket(bucketName); + return {updatedIdentity.expiration().value(), updatedIdentity}; } - } - return valueType; + return valueType; }; std::unique_lock lock(m_shutDownMutex); while (!m_shouldStopBackgroundRefresh) { - m_credentialsCache->Filter(filterUnusedKeys); - m_credentialsCache->Transform(refreshIdentityWhenCloseToExpiry); - threadSafeKeyEmpty(); - m_shutdownCondition.wait_for(lock, refreshPeriod, [this] { return m_shouldStopBackgroundRefresh; }); + m_credentialsCache->Filter(filterUnusedKeys); + m_credentialsCache->Transform(refreshIdentityWhenCloseToExpiry); + threadSafeKeyEmpty(); + m_shutdownCondition.wait_for(lock, refreshPeriod, [this] { return m_shouldStopBackgroundRefresh; }); } }