Skip to content

Commit

Permalink
Sigv4a support (#3073)
Browse files Browse the repository at this point in the history
* Fix build on smithy client with test actually allocating a client

* test client auth workflow

* test changes

* compile fix

* adding working tests for sigv4 and sigv4 a

* changes to allow mocks for testing

* auth a signer changes, test not working

* working tests

* spell fix

* fixes

* make test case consistent

* remove cout

* added cv

* fix for warning

* fix warning

* fix warning

* fix warning

* fix warning

---------

Co-authored-by: SergeyRyabinin <[email protected]>
  • Loading branch information
sbera87 and SergeyRyabinin authored Aug 19, 2024
1 parent 611a3c0 commit babff22
Show file tree
Hide file tree
Showing 13 changed files with 625 additions and 67 deletions.
29 changes: 15 additions & 14 deletions src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,19 @@ namespace client
class AwsSmithyClientT : public AwsSmithyClientBase
{
public:
AwsSmithyClientT(const ServiceClientConfigurationT& clientConfig, const Aws::String& serviceName,
explicit AwsSmithyClientT(const ServiceClientConfigurationT& clientConfig, const Aws::String& serviceName,
const std::shared_ptr<Aws::Http::HttpClient>& httpClient,
const std::shared_ptr<Aws::Client::AWSErrorMarshaller>& errorMarshaller,
const ServiceClientConfigurationT& m_client_config,
const std::shared_ptr<EndpointProviderT> endpointProvider,
const std::shared_ptr<ServiceAuthSchemeResolverT>& m_auth_scheme_resolver,
const Aws::UnorderedMap<Aws::String, AuthSchemesVariantT>& m_auth_schemes)
const std::shared_ptr<ServiceAuthSchemeResolverT>& authSchemeResolver,
const Aws::UnorderedMap<Aws::String, AuthSchemesVariantT>& authSchemes)
: AwsSmithyClientBase(clientConfig, serviceName, httpClient, errorMarshaller),
m_clientConfig(m_client_config),
m_clientConfig(clientConfig),
m_endpointProvider(endpointProvider),
m_authSchemeResolver(m_auth_scheme_resolver),
m_authSchemes(m_auth_schemes)
m_authSchemeResolver(authSchemeResolver),
m_authSchemes(authSchemes)
{
if (ServiceNameT) {
m_serviceName = ServiceNameT;
}
m_serviceName = ServiceNameT;
}

virtual ~AwsSmithyClientT() = default;
Expand All @@ -70,28 +67,32 @@ namespace client
assert(m_authSchemeResolver);
typename ServiceAuthSchemeResolverT::ServiceAuthSchemeParameters identityParams;

identityParams.serviceName = m_serviceName;
identityParams.operation = ctx.m_requestName;
identityParams.region = m_clientConfig.region;

if (ctx.m_pRequest) {
// refactor once auth scheme resolver will use it's own rule set
const auto& epParams = ctx.m_pRequest->GetEndpointContextParams();
for (const auto& epParam : epParams) {
using ParameterType = Aws::Endpoint::EndpointParameter::ParameterType;
if(epParam.GetStoredType() == ParameterType::STRING)
identityParams.insert({epParam.GetName(), epParam.GetStrValueNoCheck()});
identityParams.additionalProperties.insert({epParam.GetName(), epParam.GetStrValueNoCheck()});
else if (epParam.GetStoredType() == ParameterType::BOOLEAN)
identityParams.insert({epParam.GetName(), epParam.GetBoolValueNoCheck()});
identityParams.additionalProperties.insert({epParam.GetName(), epParam.GetBoolValueNoCheck()});
else
assert(!"Unknown endpoint parameter!");
}
const auto& serviceParams = ctx.m_pRequest->GetServiceSpecificParameters();
if (serviceParams) {
for (const auto& serviceParam : serviceParams->parameterMap) {
identityParams.insert({serviceParam.first, serviceParam.second});
identityParams.additionalProperties.insert({serviceParam.first, serviceParam.second});
}
}
}
Aws::Vector<AuthSchemeOption> authSchemeOptions = m_authSchemeResolver->resolveAuthScheme(identityParams);

auto authSchemeOptionIt = std::find_first_of(authSchemeOptions.begin(), authSchemeOptions.end(),
auto authSchemeOptionIt = std::find_if(authSchemeOptions.begin(), authSchemeOptions.end(),
[this](const AuthSchemeOption& opt)
{
return m_authSchemes.find(opt.schemeId) != m_authSchemes.end();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ namespace client
{
class AwsSmithyClientAsyncRequestContext;
/* Non-template base client class that contains main Aws Client Request pipeline logic */
class AwsSmithyClientBase
class SMITHY_API AwsSmithyClientBase
{
public:
using HttpRequest = Aws::Http::HttpRequest;
Expand All @@ -77,7 +77,7 @@ namespace client
using SelectAuthSchemeOptionOutcome = Aws::Utils::Outcome<AuthSchemeOption, AWSError>;
using ResolveEndpointOutcome = Aws::Utils::Outcome<Aws::Endpoint::AWSEndpoint, AWSError>;

AwsSmithyClientBase(Aws::Client::ClientConfiguration& clientConfig,
AwsSmithyClientBase(const Aws::Client::ClientConfiguration& clientConfig,
Aws::String serviceName,
std::shared_ptr<Aws::Http::HttpClient> httpClient,
std::shared_ptr<Aws::Client::AWSErrorMarshaller> errorMarshaller) :
Expand Down Expand Up @@ -127,7 +127,7 @@ namespace client
virtual bool AdjustClockSkew(HttpResponseOutcome& outcome, const AuthSchemeOption& authSchemeOption) const = 0;

protected:
Aws::Client::ClientConfiguration& m_clientConfig;
Aws::Client::ClientConfiguration m_clientConfig;
Aws::String m_serviceName;
Aws::String m_userAgent;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ namespace smithy
static SigningOutcome SignRequest(std::shared_ptr<HttpRequest> HTTPRequest, const AuthSchemeOption& authSchemeOption,
const Aws::UnorderedMap<Aws::String, AuthSchemesVariantT>& authSchemes)
{

auto authSchemeIt = authSchemes.find(authSchemeOption.schemeId);
if (authSchemeIt == authSchemes.end())
{
Expand All @@ -51,7 +52,7 @@ namespace smithy
false/*retryable*/));
}

AuthSchemesVariantT authScheme = *authSchemeIt;
const AuthSchemesVariantT& authScheme = authSchemeIt->second;

return SignWithAuthScheme(std::move(HTTPRequest), authScheme, authSchemeOption);
}
Expand All @@ -71,10 +72,10 @@ namespace smithy
assert(!"Auth scheme has not been found for a given auth option!");
return false;
}
AuthSchemesVariantT authScheme = *authSchemeIt;
AuthSchemesVariantT authScheme = authSchemeIt->second;

ClockSkewVisitor visitor(outcome, serverTime, authSchemeOption);
visitor.Visit(authScheme);
authScheme.Visit(visitor);

return visitor.m_resultShouldWait;
}
Expand All @@ -99,7 +100,7 @@ namespace smithy
// Auth Scheme Variant alternative contains the requested auth option
assert(strcmp(authScheme.schemeId, m_targetAuthSchemeOption.schemeId) == 0);

using IdentityT = typename decltype(authScheme)::IdentityT;
using IdentityT = typename std::remove_reference<decltype(authScheme)>::type::IdentityT;
using IdentityResolver = IdentityResolverBase<IdentityT>;
using Signer = AwsSignerBase<IdentityT>;

Expand All @@ -113,12 +114,14 @@ namespace smithy
return;
}

static_assert(
std::is_same<IdentityResolverBase<IdentityT>, typename decltype(identityResolver
)::IdentityT>::value, "Must be the same type");
static_assert(std::is_base_of<IdentityResolverBase<IdentityT>, decltype(identityResolver)>::value, "Must be the same type");
auto identityResult = identityResolver->getIdentity(m_targetAuthSchemeOption.identityProperties, m_targetAuthSchemeOption.identityProperties);

IdentityT identity = identityResolver->getIdentity(m_targetAuthSchemeOption.identityProperties);
if (!identityResult.IsSuccess())
{
result.emplace(identityResult.GetError());
return;
}
auto identity = std::move(identityResult.GetResultWithOwnership());

std::shared_ptr<Signer> signer = authScheme.signer();
if (!signer)
Expand All @@ -130,11 +133,7 @@ namespace smithy
return;
}


static_assert(std::is_same<AwsSignerBase<IdentityT>, typename decltype(signer)::IdentityT>::value, "Must be the same type");
static_assert(std::is_base_of<AwsSignerBase<IdentityT>, decltype(signer)>::value, "Must be the same type");

result.emplace(signer->sign(m_httpRequest, identity, m_targetAuthSchemeOption.signerProperties));
result.emplace(signer->sign(m_httpRequest, *identity, m_targetAuthSchemeOption.signerProperties));
}
};

Expand All @@ -143,7 +142,8 @@ namespace smithy
const AuthSchemeOption& targetAuthSchemeOption)
{
SignerVisitor visitor(httpRequest, targetAuthSchemeOption);
visitor.Visit(authSchemesVariant);
AuthSchemesVariantT authSchemesVariantCopy(authSchemesVariant); // TODO: allow const visiting
authSchemesVariantCopy.Visit(visitor);

if (!visitor.result)
{
Expand Down Expand Up @@ -177,7 +177,7 @@ namespace smithy
// Auth Scheme Variant alternative contains the requested auth option
assert(strcmp(authScheme.schemeId, m_targetAuthSchemeOption.schemeId) == 0);

using IdentityT = typename decltype(authScheme)::IdentityT;
using IdentityT = typename std::remove_reference<decltype(authScheme)>::type::IdentityT;
using Signer = AwsSignerBase<IdentityT>;

std::shared_ptr<Signer> signer = authScheme.signer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ namespace smithy {
Aws::String operation;
Aws::Crt::Optional<Aws::String> region;

Aws::UnorderedMap<Aws::String, Aws::Crt::Variant<Aws::String, bool>> additionalProperties;
Aws::UnorderedMap<Aws::String, Aws::Crt::Variant<Aws::String,
bool,
Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy,
Aws::Auth::AWSSigningAlgorithm > > additionalProperties;

};

template<typename ServiceAuthSchemeParametersT = DefaultAuthSchemeResolverParameters>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#include <smithy/identity/identity/AwsCredentialIdentityBase.h>
#include <smithy/identity/signer/built-in/SigV4Signer.h>

#include <smithy/identity/auth/built-in/SigV4AuthScheme.h>


namespace smithy {
Expand All @@ -24,16 +24,24 @@ namespace smithy {
using AwsCredentialSignerT = AwsSignerBase<IdentityT>;
using SigV4AuthSchemeParameters = DefaultAuthSchemeResolverParameters;

explicit SigV4AuthScheme(const SigV4AuthSchemeParameters& parameters)
: AuthScheme(SIGV4)
//This allows to override the identity resolver
explicit SigV4AuthScheme(std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver,
const SigV4AuthSchemeParameters& parameters)
: AuthScheme(SIGV4),
m_identityResolver{identityResolver},
m_signer{Aws::MakeShared<AwsSigV4Signer>("SigV4AuthScheme", parameters)}
{
m_identityResolver = Aws::MakeShared<DefaultAwsCredentialIdentityResolver>("SigV4AuthScheme");
assert(m_identityResolver);

m_signer = Aws::MakeShared<AwsSigV4Signer>("SigV4AuthScheme", parameters);
assert(m_signer);
}

//delegate constructor
explicit SigV4AuthScheme(const SigV4AuthSchemeParameters& parameters)
: SigV4AuthScheme(Aws::MakeShared<DefaultAwsCredentialIdentityResolver>("SigV4AuthScheme"),
parameters)
{
}

virtual ~SigV4AuthScheme() = default;

std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver() override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#pragma once

#include <smithy/identity/auth/AuthScheme.h>
#include <smithy/identity/auth/built-in/SigV4aAuthSchemeOption.h>

#include <smithy/identity/resolver/built-in/DefaultAwsCredentialIdentityResolver.h>

#include <smithy/identity/identity/AwsCredentialIdentityBase.h>
#include <smithy/identity/signer/built-in/SigV4aSigner.h>


namespace smithy {
constexpr char SIGV4A[] = "aws.auth#sigv4a";


class SigV4aAuthScheme : public AuthScheme<AwsCredentialIdentityBase>
{
public:
using AwsCredentialIdentityResolverT = IdentityResolverBase<IdentityT>;
using AwsCredentialSignerT = AwsSignerBase<IdentityT>;
using SigV4aAuthSchemeParameters = DefaultAuthSchemeResolverParameters;

//This allows to override the identity resolver
explicit SigV4aAuthScheme(std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver,
const SigV4aAuthSchemeParameters& parameters)
: AuthScheme(SIGV4A),
m_identityResolver{identityResolver},
m_signer{Aws::MakeShared<AwsSigV4aSigner>("SigV4aAuthScheme", parameters)}
{
assert(m_identityResolver);
assert(m_signer);
}

explicit SigV4aAuthScheme(const SigV4aAuthSchemeParameters& parameters)
: SigV4aAuthScheme(Aws::MakeShared<DefaultAwsCredentialIdentityResolver>("SigV4aAuthScheme"),parameters )
{
assert(m_identityResolver);

assert(m_signer);
}

virtual ~SigV4aAuthScheme() = default;

std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver() override
{
return m_identityResolver;
}

std::shared_ptr<AwsCredentialSignerT> signer() override
{
return m_signer;
}
protected:
std::shared_ptr<AwsCredentialIdentityResolverT> m_identityResolver;
std::shared_ptr<AwsCredentialSignerT> m_signer;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#pragma once

#include <smithy/identity/auth/AuthSchemeOption.h>

namespace smithy {
struct SigV4aAuthSchemeOption
{
static AuthSchemeOption sigV4aAuthSchemeOption;
};

AuthSchemeOption SigV4aAuthSchemeOption::sigV4aAuthSchemeOption = AuthSchemeOption("aws.auth#sigv4a");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#pragma once

#include <smithy/identity/auth/AuthSchemeResolverBase.h>
#include <smithy/identity/auth/built-in/SigV4aAuthSchemeOption.h>


namespace smithy {
template<typename ServiceAuthSchemeParametersT = DefaultAuthSchemeResolverParameters>
class SigV4aAuthSchemeResolver : public AuthSchemeResolverBase<ServiceAuthSchemeParametersT>
{
public:
using ServiceAuthSchemeParameters = ServiceAuthSchemeParametersT;
virtual ~SigV4aAuthSchemeResolver() = default;

Aws::Vector<AuthSchemeOption> resolveAuthScheme(const ServiceAuthSchemeParameters& identityProperties) override
{
AWS_UNREFERENCED_PARAM(identityProperties);
return {SigV4aAuthSchemeOption::sigV4aAuthSchemeOption};
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,46 @@
#include <aws/core/auth/AWSCredentialsProviderChain.h>

namespace smithy {
constexpr char ALLOC_ID[] = "DefaultAwsCredentialIdentityResolver";
/**
* A smithy SigV4 AWS Credentials resolver wrapper on top of legacy SDK Credentials provider
* TODO: refactor into own signer using smithy design
*/
class DefaultAwsCredentialIdentityResolver : public AwsCredentialIdentityResolver {
protected:

mutable std::shared_ptr<Aws::Auth::AWSCredentialsProviderChain> legacyChain_sp;

//mutable Aws::Auth::DefaultAWSCredentialsProviderChain legacyCredentialsProvider{};
public:
using SigV4AuthSchemeParameters = DefaultAuthSchemeResolverParameters;

DefaultAwsCredentialIdentityResolver() = default;
DefaultAwsCredentialIdentityResolver(): legacyChain_sp{Aws::MakeShared<Aws::Auth::DefaultAWSCredentialsProviderChain>(ALLOC_ID)}{

};

DefaultAwsCredentialIdentityResolver(std::shared_ptr<Aws::Auth::AWSCredentialsProviderChain> providerChain): legacyChain_sp{providerChain}
{
assert(legacyChain_sp);
};

ResolveIdentityFutureOutcome getIdentity(const IdentityProperties& identityProperties, const AdditionalParameters& additionalParameters) override
{
AWS_UNREFERENCED_PARAM(identityProperties);
AWS_UNREFERENCED_PARAM(additionalParameters);

auto legacyCreds = legacyCredentialsProvider.GetAWSCredentials();
auto legacyCreds = legacyChain_sp->GetAWSCredentials();

auto smithyCreds = Aws::MakeUnique<AwsCredentialIdentity>("DefaultAwsCredentialIdentityResolver",
legacyCreds.GetAWSAccessKeyId(), legacyCreds.GetAWSSecretKey(),
legacyCreds.GetSessionToken(), legacyCreds.GetExpiration());
legacyCreds.GetAWSAccessKeyId(),
legacyCreds.GetAWSSecretKey(),
legacyCreds.GetSessionToken().empty()? Aws::Crt::Optional<Aws::String>() : legacyCreds.GetSessionToken(),
legacyCreds.GetExpiration());

return ResolveIdentityFutureOutcome(std::move(smithyCreds));
}

virtual ~DefaultAwsCredentialIdentityResolver() {};
protected:
mutable Aws::Auth::DefaultAWSCredentialsProviderChain legacyCredentialsProvider{};

};
}
Loading

0 comments on commit babff22

Please sign in to comment.