Skip to content

Commit

Permalink
Smithy Bearer Auth (#3102)
Browse files Browse the repository at this point in the history
* bearer token placeholder

* test placeholder

* more placeholder changes

* fixes

* fixes wip

* fixes

* make tests functional

* make test provider the first in chain for test

* cleanup

* run clang formatter llvm

* remove redundant headers

* fix scheme id name

* fixes

* address comments
  • Loading branch information
sbera87 authored Sep 10, 2024
1 parent c5c1967 commit 5913125
Show file tree
Hide file tree
Showing 9 changed files with 371 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#pragma once

#include <smithy/identity/auth/AuthScheme.h>
#include <smithy/identity/auth/built-in/BearerTokenAuthSchemeOption.h>
#include <smithy/identity/identity/AwsBearerTokenIdentityBase.h>
#include <smithy/identity/resolver/AwsBearerTokenIdentityResolver.h>
#include <smithy/identity/signer/built-in/BearerTokenSigner.h>
namespace smithy
{
class BearerTokenAuthScheme : public AuthScheme<AwsBearerTokenIdentityBase>
{
public:
using AwsCredentialIdentityResolverT = IdentityResolverBase<IdentityT>;
using AwsCredentialSignerT = AwsSignerBase<IdentityT>;
using BearerTokenAuthSchemeParameters = DefaultAuthSchemeResolverParameters;

// This allows to override the identity resolver
explicit BearerTokenAuthScheme(
std::shared_ptr<AwsCredentialIdentityResolverT> identityResolver,
const Aws::String &serviceName, const Aws::String &region)
: AuthScheme("smithy.api#HTTPBearerAuth"),
m_identityResolver{identityResolver},
m_signer{Aws::MakeShared<smithy::BearerTokenSigner>(
"BearerTokenAuthScheme", serviceName, region)}
{
assert(m_identityResolver);
assert(m_signer);
}

explicit BearerTokenAuthScheme(const Aws::String &serviceName,
const Aws::String &region)
: BearerTokenAuthScheme(
Aws::MakeShared<DefaultAwsBearerTokenIdentityResolver>(
"BearerTokenAuthScheme"),
serviceName, region)
{
assert(m_identityResolver);

assert(m_signer);
}

virtual ~BearerTokenAuthScheme() = default;

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

std::shared_ptr<AwsCredentialSignerT> signer() override { return m_signer; }

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

#include <smithy/identity/auth/AuthSchemeOption.h>
namespace smithy
{
struct BearerTokenAuthSchemeOption
{
static AuthSchemeOption bearerTokenAuthSchemeOption;
};

AuthSchemeOption BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption =
AuthSchemeOption("smithy.api#HTTPBearerAuth");
} // namespace smithy
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#pragma once

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

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

Aws::Vector<AuthSchemeOption> resolveAuthScheme(
const ServiceAuthSchemeParameters &identityProperties) override
{
AWS_UNREFERENCED_PARAM(identityProperties);
return {BearerTokenAuthSchemeOption::bearerTokenAuthSchemeOption};
}
};
} // namespace smithy
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,17 @@
namespace smithy {
class AwsBearerTokenIdentity : public AwsBearerTokenIdentityBase {
public:
virtual Aws::String token() override;
virtual const Aws::String &token() const override;

virtual Aws::Crt::Optional<AwsIdentity::DateTime> expiration() override;
virtual Aws::Crt::Optional<AwsIdentity::DateTime>
expiration() const override;

Aws::String &token() { return m_token; }

Aws::Crt::Optional<AwsIdentity::DateTime> &expiration()
{
return m_expiration;
}

protected:
Aws::String m_token;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
namespace smithy {
class AwsBearerTokenIdentityBase : public AwsIdentity {
public:
virtual Aws::String token() = 0;
virtual const Aws::String &token() const = 0;

virtual Aws::Crt::Optional<AwsIdentity::DateTime> expiration() override = 0 ;
virtual Aws::Crt::Optional<AwsIdentity::DateTime>
expiration() const override = 0;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
#include <smithy/identity/identity/AwsBearerTokenIdentity.h>

namespace smithy {
Aws::String AwsBearerTokenIdentity::token() {
return m_token;
}
const Aws::String &AwsBearerTokenIdentity::token() const { return m_token; }

Aws::Crt::Optional<AwsIdentity::DateTime> AwsBearerTokenIdentity::expiration() {
return m_expiration;
}
Aws::Crt::Optional<AwsIdentity::DateTime>
AwsBearerTokenIdentity::expiration() const
{
return m_expiration;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,94 @@
*/
#pragma once

#include <aws/core/auth/bearer-token-provider/AWSBearerTokenProviderBase.h>
#include <aws/core/auth/bearer-token-provider/SSOBearerTokenProvider.h>
#include <smithy/identity/identity/AwsBearerTokenIdentity.h>
#include <smithy/identity/resolver/AwsIdentityResolverBase.h>

#include <smithy/identity/identity/AwsBearerTokenIdentity.h>
namespace smithy
{

class AwsBearerTokenIdentityResolver
: public IdentityResolverBase<AwsBearerTokenIdentityBase>
{
public:
static const char BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG[];

using IdentityT = AwsBearerTokenIdentity;
virtual ~AwsBearerTokenIdentityResolver() = default;

AwsBearerTokenIdentityResolver() = default;

AwsBearerTokenIdentityResolver(
const Aws::Vector<
std::shared_ptr<Aws::Auth::AWSBearerTokenProviderBase>>
&providerChain)
: m_providerChainLegacy{providerChain}
{
}

ResolveIdentityFutureOutcome
getIdentity(const IdentityProperties &identityProperties,
const AdditionalParameters &additionalParameters) override
{
AWS_UNREFERENCED_PARAM(identityProperties);
AWS_UNREFERENCED_PARAM(additionalParameters);
for (auto &bearerTokenProvider : m_providerChainLegacy)
{
if (!bearerTokenProvider)
{
AWS_LOGSTREAM_FATAL(
BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG,
"Unexpected nullptr in "
"DefaultBearerTokenProviderChain::m_providerChain");
return Aws::Client::AWSError<Aws::Client::CoreErrors>(
Aws::Client::CoreErrors::INVALID_PARAMETER_VALUE, "",
"Unexpected nullptr in "
"BearerTokenProviderChain::m_providerChain",
false);
}
auto bearerToken = bearerTokenProvider->GetAWSBearerToken();
if (!bearerToken.IsExpiredOrEmpty())
{
auto outcomePtr = Aws::MakeUnique<AwsBearerTokenIdentity>(
BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG);
outcomePtr->token() = bearerToken.GetToken();
outcomePtr->expiration() = bearerToken.GetExpiration();
return ResolveIdentityFutureOutcome(std::move(outcomePtr));
}
}

return Aws::Client::AWSError<Aws::Client::CoreErrors>(
Aws::Client::CoreErrors::NOT_INITIALIZED, "",
"No bearer token provider in chain found", false);
}

void AddBearerTokenProvider(
std::shared_ptr<Aws::Auth::AWSBearerTokenProviderBase> provider)
{
m_providerChainLegacy.emplace_back(std::move(provider));
}

protected:
Aws::Vector<std::shared_ptr<Aws::Auth::AWSBearerTokenProviderBase>>
m_providerChainLegacy;
};

class DefaultAwsBearerTokenIdentityResolver
: public AwsBearerTokenIdentityResolver
{
public:
using IdentityT = AwsBearerTokenIdentity;
virtual ~DefaultAwsBearerTokenIdentityResolver() = default;

namespace smithy {
class AwsBearerTokenIdentityResolver : public IdentityResolverBase<AwsBearerTokenIdentity> {
public:
using IdentityT = AwsBearerTokenIdentity;
virtual ~AwsBearerTokenIdentityResolver() = default;
DefaultAwsBearerTokenIdentityResolver()
: AwsBearerTokenIdentityResolver(
{Aws::MakeShared<Aws::Auth::SSOBearerTokenProvider>(
"SSOBearerTokenProvider")}){};
};
const char
AwsBearerTokenIdentityResolver::BEARER_TOKEN_PROVIDER_CHAIN_LOG_TAG[] =
"BearerTokenProvider";

ResolveIdentityFutureOutcome getIdentity(const IdentityProperties& identityProperties, const AdditionalParameters& additionalParameters) override = 0;
};
}
} // namespace smithy
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

#pragma once

#include <smithy/identity/identity/AwsBearerTokenIdentityBase.h>
#include <smithy/identity/signer/AwsSignerBase.h>

#include <aws/core/auth/signer/AWSAuthSignerHelper.h>
#include <aws/core/http/HttpRequest.h>
#include <aws/crt/http/HttpConnection.h>
#include <aws/crt/http/HttpRequestResponse.h>

namespace smithy
{
static const char AUTHORIZATION_HEADER[] = "authorization";

class BearerTokenSigner : public AwsSignerBase<AwsBearerTokenIdentityBase>
{

public:
static const char LOGGING_TAG[];

using BearerTokenAuthSchemeParameters =
smithy::DefaultAuthSchemeResolverParameters;
explicit BearerTokenSigner(const Aws::String &serviceName,
const Aws::String &region)
: m_serviceName(serviceName), m_region(region)
{
}

SigningFutureOutcome
sign(std::shared_ptr<HttpRequest> httpRequest,
const smithy::AwsBearerTokenIdentityBase &identity,
SigningProperties properties) override
{
AWS_UNREFERENCED_PARAM(properties);

if (Aws::Http::Scheme::HTTPS != httpRequest->GetUri().GetScheme())
{
// Clients MUST always use TLS (https) or equivalent transport
// security when making requests with bearer tokens.
// https://datatracker.ietf.org/doc/html/rfc6750
AWS_LOGSTREAM_ERROR(
LOGGING_TAG,
"HTTPS scheme must be used with a bearer token authorization");
return SigningError(
Aws::Client::CoreErrors::INVALID_PARAMETER_VALUE, "",
"Failed to sign the request with bearer", false);
}

httpRequest->SetHeaderValue(AUTHORIZATION_HEADER,
"Bearer " + identity.token());

return SigningFutureOutcome(std::move(httpRequest));
}

virtual ~BearerTokenSigner(){};

protected:
Aws::String m_serviceName;
Aws::String m_region;
};

const char BearerTokenSigner::LOGGING_TAG[] = "BearerTokenSigner";
} // namespace smithy
Loading

0 comments on commit 5913125

Please sign in to comment.