Skip to content

Commit

Permalink
wip - wire smithy client to use account id resolved from identity for…
Browse files Browse the repository at this point in the history
… endpoint paramters
  • Loading branch information
sbiscigl committed Feb 26, 2025
1 parent ee92bb3 commit 0c80e29
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 34 deletions.
17 changes: 15 additions & 2 deletions src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,29 @@ namespace client
false/*retryable*/);
}

SigningOutcome SignHttpRequest(std::shared_ptr<HttpRequest> httpRequest, const AuthSchemeOption& targetAuthSchemeOption) const override
SigningOutcome SignHttpRequest(std::shared_ptr<HttpRequest> httpRequest, const AwsSmithyClientAsyncRequestContext& ctx) const override
{
return AwsClientRequestSigning<AuthSchemesVariantT>::SignRequest(httpRequest, targetAuthSchemeOption, m_authSchemes);
return AwsClientRequestSigning<AuthSchemesVariantT>::SignRequest(httpRequest, ctx, m_authSchemes);
}

bool AdjustClockSkew(HttpResponseOutcome& outcome, const AuthSchemeOption& authSchemeOption) const override
{
return AwsClientRequestSigning<AuthSchemesVariantT>::AdjustClockSkew(outcome, authSchemeOption, m_authSchemes);
}

IdentityOutcome ResolveIdentity(const AwsSmithyClientAsyncRequestContext& ctx) const override {
// TODO: return identity as outcome
AWS_UNREFERENCED_PARAM(ctx);
return AWSError{CoreErrors::UNKNOWN, "NotImplemented", "method not implemented", false};
}

RefreshBuiltInOutcome RefreshBuiltinParameters(const AwsSmithyClientAsyncRequestContext& ctx) const override {
//TODO: template specialization when ServiceClientConfigurationT doesnt have account id
//TODO: use identity in context to get account id
AWS_UNREFERENCED_PARAM(ctx);
return AWSError{CoreErrors::UNKNOWN, "NotImplemented", "method not implemented", false};
};

ResponseT MakeRequestDeserialize(Aws::AmazonWebServiceRequest const * const request,
const char* requestName,
Aws::Http::HttpMethod method,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ namespace smithy
ResponseHandlerFunc m_responseHandler;
std::shared_ptr<Aws::Utils::Threading::Executor> m_pExecutor;
std::shared_ptr<interceptor::InterceptorContext> m_interceptorContext;
std::shared_ptr<smithy::AwsIdentity> m_awsIdentity;
};
} // namespace client
} // namespace smithy
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <aws/core/utils/FutureOutcome.h>
#include <aws/core/utils/memory/stl/AWSMap.h>
#include <aws/core/utils/Outcome.h>
#include <aws/core/NoResult.h>
#include <aws/core/http/HttpClientFactory.h>
#include <aws/core/client/AWSErrorMarshaller.h>
#include <aws/core/AmazonWebServiceResult.h>
Expand Down Expand Up @@ -84,6 +85,8 @@ namespace client
using SelectAuthSchemeOptionOutcome = Aws::Utils::Outcome<AuthSchemeOption, AWSError>;
using ResolveEndpointOutcome = Aws::Utils::Outcome<Aws::Endpoint::AWSEndpoint, AWSError>;
using StreamOutcome = Aws::Utils::Outcome<Aws::AmazonWebServiceResult<Aws::Utils::Stream::ResponseStream>, AWSError >;
using IdentityOutcome = Aws::Utils::Outcome<std::shared_ptr<smithy::AwsIdentity>, AWSError>;
using RefreshBuiltInOutcome = Aws::Utils::Outcome<Aws::NoResult, AWSError>;

AwsSmithyClientBase(Aws::UniquePtr<Aws::Client::ClientConfiguration>&& clientConfig,
Aws::String serviceName,
Expand Down Expand Up @@ -188,8 +191,10 @@ namespace client

virtual ResolveEndpointOutcome ResolveEndpoint(const Aws::Endpoint::EndpointParameters& endpointParameters, EndpointUpdateCallback&& epCallback) const = 0;
virtual SelectAuthSchemeOptionOutcome SelectAuthSchemeOption(const AwsSmithyClientAsyncRequestContext& ctx) const = 0;
virtual SigningOutcome SignHttpRequest(std::shared_ptr<HttpRequest> httpRequest, const AuthSchemeOption& targetAuthSchemeOption) const = 0;
virtual SigningOutcome SignHttpRequest(std::shared_ptr<HttpRequest> httpRequest, const AwsSmithyClientAsyncRequestContext& ctx) const = 0;
virtual bool AdjustClockSkew(HttpResponseOutcome& outcome, const AuthSchemeOption& authSchemeOption) const = 0;
virtual IdentityOutcome ResolveIdentity(const AwsSmithyClientAsyncRequestContext& ctx) const = 0;
virtual RefreshBuiltInOutcome RefreshBuiltinParameters(const AwsSmithyClientAsyncRequestContext& ctx) const = 0;

std::shared_ptr<Aws::Client::ClientConfiguration> m_clientConfig;
Aws::String m_serviceName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ namespace smithy
using SigningOutcome = Aws::Utils::FutureOutcome<std::shared_ptr<HttpRequest>, SigningError>;
using HttpResponseOutcome = Aws::Utils::Outcome<std::shared_ptr<Aws::Http::HttpResponse>, Aws::Client::AWSError<Aws::Client::CoreErrors>>;

static SigningOutcome SignRequest(std::shared_ptr<HttpRequest> HTTPRequest, const AuthSchemeOption& authSchemeOption,
const Aws::UnorderedMap<Aws::String, AuthSchemesVariantT>& authSchemes)
static SigningOutcome SignRequest(std::shared_ptr<HttpRequest> HTTPRequest,
const client::AwsSmithyClientAsyncRequestContext& ctx,
const Aws::UnorderedMap<Aws::String, AuthSchemesVariantT>& authSchemes)
{

auto authSchemeIt = authSchemes.find(authSchemeOption.schemeId);
auto authSchemeIt = authSchemes.find(ctx.m_authSchemeOption.schemeId);
if (authSchemeIt == authSchemes.end())
{
assert(!"Auth scheme has not been found for a given auth option!");
Expand All @@ -55,7 +55,7 @@ namespace smithy

const AuthSchemesVariantT& authScheme = authSchemeIt->second;

return SignWithAuthScheme(std::move(HTTPRequest), authScheme, authSchemeOption);
return SignWithAuthScheme(std::move(HTTPRequest), authScheme, ctx);
}
static SigningOutcome PreSignRequest(std::shared_ptr<HttpRequest> httpRequest,
const AuthSchemeOption& authSchemeOption,
Expand Down Expand Up @@ -115,21 +115,21 @@ namespace smithy
protected:
struct SignerVisitor
{
SignerVisitor(std::shared_ptr<HttpRequest> httpRequest, const AuthSchemeOption& targetAuthSchemeOption)
: m_httpRequest(std::move(httpRequest)), m_targetAuthSchemeOption(targetAuthSchemeOption)
SignerVisitor(std::shared_ptr<HttpRequest> httpRequest, const client::AwsSmithyClientAsyncRequestContext& ctx)
: m_httpRequest(std::move(httpRequest)), m_requestContext(ctx)
{
}

const std::shared_ptr<HttpRequest> m_httpRequest;
const AuthSchemeOption& m_targetAuthSchemeOption;
const client::AwsSmithyClientAsyncRequestContext& m_requestContext;

Aws::Crt::Optional<SigningOutcome> result;

template <typename AuthSchemeAlternativeT>
void operator()(AuthSchemeAlternativeT& authScheme)
{
// Auth Scheme Variant alternative contains the requested auth option
assert(strcmp(authScheme.schemeId, m_targetAuthSchemeOption.schemeId) == 0);
assert(strcmp(authScheme.schemeId, m_requestContext.m_authSchemeOption.schemeId) == 0);

using IdentityT = typename std::remove_reference<decltype(authScheme)>::type::IdentityT;
using IdentityResolver = IdentityResolverBase<IdentityT>;
Expand Down Expand Up @@ -157,15 +157,6 @@ namespace smithy
}
}

auto identityResult = identityResolver->getIdentity(m_targetAuthSchemeOption.identityProperties(), additionalIdentityProperties);

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 @@ -176,7 +167,9 @@ namespace smithy
return;
}

result.emplace(signer->sign(m_httpRequest, *identity, m_targetAuthSchemeOption.signerProperties()));
result.emplace(signer->sign(m_httpRequest,
*static_cast<IdentityT*>(m_requestContext.m_awsIdentity.get()),
m_requestContext.m_authSchemeOption.signerProperties()));
}
};

Expand Down Expand Up @@ -237,10 +230,11 @@ namespace smithy
};

static
SigningOutcome SignWithAuthScheme(std::shared_ptr<HttpRequest> httpRequest, const AuthSchemesVariantT& authSchemesVariant,
const AuthSchemeOption& targetAuthSchemeOption)
SigningOutcome SignWithAuthScheme(std::shared_ptr<HttpRequest> httpRequest,
const AuthSchemesVariantT& authSchemesVariant,
const client::AwsSmithyClientAsyncRequestContext& ctx)
{
SignerVisitor visitor(httpRequest, targetAuthSchemeOption);
SignerVisitor visitor(httpRequest, ctx);
AuthSchemesVariantT authSchemesVariantCopy(authSchemesVariant); // TODO: allow const visiting
authSchemesVariantCopy.Visit(visitor);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,30 @@ void AwsSmithyClientBase::MakeRequestAsync(Aws::AmazonWebServiceRequest const* c
}
pRequestCtx->m_authSchemeOption = std::move(authSchemeOptionOutcome.GetResultWithOwnership());
assert(pRequestCtx->m_authSchemeOption.schemeId);

// resolve identity
auto identityOutcome = this->ResolveIdentity(*pRequestCtx);
if (!identityOutcome.IsSuccess())
{
pExecutor->Submit([identityOutcome, responseHandler]() mutable
{
responseHandler(std::move(identityOutcome));
});
return;
}
pRequestCtx->m_awsIdentity = std::move(identityOutcome.GetResultWithOwnership());

// refresh built-in endpoint params with the request context
const auto refreshBuiltInsOutcome = this->RefreshBuiltinParameters(*pRequestCtx);
if (!refreshBuiltInsOutcome.IsSuccess())
{
pExecutor->Submit([refreshBuiltInsOutcome, responseHandler]() mutable
{
responseHandler(std::move(refreshBuiltInsOutcome.GetError()));
});
return;
}

Aws::Endpoint::EndpointParameters epParams = request ? request->GetEndpointContextParams() : Aws::Endpoint::EndpointParameters();
const auto authSchemeEpParams = pRequestCtx->m_authSchemeOption.endpointParameters();
epParams.insert(epParams.end(), authSchemeEpParams.begin(), authSchemeEpParams.end());
Expand Down Expand Up @@ -323,7 +347,7 @@ void AwsSmithyClientBase::AttemptOneRequestAsync(std::shared_ptr<AwsSmithyClient
};

SigningOutcome signingOutcome = TracingUtils::MakeCallWithTiming<SigningOutcome>([&]() -> SigningOutcome {
return this->SignHttpRequest(pRequestCtx->m_httpRequest, pRequestCtx->m_authSchemeOption);
return this->SignHttpRequest(pRequestCtx->m_httpRequest, *pRequestCtx);
},
TracingUtils::SMITHY_CLIENT_SIGNING_METRIC,
*m_clientConfig->telemetryProvider->getMeter(this->GetServiceClientName(), {}),
Expand Down
16 changes: 8 additions & 8 deletions tests/aws-cpp-sdk-core-tests/smithy/client/SmithyClientTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,9 @@ class TestClient : public MySmithyClient
return MySmithyClient::SelectAuthSchemeOption(ctx);
}

SigningOutcome SignRequest(std::shared_ptr<HttpRequest> httpRequest, const smithy::AuthSchemeOption& targetAuthSchemeOption) const
SigningOutcome SignRequest(std::shared_ptr<HttpRequest> httpRequest, const smithy::client::AwsSmithyClientAsyncRequestContext& ctx) const
{
return MySmithyClient::SignHttpRequest(httpRequest, targetAuthSchemeOption);
return MySmithyClient::SignHttpRequest(httpRequest, ctx);
}


Expand Down Expand Up @@ -239,15 +239,15 @@ TEST_F(SmithyClientTest, testSigV4) {
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();

Aws::String uri{"https://treasureisland-cb93079d-24a0-4862-8es2-88456ead.xyz.amazonaws.com"};

std::shared_ptr<Aws::Http::HttpRequest> httpRequest(Aws::Http::CreateHttpRequest(uri, Aws::Http::HttpMethod::HTTP_GET, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod));

auto res2 = ptr->SignRequest(httpRequest, res.GetResult());
auto res2 = ptr->SignRequest(httpRequest, ctx);

EXPECT_EQ(res2.IsSuccess(), true);
EXPECT_EQ(res2.GetResult()->GetSigningAccessKey(), "dummyAccessId");
Expand Down Expand Up @@ -287,15 +287,15 @@ TEST_F(SmithyClientTest, testSigV4a) {
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();

Aws::String uri{"https://treasureisland-cb93079d-24a0-4862-8es2-88456ead.xyz.amazonaws.com"};

std::shared_ptr<Aws::Http::HttpRequest> httpRequest(Aws::Http::CreateHttpRequest(uri, Aws::Http::HttpMethod::HTTP_GET, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod));

auto res2 = ptr->SignRequest(httpRequest, res.GetResult());
auto res2 = ptr->SignRequest(httpRequest, ctx);

EXPECT_EQ(res2.IsSuccess(), true);

Expand Down Expand Up @@ -333,9 +333,9 @@ TEST_F(SmithyClientTest, bearer)
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();

Aws::String uri{
"https://"
Expand All @@ -346,7 +346,7 @@ TEST_F(SmithyClientTest, bearer)
uri, Aws::Http::HttpMethod::HTTP_GET,
Aws::Utils::Stream::DefaultResponseStreamFactoryMethod));

auto res2 = ptr->SignRequest(httpRequest, res.GetResult());
auto res2 = ptr->SignRequest(httpRequest, ctx);

EXPECT_EQ(res2.IsSuccess(), true);

Expand Down

0 comments on commit 0c80e29

Please sign in to comment.