in src/odbc/rsodbc/iam/RsIamClient.cpp [487:635]
Model::GetClusterCredentialsWithIAMOutcome RsIamClient::SendClusterCredentialsWithIAMRequest(
const std::shared_ptr<AWSCredentialsProvider>& in_credentialsProvider)
{
RS_LOG_DEBUG("IAMCLNT", "RsIamClient::SendClusterCredentialsWithIAMRequest");
ClientConfiguration config;
/* infer awsRegion and ClusterId from host name if not provided in the connection string
e.g., redshiftj-iam-test.c2mf5zd3u3sv.us-west-2.redshift.amazonaws.com,
should be tokenized to at least 6 elements
*/
std::vector<rs_string> hostnameTokens = IAMUtils::TokenizeSetting(m_settings.m_host, ".");
rs_string inferredClusterId, inferredAwsRegion;
if (hostnameTokens.size() >= 6)
{
/* e.g., redshiftj-iam-test.c2mf5zd3u3sv.us-west-2.redshift.amazonaws.com
e.g., redshiftj-iam-test.c2mf5zd3u3sv.us-west-2.redshift.amazonaws.com.cn
*/
inferredClusterId = hostnameTokens[0];
inferredAwsRegion = hostnameTokens[2];
}
if(m_settings.m_isCname && inferredAwsRegion.empty()){
config.region = IAMUtils().GetAwsRegionFromCname(m_settings.m_host);
}
else
{
config.region = m_settings.m_awsRegion.empty() ? inferredAwsRegion : m_settings.m_awsRegion;
config.endpointOverride = IAMUtils::convertToUTF8(m_settings.m_endpointUrl);
}
if (m_settings.m_stsConnectionTimeout > 0)
{
config.httpRequestTimeoutMs = m_settings.m_stsConnectionTimeout * 1000;
config.connectTimeoutMs = m_settings.m_stsConnectionTimeout * 1000;
config.requestTimeoutMs = m_settings.m_stsConnectionTimeout * 1000;
}
RS_LOG_DEBUG("IAMCLNT",
"RsIamClient::SendClusterCredentialsWithIAMRequest",
"httpRequestTimeoutMs: %ld, connectTimeoutMs: %ld, requestTimeoutMs: %ld",
config.httpRequestTimeoutMs,
config.connectTimeoutMs,
config.requestTimeoutMs);
#ifndef _WIN32
// Added CA file to the config for verifying STS server certificate
if (!m_settings.m_caFile.empty())
{
config.caFile = m_settings.m_caFile;
}
else
{
config.caFile = IAMUtils::convertToUTF8(IAMUtils::GetDefaultCaFile()); // .GetAsPlatformString()
}
#endif
if (!m_settings.m_httpsProxyHost.empty())
{
config.proxyHost = m_settings.m_httpsProxyHost;
config.proxyPort = m_settings.m_httpsProxyPort;
config.proxyUserName = m_settings.m_httpsProxyUsername;
config.proxyPassword = m_settings.m_httpsProxyPassword;
}
RedshiftClient client(in_credentialsProvider, config);
// Compose the ClusterCredentialRequest object
Model::GetClusterCredentialsWithIAMRequest request;
if(m_settings.m_isCname) {
//suppose to call the request.SetCustomDomainName() API but its not available.
//request.SetCustomDomainName();
request.SetCustomDomainName(m_settings.m_host.c_str());
}
else {
request.SetClusterIdentifier(m_settings.m_clusterIdentifer.empty() ?
inferredClusterId.c_str() : m_settings.m_clusterIdentifer.c_str());
}
request.SetDbName(m_settings.m_database);
// m_accessDuration setting corresponds to IAMDuration option
request.SetDurationSeconds(m_settings.m_accessDuration);
/*
If we know this is a custom cluster name, we need to fetch the clusterId associated with it
*/
Model::GetClusterCredentialsWithIAMOutcome outcome;
rs_string tempClusterIdentifierIAM;
try {
if (m_settings.m_isCname) {
Model::DescribeCustomDomainAssociationsRequest describeRequest;
describeRequest.SetCustomDomainName(m_settings.m_host);
const Model::DescribeCustomDomainAssociationsOutcome& describeResponseOutcome = client.DescribeCustomDomainAssociations(describeRequest);
if (describeResponseOutcome.IsSuccess()) {
const Model::DescribeCustomDomainAssociationsResult& describeResponse = describeResponseOutcome.GetResult();
const auto& associations = describeResponse.GetAssociations();
if (!associations.empty()) {
const auto& certificateAssociations = associations[0].GetCertificateAssociations();
if (!certificateAssociations.empty()) {
tempClusterIdentifierIAM = certificateAssociations[0].GetClusterIdentifier();
}
else{
RS_LOG_ERROR("IAMCLNT", "RsIamClient::SendClusterCredentialWithIAMRequest:CNAME Feature: No certificateAssociations list Found!");
IAMUtils::ThrowConnectionExceptionWithInfo("CNAME FEATURE::No certificateAssociations list Found!");
}
}
else{
RS_LOG_ERROR("IAMCLNT", "RsIamClient::SendClusterCredentialWithIAMRequest:CNAME Feature: No Associations list Found!");
IAMUtils::ThrowConnectionExceptionWithInfo("CNAME FEATURE::No Associations list Found!");
}
}
else {
RS_LOG_DEBUG("IAMCLNT", "Failed to describe custom domain associations. Assuming cluster incorrectly classified as cname, setting cluster identifier directly.");
request.SetCustomDomainName(""); // Clear the custom domain name
request.SetClusterIdentifier(m_settings.m_clusterIdentifer.empty() ? inferredClusterId.c_str() : m_settings.m_clusterIdentifer.c_str()); // Set the cluster identifier instead
}
}
/* if host is empty describe cluster using cluster id */
if (m_settings.m_host.empty() || m_settings.m_port==0) {
if (m_settings.m_clusterIdentifer.empty() && tempClusterIdentifierIAM.empty()) {
RS_LOG_ERROR("IAMCLNT", "RsIamClient::SendClusterCredentialsithIAMRequest: Can not describe cluster: missing clusterId or region.");
IAMUtils::ThrowConnectionExceptionWithInfo("Can not describe cluster: missing clusterId or region.");
}
Model::Endpoint endpoint = DescribeCluster(client, tempClusterIdentifierIAM.empty() ? m_settings.m_clusterIdentifer : tempClusterIdentifierIAM);
m_credentials.SetHost(endpoint.GetAddress());
m_credentials.SetPort(static_cast<short>(endpoint.GetPort()));
}
RS_LOG_DEBUG("IAMCLNT", "RsIamClient::SendClusterCredentialswithIAMRequest: Before GetClusterCredentialswithIAM()");
// Send the request using RedshiftClient
outcome = client.GetClusterCredentialsWithIAM(request);
RS_LOG_DEBUG("IAMCLNT", "RsIamClient::SendClusterCredentialswithIAMRequest: After GetClusterCredentialswithIAM()");
}
catch (const Aws::Client::AWSError<Aws::Redshift::RedshiftErrors>& ex) {
RS_LOG_DEBUG("IAMCLNT", "Failed to call GetClusterCredentialsWithIAM. Exception:%s", ex.GetMessage().c_str());
throw ex;
}
return outcome;
}