diff --git a/generated/src/aws-cpp-sdk-dynamodb/include/aws/dynamodb/DynamoDBClient.h b/generated/src/aws-cpp-sdk-dynamodb/include/aws/dynamodb/DynamoDBClient.h index d57368c460a..19f50e4c26c 100644 --- a/generated/src/aws-cpp-sdk-dynamodb/include/aws/dynamodb/DynamoDBClient.h +++ b/generated/src/aws-cpp-sdk-dynamodb/include/aws/dynamodb/DynamoDBClient.h @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include namespace Aws { namespace DynamoDB { @@ -38,7 +38,7 @@ AWS_DYNAMODB_API extern const char SERVICE_NAME[]; class AWS_DYNAMODB_API DynamoDBClient : Aws::Client::ClientWithAsyncTemplateMethods, smithy::client::AwsSmithyClientT, Aws::Crt::Variant, + smithy::AuthSchemeResolverBase<>, Aws::Crt::Variant, DynamoDBEndpointProviderBase, smithy::client::JsonOutcomeSerializer, smithy::client::JsonOutcome, Aws::Client::DynamoDBErrorMarshaller> { public: diff --git a/generated/src/aws-cpp-sdk-dynamodb/source/DynamoDBClient.cpp b/generated/src/aws-cpp-sdk-dynamodb/source/DynamoDBClient.cpp index 6fae7149558..1dce2d7dc4b 100644 --- a/generated/src/aws-cpp-sdk-dynamodb/source/DynamoDBClient.cpp +++ b/generated/src/aws-cpp-sdk-dynamodb/source/DynamoDBClient.cpp @@ -104,7 +104,8 @@ DynamoDBClient::DynamoDBClient(const DynamoDB::DynamoDBClientConfiguration& clie : AwsSmithyClientT(clientConfiguration, GetServiceName(), "DynamoDB", Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), endpointProvider ? endpointProvider : Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>( + ALLOCATION_TAG, Aws::Vector({smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption})), { {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{GetServiceName(), clientConfiguration.region}}, @@ -116,7 +117,8 @@ DynamoDBClient::DynamoDBClient(const AWSCredentials& credentials, std::shared_pt clientConfiguration, GetServiceName(), "DynamoDB", Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), endpointProvider ? endpointProvider : Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>( + ALLOCATION_TAG, Aws::Vector({smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption})), { {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, credentials), @@ -130,37 +132,50 @@ DynamoDBClient::DynamoDBClient(const std::shared_ptr& cr clientConfiguration, GetServiceName(), "DynamoDB", Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), endpointProvider ? endpointProvider : Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), - {{smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, - smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), - GetServiceName(), clientConfiguration.region}}}) {} + Aws::MakeShared>( + ALLOCATION_TAG, Aws::Vector({smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption})), + { + {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, + smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), + GetServiceName(), clientConfiguration.region}}, + }) {} /* Legacy constructors due deprecation */ DynamoDBClient::DynamoDBClient(const Client::ClientConfiguration& clientConfiguration) : AwsSmithyClientT(clientConfiguration, GetServiceName(), "DynamoDB", Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), - {{smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, - smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG), - GetServiceName(), clientConfiguration.region}}}) {} + Aws::MakeShared>( + ALLOCATION_TAG, Aws::Vector({smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption})), + { + {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, + smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG), + GetServiceName(), clientConfiguration.region}}, + }) {} DynamoDBClient::DynamoDBClient(const AWSCredentials& credentials, const Client::ClientConfiguration& clientConfiguration) - : AwsSmithyClientT(clientConfiguration, GetServiceName(), "DynamoDB", Aws::Http::CreateHttpClient(clientConfiguration), - 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}}}) {} + : AwsSmithyClientT( + clientConfiguration, GetServiceName(), "DynamoDB", Aws::Http::CreateHttpClient(clientConfiguration), + Aws::MakeShared(ALLOCATION_TAG), Aws::MakeShared(ALLOCATION_TAG), + Aws::MakeShared>( + ALLOCATION_TAG, Aws::Vector({smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption})), + { + {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, + smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, credentials), + GetServiceName(), clientConfiguration.region}}, + }) {} DynamoDBClient::DynamoDBClient(const std::shared_ptr& credentialsProvider, const Client::ClientConfiguration& clientConfiguration) : AwsSmithyClientT( clientConfiguration, GetServiceName(), "DynamoDB", Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared(ALLOCATION_TAG), Aws::MakeShared(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), - {{smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, - smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), - GetServiceName(), clientConfiguration.region}}}) {} + Aws::MakeShared>( + ALLOCATION_TAG, Aws::Vector({smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption})), + { + {smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId, + smithy::SigV4AuthScheme{Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), + GetServiceName(), clientConfiguration.region}}, + }) {} /* End of legacy constructors due deprecation */ DynamoDBClient::~DynamoDBClient() { ShutdownSdkClient(this, -1); } diff --git a/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h b/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h index a72809b240e..75e2ba5fac8 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h +++ b/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h @@ -563,6 +563,12 @@ namespace Aws std::chrono::milliseconds credentialCacheCacheTTL = std::chrono::minutes(50); } stsCredentialsProviderConfig; } credentialProviderConfig; + + /** + * Authentication scheme preferences in order of preference. + * First available auth scheme will be used for each operation. + */ + Aws::Vector authPreferences; }; /** 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 21c8341d80c..b5eeb8f7d12 100644 --- a/src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClient.h +++ b/src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClient.h @@ -163,6 +163,7 @@ namespace client identityParams.serviceName = m_serviceName; identityParams.operation = ctx.m_requestName; identityParams.region = m_clientConfiguration.region; + identityParams.authPreferences = m_clientConfiguration.authPreferences; if (ctx.m_pRequest) { // refactor once auth scheme resolver will use it's own rule set diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/auth/AuthSchemeResolverBase.h b/src/aws-cpp-sdk-core/include/smithy/identity/auth/AuthSchemeResolverBase.h index 4ab79935e4c..39c81b3897b 100644 --- a/src/aws-cpp-sdk-core/include/smithy/identity/auth/AuthSchemeResolverBase.h +++ b/src/aws-cpp-sdk-core/include/smithy/identity/auth/AuthSchemeResolverBase.h @@ -8,10 +8,23 @@ #include #include -#include - +#include namespace smithy { + +static const char SIGV4_PREFERENCE[] = "sigv4"; +static const char SIGV4A_PREFERENCE[] = "sigv4a"; +static const char BEARER_PREFERENCE[] = "bearer"; +static const char NO_AUTH_PREFERENCE[] = "noauth"; + +// Global map from auth scheme name (trimmed ID) to full ID for case insensitive lookup +static const Aws::Array, 4> AUTH_SCHEME_NAME_TO_ID = { + std::make_pair(SIGV4_PREFERENCE, "aws.auth#sigv4"), + std::make_pair(SIGV4A_PREFERENCE, "aws.auth#sigv4a"), + std::make_pair(BEARER_PREFERENCE, "smithy.api#HTTPBearerAuth"), + std::make_pair(NO_AUTH_PREFERENCE, "smithy.api#noAuth") +}; + /** * 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. @@ -22,6 +35,7 @@ class DefaultAuthSchemeResolverParameters Aws::String serviceName; Aws::String operation; Aws::Crt::Optional region; + Aws::Vector authPreferences; Aws::UnorderedMap resolveAuthScheme(const ServiceAuthSchemeParameters& identityProperties) = 0; + + virtual Aws::Vector resolveAuthScheme(const ServiceAuthSchemeParameters& identityProperties) { + auto options = resolveAuthSchemeImpl(identityProperties); + return filterByPreferences(options, identityProperties.authPreferences); + } + +protected: + virtual Aws::Vector resolveAuthSchemeImpl(const ServiceAuthSchemeParameters& identityProperties) = 0; + + virtual Aws::Vector filterByPreferences(const Aws::Vector& options, + const Aws::Vector& preferences) { + if (preferences.empty()) return options; + + Aws::Vector filtered; + for (const auto& pref : preferences) { + auto prefSchemeIt = find_if(AUTH_SCHEME_NAME_TO_ID.begin(), AUTH_SCHEME_NAME_TO_ID.end(), [&](const std::pair &pair) { return Aws::Utils::StringUtils::ToLower(pref.c_str()) == pair.first; }); + if (prefSchemeIt == AUTH_SCHEME_NAME_TO_ID.end()) continue; + for (const auto& option : options) { + if (strcmp(option.schemeId, prefSchemeIt->second) == 0) { + filtered.push_back(option); + break; + } + } + } + return filtered.empty() ? options : filtered; + } }; } \ No newline at end of file diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/BearerTokenAuthScheme.h b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/BearerTokenAuthScheme.h index 4e6e450621d..38800b01190 100644 --- a/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/BearerTokenAuthScheme.h +++ b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/BearerTokenAuthScheme.h @@ -11,6 +11,8 @@ #include namespace smithy { +constexpr char BEARER[] = "smithy.api#HTTPBearerAuth"; + class BearerTokenAuthScheme : public AuthScheme { public: @@ -22,7 +24,7 @@ class BearerTokenAuthScheme : public AuthScheme explicit BearerTokenAuthScheme( std::shared_ptr identityResolver, const Aws::String &serviceName, const Aws::String ®ion) - : AuthScheme("smithy.api#HTTPBearerAuth"), + : AuthScheme(BEARER), m_identityResolver{identityResolver}, m_signer{Aws::MakeShared( "BearerTokenAuthScheme", serviceName, region)} diff --git a/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/GenericAuthSchemeResolver.h b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/GenericAuthSchemeResolver.h new file mode 100644 index 00000000000..7fc600d5d11 --- /dev/null +++ b/src/aws-cpp-sdk-core/include/smithy/identity/auth/built-in/GenericAuthSchemeResolver.h @@ -0,0 +1,30 @@ +/** +* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#pragma once + +#include + + +namespace smithy { + template + class GenericAuthSchemeResolver : public AuthSchemeResolverBase + { + public: + using ServiceAuthSchemeParameters = ServiceAuthSchemeParametersT; + GenericAuthSchemeResolver(const Aws::Vector& allowedAuth) : m_allowedAuth(allowedAuth) {} + GenericAuthSchemeResolver() = default; + virtual ~GenericAuthSchemeResolver() = default; + + private: + Aws::Vector m_allowedAuth; + + protected: + Aws::Vector resolveAuthSchemeImpl(const ServiceAuthSchemeParameters& identityProperties) override + { + AWS_UNREFERENCED_PARAM(identityProperties); + return m_allowedAuth; + } + }; +} \ 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 index 5cd1b372a81..5bf5b7ba11c 100644 --- 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 @@ -12,12 +12,18 @@ #include #include +/** + * This is an auth scheme resolver prioritizing endpoints2.0 auth resolution + * used for s3 which supersedes the model based auth resolution we do in GenericAuthResolver. + */ + namespace smithy { template class SigV4MultiAuthSchemeResolver : public AuthSchemeResolverBase { - private: public: + SigV4MultiAuthSchemeResolver(const Aws::Vector& allowedAuth) : m_allowedAuth(allowedAuth) {} + SigV4MultiAuthSchemeResolver() = default; void Init(const ClientConfigType& config) override{ m_endpointProviderForAuth = Aws::MakeShared("SigV4MultiAuthSchemeResolver"); @@ -27,8 +33,12 @@ namespace smithy { using ServiceAuthSchemeParameters = ServiceAuthSchemeParametersT; virtual ~SigV4MultiAuthSchemeResolver() = default; - Aws::Vector resolveAuthScheme(const ServiceAuthSchemeParameters& identityProperties) override + Aws::Vector resolveAuthSchemeImpl(const ServiceAuthSchemeParameters& identityProperties) override { + if (!m_allowedAuth.empty()) { + // This code path will not currently be taken, but we should enable a way for the user to disable preference for endpoints2.0 resolution and use the preference list + return m_allowedAuth; + } //pack endpoint params from identityProperties Aws::Endpoint::EndpointParameters epParams; @@ -66,6 +76,10 @@ namespace smithy { return {SigV4AuthSchemeOption::sigV4AuthSchemeOption}; } + + private: + Aws::Vector m_allowedAuth; + protected: std::shared_ptr m_endpointProviderForAuth; }; diff --git a/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp b/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp index 3b427fb7ae4..289552f1ddf 100644 --- a/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp +++ b/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp @@ -188,6 +188,18 @@ Aws::String calculateRegion() { return ""; } + +Aws::Vector calculateAuthPreferences() { + // Automatically determine the AWS region from environment variables, configuration file and EC2 metadata. + Aws::Vector res; + auto prefs = Aws::Environment::GetEnv("AWS_AUTH_SCHEME_PREFERENCE"); + Aws::Vector prefsList = Aws::Utils::StringUtils::Split(prefs, ','); + for (auto& pref : prefsList) { + res.push_back(Aws::Utils::StringUtils::Trim(pref.c_str())); + } + return res; +} + void setLegacyClientConfigurationParameters(ClientConfiguration& clientConfig) { clientConfig.scheme = Aws::Http::Scheme::HTTPS; @@ -251,6 +263,7 @@ void setLegacyClientConfigurationParameters(ClientConfiguration& clientConfig) clientConfig.region = calculateRegion(); clientConfig.credentialProviderConfig.region = clientConfig.region; + clientConfig.authPreferences = calculateAuthPreferences(); // Set the endpoint to interact with EC2 instance's metadata service Aws::String ec2MetadataServiceEndpoint = Aws::Environment::GetEnv("AWS_EC2_METADATA_SERVICE_ENDPOINT"); 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 18ef6e124f7..4b14cfd5418 100644 --- a/tests/aws-cpp-sdk-core-tests/smithy/client/SmithyClientTest.cpp +++ b/tests/aws-cpp-sdk-core-tests/smithy/client/SmithyClientTest.cpp @@ -17,12 +17,10 @@ #include #include #include -#include #include -#include #include -#include #include +#include namespace { const char* ALLOC_TAG = "SmithyClientTest"; @@ -232,7 +230,7 @@ class TestClient : public MySmithyClient TEST_F(SmithyClientTest, testSigV4) { - std::shared_ptr authSchemeResolver = Aws::MakeShared >(ALLOCATION_TAG); + std::shared_ptr authSchemeResolver = Aws::MakeShared >(ALLOCATION_TAG, Aws::Vector({smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption})); Aws::UnorderedMap authSchemesMap; @@ -279,7 +277,7 @@ TEST_F(SmithyClientTest, testSigV4) { TEST_F(SmithyClientTest, testSigV4a) { - std::shared_ptr authSchemeResolver = Aws::MakeShared>(ALLOCATION_TAG); + std::shared_ptr authSchemeResolver = Aws::MakeShared>(ALLOCATION_TAG, Aws::Vector({smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption})); Aws::UnorderedMap authSchemesMap; @@ -328,8 +326,8 @@ TEST_F(SmithyClientTest, bearer) { std::shared_ptr authSchemeResolver = - Aws::MakeShared>( - ALLOCATION_TAG); + Aws::MakeShared>( + ALLOCATION_TAG, Aws::Vector({smithy::BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption})); Aws::UnorderedMap authSchemesMap; @@ -375,6 +373,183 @@ TEST_F(SmithyClientTest, bearer) "Bearer testBearerToken"); } +TEST_F(SmithyClientTest, testSigV4aPreference) { + + std::shared_ptr authSchemeResolver = Aws::MakeShared >(ALLOCATION_TAG, Aws::Vector({smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption, smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption, smithy::BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption})); + + Aws::UnorderedMap authSchemesMap; + + //add mock credentials provider for the test to the credentials provider chain + AddCredentialsProvider(Aws::MakeShared("TestCredentialsProviderChain")); + + //create resolver with the credentials provider chain + auto credentialsResolver = Aws::MakeShared(ALLOCATION_TAG, credsProviderChain); + + Aws::String key{smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption.schemeId}; + SigVariant val{smithy::SigV4aAuthScheme( credentialsResolver, "MyService", "us-west-2")}; + + authSchemesMap.emplace(key, val); + + Aws::String key2{smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId}; + SigVariant val2{smithy::SigV4AuthScheme( credentialsResolver, "MyService", "us-west-2")}; + + authSchemesMap.emplace(key2, val2); + + Aws::String key3{smithy::BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption.schemeId}; + SigVariant val3{smithy::BearerTokenAuthScheme( Aws::MakeShared(ALLOCATION_TAG), "MyService", "us-west-2")}; + + authSchemesMap.emplace(key3, val3); + + clientConfig.authPreferences = {smithy::SIGV4A_PREFERENCE}; + std::shared_ptr ptr = Aws::MakeShared( + ALLOCATION_TAG, + clientConfig, + "MyService", + httpClient, + errorMarshaller, + endPointProvider, + authSchemeResolver, + authSchemesMap); + smithy::client::AwsSmithyClientAsyncRequestContext ctx; + ctx.m_pRequest = nullptr; + + auto res = ptr->SelectAuthSchemeOption(ctx); + EXPECT_EQ(res.IsSuccess(), true); + EXPECT_EQ(res.GetResult().schemeId, key); + ctx.m_authSchemeOption = res.GetResultWithOwnership(); + ctx.m_awsIdentity = ptr->ResolveIdentity(ctx).GetResultWithOwnership(); + + Aws::String uri{"https://treasureisland-cb93079d-24a0-4862-8es2-88456ead.xyz.amazonaws.com"}; + + std::shared_ptr httpRequest(Aws::Http::CreateHttpRequest(uri, Aws::Http::HttpMethod::HTTP_GET, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + + auto res2 = ptr->SignRequest(httpRequest, ctx); + + EXPECT_EQ(res2.IsSuccess(), true); + EXPECT_TRUE(!res2.GetResult()->GetSigningAccessKey().empty()); + EXPECT_FALSE(res2.GetResult()->GetUri().GetURIString(true).empty()); +} + +TEST_F(SmithyClientTest, testSigV4Preference) { + + std::shared_ptr authSchemeResolver = Aws::MakeShared >(ALLOCATION_TAG, Aws::Vector({smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption, smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption, smithy::BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption})); + + Aws::UnorderedMap authSchemesMap; + + //add mock credentials provider for the test to the credentials provider chain + AddCredentialsProvider(Aws::MakeShared("TestCredentialsProviderChain")); + + //create resolver with the credentials provider chain + auto credentialsResolver = Aws::MakeShared(ALLOCATION_TAG, credsProviderChain); + + Aws::String key{smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId}; + SigVariant val{smithy::SigV4AuthScheme( credentialsResolver, "MyService", "us-west-2")}; + + authSchemesMap.emplace(key, val); + + Aws::String key2{smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption.schemeId}; + SigVariant val2{smithy::SigV4aAuthScheme( credentialsResolver, "MyService", "us-west-2")}; + + authSchemesMap.emplace(key2, val2); + + Aws::String key3{smithy::BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption.schemeId}; + SigVariant val3{smithy::BearerTokenAuthScheme( Aws::MakeShared(ALLOCATION_TAG), "MyService", "us-west-2")}; + + authSchemesMap.emplace(key3, val3); + + clientConfig.authPreferences = {smithy::SIGV4_PREFERENCE}; + std::shared_ptr ptr = Aws::MakeShared( + ALLOCATION_TAG, + clientConfig, + "MyService", + httpClient, + errorMarshaller, + endPointProvider, + authSchemeResolver, + authSchemesMap); + smithy::client::AwsSmithyClientAsyncRequestContext ctx; + ctx.m_pRequest = nullptr; + + auto res = ptr->SelectAuthSchemeOption(ctx); + EXPECT_EQ(res.IsSuccess(), true); + EXPECT_EQ(res.GetResult().schemeId, key); + ctx.m_authSchemeOption = res.GetResultWithOwnership(); + ctx.m_awsIdentity = ptr->ResolveIdentity(ctx).GetResultWithOwnership(); + + Aws::String uri{"https://treasureisland-cb93079d-24a0-4862-8es2-88456ead.xyz.amazonaws.com"}; + + std::shared_ptr httpRequest(Aws::Http::CreateHttpRequest(uri, Aws::Http::HttpMethod::HTTP_GET, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + + auto res2 = ptr->SignRequest(httpRequest, ctx); + + EXPECT_EQ(res2.IsSuccess(), true); + EXPECT_EQ(res2.GetResult()->GetSigningAccessKey(), "dummyAccessId"); +} + +TEST_F(SmithyClientTest, testBearerPreference) { + + std::shared_ptr authSchemeResolver = Aws::MakeShared >(ALLOCATION_TAG, Aws::Vector({smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption, smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption, smithy::BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption})); + + Aws::UnorderedMap authSchemesMap; + + //add mock credentials provider for the test to the credentials provider chain + AddCredentialsProvider(Aws::MakeShared("TestCredentialsProviderChain")); + + //create resolver with the credentials provider chain + auto credentialsResolver = Aws::MakeShared(ALLOCATION_TAG, credsProviderChain); + + Aws::String key{smithy::BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption.schemeId}; + SigVariant val{smithy::BearerTokenAuthScheme( Aws::MakeShared(ALLOCATION_TAG), "MyService", "us-west-2")}; + + authSchemesMap.emplace(key, val); + + Aws::String key2{smithy::SigV4aAuthSchemeOption::sigV4aAuthSchemeOption.schemeId}; + SigVariant val2{smithy::SigV4aAuthScheme( credentialsResolver, "MyService", "us-west-2")}; + + authSchemesMap.emplace(key2, val2); + + Aws::String key3{smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption.schemeId}; + SigVariant val3{smithy::SigV4AuthScheme( credentialsResolver, "MyService", "us-west-2")}; + + authSchemesMap.emplace(key3, val3); + + clientConfig.authPreferences = {smithy::BEARER_PREFERENCE}; + std::shared_ptr ptr = Aws::MakeShared( + ALLOCATION_TAG, + clientConfig, + "MyService", + httpClient, + errorMarshaller, + endPointProvider, + authSchemeResolver, + authSchemesMap); + smithy::client::AwsSmithyClientAsyncRequestContext ctx; + ctx.m_pRequest = nullptr; + + auto res = ptr->SelectAuthSchemeOption(ctx); + EXPECT_EQ(res.IsSuccess(), true); + EXPECT_EQ(res.GetResult().schemeId, key); + ctx.m_authSchemeOption = res.GetResultWithOwnership(); + ctx.m_awsIdentity = ptr->ResolveIdentity(ctx).GetResultWithOwnership(); + + Aws::String uri{ + "https://" + "treasureisland-cb93079d-24a0-4862-8es2-88456ead.xyz.amazonaws.com"}; + + std::shared_ptr httpRequest( + Aws::Http::CreateHttpRequest( + uri, Aws::Http::HttpMethod::HTTP_GET, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod)); + + auto res2 = ptr->SignRequest(httpRequest, ctx); + + EXPECT_EQ(res2.IsSuccess(), true); + + EXPECT_TRUE(!res2.GetResult()->GetHeaderValue("authorization").empty()); + EXPECT_EQ(res2.GetResult()->GetHeaderValue("authorization"), + "Bearer testBearerToken"); +} + struct SampleConfiguration: public Aws::Client::ClientConfiguration { Aws::String localToService{"whatever"}; }; @@ -407,7 +582,7 @@ struct SampleEndpointProvider : public Aws::Endpoint::EndpointProviderBase<> static constexpr char SampleServiceName[] = "SampleService"; class SampleClient: public smithy::client::AwsSmithyClientT, + smithy::GenericAuthSchemeResolver<>, Aws::Crt::Variant, SampleEndpointProvider, smithy::client::JsonOutcomeSerializer, @@ -421,7 +596,7 @@ class SampleClient: public smithy::client::AwsSmithyClientT(SampleServiceName), Aws::MakeShared(SampleServiceName), Aws::MakeShared(SampleServiceName), - Aws::MakeShared>(SampleServiceName), + Aws::MakeShared>(SampleServiceName), Aws::UnorderedMap>()) {} }; @@ -438,7 +613,7 @@ TEST_F(SmithyClientTest, SmithyClientShouldCopyAssignAndMove) { AWS_UNREFERENCED_PARAM(assign); } -class TestAuthSchemeResolver : public smithy::SigV4AuthSchemeResolver<> +class TestAuthSchemeResolver : public smithy::GenericAuthSchemeResolver<> { public: virtual Aws::String GetTestId() const { return "BaseClass"; } diff --git a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/domainmodels/codegeneration/ServiceModel.java b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/domainmodels/codegeneration/ServiceModel.java index 705c88b15ee..0a0e00580b4 100644 --- a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/domainmodels/codegeneration/ServiceModel.java +++ b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/domainmodels/codegeneration/ServiceModel.java @@ -54,6 +54,10 @@ public boolean hasSigV4Auth() { return operations.values().parallelStream().anyMatch(operation -> operation.getSignerName().equals("Aws::Auth::SIGV4_SIGNER")); } + public boolean hasSigV4aAuth() { + return operations.values().parallelStream().anyMatch(operation -> operation.getSignerName().equals("Aws::Auth::ASYMMETRIC_SIGV4_SIGNER")); + } + public boolean hasBearerAuth() { if(metadata.getSignatureVersion().equals("bearer")) { return true; diff --git a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/generators/cpp/CppClientGenerator.java b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/generators/cpp/CppClientGenerator.java index 53119435d23..3e0fb7803a7 100644 --- a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/generators/cpp/CppClientGenerator.java +++ b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/generators/cpp/CppClientGenerator.java @@ -736,24 +736,18 @@ protected SdkFileEntry generateClientSmithyHeaderFile(final ServiceModel service private void selectAuthschemeResolver(final ServiceModel serviceModel, VelocityContext context) { - if(serviceModel.getAuthSchemes().size() > 1) + //Ensure we support this auth + Optional firstAuthScheme = serviceModel.getAuthSchemes().stream().filter(entry->ResolverMapping.containsKey(entry)).findFirst(); + if(firstAuthScheme.isPresent()) { - context.put("AuthSchemeResolver", "SigV4MultiAuthSchemeResolver"); + context.put("AuthSchemeResolver", ResolverMapping.get(firstAuthScheme.get())); } else { - Optional firstAuthScheme = serviceModel.getAuthSchemes().stream().filter(entry->ResolverMapping.containsKey(entry)).findFirst(); - - if(firstAuthScheme.isPresent()) - { - context.put("AuthSchemeResolver", ResolverMapping.get(firstAuthScheme.get())); - } - else - { - throw new RuntimeException(String.format("authSchemes '%s'",serviceModel.getAuthSchemes().stream().collect(Collectors.toList()))); - } + throw new RuntimeException(String.format("authSchemes '%s'",serviceModel.getAuthSchemes().stream().collect(Collectors.toList()))); } context.put("AuthSchemeVariants", serviceModel.getAuthSchemes().stream().map(this::mapAuthSchemes).collect(Collectors.joining(","))); + context.put("AuthSchemeOptions", serviceModel.getAuthSchemes().stream().map(this::mapAuthSchemeOptions).collect(Collectors.joining(","))); } protected SdkFileEntry GenerateSmithyClientSourceFile(final ServiceModel serviceModel, int i, Optional templateFile) { @@ -765,6 +759,7 @@ protected SdkFileEntry GenerateSmithyClientSourceFile(final ServiceModel service context.put("CppViewHelper", CppViewHelper.class); selectAuthschemeResolver(serviceModel, context); context.put("AuthSchemeMapEntries", createAuthSchemeMapEntries(serviceModel)); + context.put("AuthSchemes", getSupportedAuthSchemes(serviceModel)); final String fileName; if (i == 0) { @@ -811,6 +806,13 @@ protected String mapAuthSchemes(final String authSchemeName) { throw new RuntimeException(String.format("Unsupported authScheme '%s'", authSchemeName)); } + protected String mapAuthSchemeOptions(final String authSchemeName) { + if (SchemeIdMapping.containsKey(authSchemeName)) { + return SchemeIdMapping.get(authSchemeName); + } + throw new RuntimeException(String.format("Unsupported authScheme '%s'", authSchemeName)); + } + private static final Map SchemeIdMapping = ImmutableMap.of( "aws.auth#sigv4", "smithy::SigV4AuthSchemeOption::sigV4AuthSchemeOption", @@ -822,11 +824,11 @@ protected String mapAuthSchemes(final String authSchemeName) { ); protected static final Map ResolverMapping = ImmutableMap.of( - "aws.auth#sigv4", "SigV4AuthSchemeResolver", - "aws.auth#sigv4a", "SigV4aAuthSchemeResolver", - "bearer", "BearerTokenAuthSchemeResolver", - "v4", "SigV4AuthSchemeResolver", - "v2", "SigV4AuthSchemeResolver" + "aws.auth#sigv4", "GenericAuthSchemeResolver", + "aws.auth#sigv4a", "GenericAuthSchemeResolver", + "bearer", "GenericAuthSchemeResolver", + "v4", "GenericAuthSchemeResolver", + "v2", "GenericAuthSchemeResolver" ); diff --git a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientHeader.vm b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientHeader.vm index af3f00c935e..b10b2c429d9 100644 --- a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientHeader.vm +++ b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientHeader.vm @@ -18,13 +18,16 @@ \#include \#include \#include -#if($serviceModel.hasOnlyBearerAuth()) -\#include +#if($serviceModel.hasBearerAuth()) \#include -#else -\#include +#end +#if($serviceModel.hasSigV4Auth()) \#include #end +#if($serviceModel.hasSigV4aAuth()) +\#include +#end +\#include \#include \#include @@ -45,7 +48,7 @@ namespace ${serviceNamespace} class ${CppViewHelper.computeExportValue($metadata.classNamePrefix)} ${className}${finalClass} : Aws::Client::ClientWithAsyncTemplateMethods<${className}>, smithy::client::AwsSmithyClientT<${rootNamespace}::${serviceNamespace}::SERVICE_NAME, ${serviceConfiguration}, - smithy::${AuthSchemeResolver}<>, + smithy::AuthSchemeResolverBase<>, ${rootNamespace}::Crt::Variant<${AuthSchemeVariants}>, ${metadata.classNamePrefix}EndpointProviderBase, smithy::client::$serializer, diff --git a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientSource.vm b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientSource.vm index c2f06a27eeb..c1de1ec8788 100644 --- a/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientSource.vm +++ b/tools/code-generation/generator/src/main/resources/com/amazonaws/util/awsclientgenerator/velocity/cpp/smithy/SmithyClientSource.vm @@ -18,10 +18,7 @@ \#include #parse("com/amazonaws/util/awsclientgenerator/velocity/cpp/ServiceClientSourceHeaders.vm") -#if($serviceModel.hasOnlyBearerAuth()) -\#include -\#include -#else +#if(!$serviceModel.hasOnlyBearerAuth()) \#include \#include \#include 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 5bb9367b81b..5be03661570 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 @@ -11,7 +11,7 @@ ${className}::${className}(const Aws::Auth::BearerTokenAuthSignerProvider& beare Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared<${metadata.classNamePrefix}ErrorMarshaller>(ALLOCATION_TAG), endpointProvider ? endpointProvider : Aws::MakeShared<${metadata.classNamePrefix}EndpointProvider>(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG, Aws::Vector({$AuthSchemeOptions})), { #foreach($entry in $AuthSchemeMapEntries) {${entry}{Aws::MakeShared(ALLOCATION_TAG, bearerTokenProvider), GetServiceName(), clientConfiguration.region}}, @@ -28,7 +28,7 @@ ${className}::${className}(const Aws::Auth::BearerTokenAuthSignerProvider& beare Aws::Http::CreateHttpClient(clientConfiguration), Aws::MakeShared<${metadata.classNamePrefix}ErrorMarshaller>(ALLOCATION_TAG), Aws::MakeShared<${metadata.classNamePrefix}EndpointProvider>(ALLOCATION_TAG), - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG, Aws::Vector({$AuthSchemeOptions})), { #foreach($entry in $AuthSchemeMapEntries) {${entry}{Aws::MakeShared(ALLOCATION_TAG, bearerTokenProvider), GetServiceName(), clientConfiguration.region}}, @@ -52,7 +52,7 @@ ${className}::${className}(const ${clientConfiguration}& clientConfiguration, Aws::MakeShared<${AuthSchemeResolver}>(ALLOCATION_TAG), #else #if(!$IsMultiAuth) - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG, Aws::Vector({$AuthSchemeOptions})), #else Aws::MakeShared(ALLOCATION_TAG, ${metadata.classNamePrefix}EndpointProvider, ${clientConfiguration}), #end @@ -92,7 +92,7 @@ ${className}::${className}(const AWSCredentials& credentials, Aws::MakeShared<${AuthSchemeResolver}>(ALLOCATION_TAG), #else #if(!$IsMultiAuth) - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG, Aws::Vector({$AuthSchemeOptions})), #else Aws::MakeShared(ALLOCATION_TAG, ${metadata.classNamePrefix}EndpointProvider, ${clientConfiguration}), #end @@ -132,7 +132,7 @@ ${className}::${className}(const std::shared_ptr& creden Aws::MakeShared<${AuthSchemeResolver}>(ALLOCATION_TAG), #else #if(!$IsMultiAuth) - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG, Aws::Vector({$AuthSchemeOptions})), #else Aws::MakeShared(ALLOCATION_TAG, ${metadata.classNamePrefix}EndpointProvider, ${clientConfiguration}), #end @@ -153,7 +153,7 @@ ${className}::${className}(const std::shared_ptr& creden }() #else #foreach($entry in $AuthSchemeMapEntries) - {${entry}{ Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), GetServiceName(), clientConfiguration.region}} + {${entry}{ Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), GetServiceName(), clientConfiguration.region}}, #end #end }) @@ -282,13 +282,13 @@ ${className}::${className}(const Client::ClientConfiguration& clientConfiguratio Aws::MakeShared<${metadata.classNamePrefix}ErrorMarshaller>(ALLOCATION_TAG), Aws::MakeShared<${metadata.classNamePrefix}EndpointProvider>(ALLOCATION_TAG), #if(!$IsMultiAuth) - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG, Aws::Vector({$AuthSchemeOptions})), #else Aws::MakeShared(ALLOCATION_TAG, ${metadata.classNamePrefix}EndpointProvider, ${clientConfiguration}), #end { #foreach($entry in $AuthSchemeMapEntries) - {$entry{Aws::MakeShared(ALLOCATION_TAG), GetServiceName(), clientConfiguration.region}} + {$entry{Aws::MakeShared(ALLOCATION_TAG), GetServiceName(), clientConfiguration.region}}, #end }) {} @@ -302,13 +302,13 @@ ${className}::${className}(const AWSCredentials& credentials, Aws::MakeShared<${metadata.classNamePrefix}ErrorMarshaller>(ALLOCATION_TAG), Aws::MakeShared<${metadata.classNamePrefix}EndpointProvider>(ALLOCATION_TAG), #if(!$IsMultiAuth) - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG, Aws::Vector({$AuthSchemeOptions})), #else Aws::MakeShared(ALLOCATION_TAG, ${metadata.classNamePrefix}EndpointProvider, ${clientConfiguration}), #end { #foreach($entry in $AuthSchemeMapEntries) - {$entry{Aws::MakeShared(ALLOCATION_TAG, credentials), GetServiceName(), clientConfiguration.region}} + {$entry{Aws::MakeShared(ALLOCATION_TAG, credentials), GetServiceName(), clientConfiguration.region}}, #end }) {} @@ -322,12 +322,12 @@ ${className}::${className}(const std::shared_ptr& creden Aws::MakeShared<${metadata.classNamePrefix}ErrorMarshaller>(ALLOCATION_TAG), Aws::MakeShared<${metadata.classNamePrefix}EndpointProvider>(ALLOCATION_TAG), #if(!$IsMultiAuth) - Aws::MakeShared>(ALLOCATION_TAG), + Aws::MakeShared>(ALLOCATION_TAG, Aws::Vector({$AuthSchemeOptions})), #else Aws::MakeShared(ALLOCATION_TAG, ${metadata.classNamePrefix}EndpointProvider, ${clientConfiguration}), #end { #foreach($entry in $AuthSchemeMapEntries) - {$entry{Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), GetServiceName(), clientConfiguration.region}} + {$entry{Aws::MakeShared(ALLOCATION_TAG, credentialsProvider), GetServiceName(), clientConfiguration.region}}, #end }) {}