Skip to content

Set user configured CA file and path to the S3 CRT client #2530

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5614,9 +5614,9 @@ namespace Aws
const Aws::Http::URI &uri, Aws::Http::HttpMethod method) const;
S3CrtClientConfiguration m_clientConfiguration;
std::shared_ptr<Utils::Threading::Executor> m_executor;
struct aws_s3_client* m_s3CrtClient;
struct aws_signing_config_aws m_s3CrtSigningConfig;
struct CrtClientShutdownCallbackDataWrapper m_wrappedData;
struct aws_s3_client* m_s3CrtClient = {};
struct aws_signing_config_aws m_s3CrtSigningConfig = {};
struct CrtClientShutdownCallbackDataWrapper m_wrappedData = {};
std::shared_ptr<Aws::Utils::Threading::Semaphore> m_clientShutdownSem;
Aws::String m_userAgent;
std::shared_ptr<Aws::Auth::AWSCredentialsProvider> m_credProvider;
Expand Down
54 changes: 43 additions & 11 deletions generated/src/aws-cpp-sdk-s3-crt/source/S3CrtClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,10 @@ S3CrtClient::S3CrtClient(const std::shared_ptr<AWSCredentialsProvider>& credenti
S3CrtClient::~S3CrtClient()
{
aws_s3_client_release(m_s3CrtClient);
m_clientShutdownSem->WaitOne(); // Wait aws_s3_client shutdown
if(m_clientShutdownSem)
{
m_clientShutdownSem->WaitOne(); // Wait aws_s3_client shutdown
}
ShutdownSdkClient(this, -1);
}

Expand Down Expand Up @@ -261,20 +264,48 @@ void S3CrtClient::init(const S3Crt::ClientConfiguration& config, const std::shar
static const size_t DEFAULT_PART_SIZE = 5 * 1024 * 1024; // 5MB
s3CrtConfig.part_size = config.partSize < DEFAULT_PART_SIZE ? DEFAULT_PART_SIZE : config.partSize;

Aws::Crt::Io::TlsConnectionOptions* tlsConnectionOptions = config.tlsConnectionOptions ? config.tlsConnectionOptions.get() : Aws::GetDefaultTlsConnectionOptions();
aws_tls_connection_options tlsOptions;
AWS_ZERO_STRUCT(tlsOptions);
if (tlsConnectionOptions)
Aws::UniquePtr<Aws::Crt::Io::TlsConnectionOptions> pTlsConnectionOptions;
if (config.tlsConnectionOptions)
{
pTlsConnectionOptions = Aws::MakeUnique<Aws::Crt::Io::TlsConnectionOptions>(ALLOCATION_TAG, *config.tlsConnectionOptions);
if (!config.caPath.empty() || !config.caFile.empty())
{
AWS_LOGSTREAM_WARN(ALLOCATION_TAG, "caPath or caFile on client configuration are ignored in case of user-configured TlsConnectionOptions provided");
}
}

if (!pTlsConnectionOptions)
{
Aws::Crt::Io::TlsContextOptions crtTlsContextOptions = Aws::Crt::Io::TlsContextOptions::InitDefaultClient();
if (!config.caPath.empty() || !config.caFile.empty())
{
const char *caPath = config.caPath.empty() ? nullptr : config.caPath.c_str();
const char *caFile = config.caFile.empty() ? nullptr : config.caFile.c_str();
if(!crtTlsContextOptions.OverrideDefaultTrustStore(caPath, caFile)) {
AWS_LOGSTREAM_FATAL(ALLOCATION_TAG, "Failed to initialize S3 Crt client: failed to set caPath/caFile");
m_isInitialized = false;
return;
}
}
Aws::Crt::Io::TlsContext crtTlsContext(crtTlsContextOptions, Aws::Crt::Io::TlsMode::CLIENT);
pTlsConnectionOptions = Aws::MakeUnique<Aws::Crt::Io::TlsConnectionOptions>(ALLOCATION_TAG, crtTlsContext.NewConnectionOptions());
}

aws_tls_connection_options nonConstTlsOptions;
AWS_ZERO_STRUCT(nonConstTlsOptions);
if (pTlsConnectionOptions)
{
aws_tls_connection_options_copy(&tlsOptions, tlsConnectionOptions->GetUnderlyingHandle());
ResolveEndpointOutcome endpointOutcome = m_endpointProvider->ResolveEndpoint({});
if (!endpointOutcome.IsSuccess())
{
AWS_LOGSTREAM_ERROR(ALLOCATION_TAG, "Failed to resolve base URI: " << endpointOutcome.GetError().GetMessage());
AWS_LOGSTREAM_FATAL(ALLOCATION_TAG, "Failed to initialize S3 Crt client: failed to resolve base URI: " << endpointOutcome.GetError().GetMessage());
m_isInitialized = false;
return;
}
tlsOptions.server_name = aws_string_new_from_c_str(Aws::get_aws_allocator(), endpointOutcome.GetResult().GetURL().c_str());
s3CrtConfig.tls_connection_options = &tlsOptions;
Aws::Crt::ByteCursor serverName = Aws::Crt::ByteCursorFromCString(endpointOutcome.GetResult().GetURI().GetAuthority().c_str());
pTlsConnectionOptions->SetServerName(serverName);
aws_tls_connection_options_copy(&nonConstTlsOptions, pTlsConnectionOptions->GetUnderlyingHandle());
s3CrtConfig.tls_connection_options = &nonConstTlsOptions;
}
else
{
Expand All @@ -291,13 +322,14 @@ void S3CrtClient::init(const S3Crt::ClientConfiguration& config, const std::shar
s3CrtConfig.shutdown_callback_user_data = static_cast<void*>(&m_wrappedData);

m_s3CrtClient = aws_s3_client_new(Aws::get_aws_allocator(), &s3CrtConfig);
if (tlsConnectionOptions)
if (pTlsConnectionOptions)
{
aws_tls_connection_options_clean_up(&tlsOptions);
aws_tls_connection_options_clean_up(&nonConstTlsOptions);
}
if (!m_s3CrtClient)
{
AWS_LOGSTREAM_FATAL(ALLOCATION_TAG, "Failed to allocate aws_s3_client instance, abort.");
m_isInitialized = false;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1355,4 +1355,23 @@ namespace
ASSERT_FALSE(outcome.IsSuccess());
ASSERT_EQ(outcome.GetError().GetErrorType(), Aws::S3Crt::S3CrtErrors::NETWORK_CONNECTION);
}

TEST_F(BucketAndObjectOperationTest, MissingCertificate) {
Aws::S3Crt::ClientConfiguration s3ClientConfig;
s3ClientConfig.region = Aws::Region::US_EAST_1;
s3ClientConfig.caFile = "/some-non-existing-certificate/cert.crt";
s3ClientConfig.verifySSL = true;

S3CrtClient crtClient = S3CrtClient(Aws::Auth::AWSCredentials{"", ""},
s3ClientConfig,
Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never);

GetObjectRequest getObjectRequest;
getObjectRequest.SetBucket("aws-sdk-cpp-docs");
getObjectRequest.SetKey("cpp/api/LATEST/index.html");

auto result = crtClient.GetObject(getObjectRequest);
ASSERT_FALSE(result.IsSuccess());
ASSERT_EQ((Aws::Client::CoreErrors) result.GetError().GetErrorType(), Aws::Client::CoreErrors::NOT_INITIALIZED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,9 @@ namespace ${rootNamespace}
#end
std::shared_ptr<Utils::Threading::Executor> m_executor;
#if($serviceNamespace == "S3Crt")
struct aws_s3_client* m_s3CrtClient;
struct aws_signing_config_aws m_s3CrtSigningConfig;
struct CrtClientShutdownCallbackDataWrapper m_wrappedData;
struct aws_s3_client* m_s3CrtClient = {};
struct aws_signing_config_aws m_s3CrtSigningConfig = {};
struct CrtClientShutdownCallbackDataWrapper m_wrappedData = {};
std::shared_ptr<Aws::Utils::Threading::Semaphore> m_clientShutdownSem;
Aws::String m_userAgent;
std::shared_ptr<Aws::Auth::AWSCredentialsProvider> m_credProvider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,10 @@ ${className}::~${className}()
{
#if($serviceNamespace == "S3Crt")
aws_s3_client_release(m_s3CrtClient);
m_clientShutdownSem->WaitOne(); // Wait aws_s3_client shutdown
if(m_clientShutdownSem)
{
m_clientShutdownSem->WaitOne(); // Wait aws_s3_client shutdown
}
#end
ShutdownSdkClient(this, -1);
}
Expand Down Expand Up @@ -304,20 +307,48 @@ void ${className}::init(const ${clientConfigurationNamespace}::ClientConfigurati
static const size_t DEFAULT_PART_SIZE = 5 * 1024 * 1024; // 5MB
s3CrtConfig.part_size = config.partSize < DEFAULT_PART_SIZE ? DEFAULT_PART_SIZE : config.partSize;

Aws::Crt::Io::TlsConnectionOptions* tlsConnectionOptions = config.tlsConnectionOptions ? config.tlsConnectionOptions.get() : Aws::GetDefaultTlsConnectionOptions();
aws_tls_connection_options tlsOptions;
AWS_ZERO_STRUCT(tlsOptions);
if (tlsConnectionOptions)
Aws::UniquePtr<Aws::Crt::Io::TlsConnectionOptions> pTlsConnectionOptions;
if (config.tlsConnectionOptions)
{
pTlsConnectionOptions = Aws::MakeUnique<Aws::Crt::Io::TlsConnectionOptions>(ALLOCATION_TAG, *config.tlsConnectionOptions);
if (!config.caPath.empty() || !config.caFile.empty())
{
AWS_LOGSTREAM_WARN(ALLOCATION_TAG, "caPath or caFile on client configuration are ignored in case of user-configured TlsConnectionOptions provided");
}
}

if (!pTlsConnectionOptions)
{
Aws::Crt::Io::TlsContextOptions crtTlsContextOptions = Aws::Crt::Io::TlsContextOptions::InitDefaultClient();
if (!config.caPath.empty() || !config.caFile.empty())
{
const char *caPath = config.caPath.empty() ? nullptr : config.caPath.c_str();
const char *caFile = config.caFile.empty() ? nullptr : config.caFile.c_str();
if(!crtTlsContextOptions.OverrideDefaultTrustStore(caPath, caFile)) {
AWS_LOGSTREAM_FATAL(ALLOCATION_TAG, "Failed to initialize S3 Crt client: failed to set caPath/caFile");
m_isInitialized = false;
return;
}
}
Aws::Crt::Io::TlsContext crtTlsContext(crtTlsContextOptions, Aws::Crt::Io::TlsMode::CLIENT);
pTlsConnectionOptions = Aws::MakeUnique<Aws::Crt::Io::TlsConnectionOptions>(ALLOCATION_TAG, crtTlsContext.NewConnectionOptions());
}

aws_tls_connection_options nonConstTlsOptions;
AWS_ZERO_STRUCT(nonConstTlsOptions);
if (pTlsConnectionOptions)
{
aws_tls_connection_options_copy(&tlsOptions, tlsConnectionOptions->GetUnderlyingHandle());
ResolveEndpointOutcome endpointOutcome = m_endpointProvider->ResolveEndpoint({});
if (!endpointOutcome.IsSuccess())
{
AWS_LOGSTREAM_ERROR(ALLOCATION_TAG, "Failed to resolve base URI: " << endpointOutcome.GetError().GetMessage());
AWS_LOGSTREAM_FATAL(ALLOCATION_TAG, "Failed to initialize S3 Crt client: failed to resolve base URI: " << endpointOutcome.GetError().GetMessage());
m_isInitialized = false;
return;
}
tlsOptions.server_name = aws_string_new_from_c_str(Aws::get_aws_allocator(), endpointOutcome.GetResult().GetURL().c_str());
s3CrtConfig.tls_connection_options = &tlsOptions;
Aws::Crt::ByteCursor serverName = Aws::Crt::ByteCursorFromCString(endpointOutcome.GetResult().GetURI().GetAuthority().c_str());
pTlsConnectionOptions->SetServerName(serverName);
aws_tls_connection_options_copy(&nonConstTlsOptions, pTlsConnectionOptions->GetUnderlyingHandle());
s3CrtConfig.tls_connection_options = &nonConstTlsOptions;
}
else
{
Expand All @@ -334,13 +365,14 @@ void ${className}::init(const ${clientConfigurationNamespace}::ClientConfigurati
s3CrtConfig.shutdown_callback_user_data = static_cast<void*>(&m_wrappedData);

m_s3CrtClient = aws_s3_client_new(Aws::get_aws_allocator(), &s3CrtConfig);
if (tlsConnectionOptions)
if (pTlsConnectionOptions)
{
aws_tls_connection_options_clean_up(&tlsOptions);
aws_tls_connection_options_clean_up(&nonConstTlsOptions);
}
if (!m_s3CrtClient)
{
AWS_LOGSTREAM_FATAL(ALLOCATION_TAG, "Failed to allocate aws_s3_client instance, abort.");
m_isInitialized = false;
}
#end
}
Expand Down