void RsIamHelper::SetIamSettings()

in src/odbc/rsodbc/iam/RsIamHelper.cpp [296:504]


void RsIamHelper::SetIamSettings(
    bool isIAMAuth,
    RS_IAM_CONN_PROPS_INFO *pIamProps,
    RS_PROXY_CONN_PROPS_INFO *pHttpsProps,
    RsSettings& settings)
{
    RS_LOG_DEBUG("IAMHLP", "RsIamHelper::SetIamSettings");
    rs_string temp;

    settings.m_iamAuth = isIAMAuth;
    SetCommonFederatedAuthSettings(pIamProps, settings);

    if(settings.m_iamAuth == true) {
        settings.m_username = pIamProps->szUser;
        settings.m_password = pIamProps->szPassword;

        std::vector<rs_string> hostnameTokens = IAMUtils::TokenizeSetting(settings.m_host, ".");
        rs_string workGroup;
        rs_string acctId;
        rs_string requiredClusterId;
        if (hostnameTokens.size() >= 6 && (hostnameTokens[3].find("serverless") != rs_string::npos))
            {
                /*Serverless_cluster's host examples:
                e.g., default.518627716765.us-east-1.redshift-serverless.amazonaws.com
                */ 
                workGroup = hostnameTokens[0];
                acctId = hostnameTokens[1];
                settings.m_isServerless = true;
                if (settings.m_awsRegion.empty()) {
                    settings.m_awsRegion = hostnameTokens[2];
                }

            }
            else if (hostnameTokens.size() >= 6)
            {
                /*provisioned_cluster_host examples: 
                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
                */
                requiredClusterId = hostnameTokens[0];
                if (settings.m_awsRegion.empty()) {
                    settings.m_awsRegion = hostnameTokens[2];
                }
            }

        settings.m_isServerless = pIamProps->isServerless;
        settings.m_workGroup = pIamProps->szWorkGroup;
        std::smatch mProvisioned;
        std::smatch mServerless;
        std::smatch mNlb;

        bool provisionedMatches = std::regex_match(settings.m_host, mProvisioned, hostPattern);
        bool serverlessMatches = std::regex_match(settings.m_host, mServerless, serverlessWorkgroupHostPattern);
        bool nlbMatches = std::regex_match(settings.m_host, mNlb, nlbHostPattern);
        rs_string clusterId;

        // replace host value if user has provided a managed VPC URL.
        settings.m_managedVpcUrl = pIamProps->szManagedVpcUrl;
        if (!settings.m_managedVpcUrl.empty()) {
            if (!workGroup.empty()) {
                settings.m_workGroup = workGroup;
            }
            settings.m_host = settings.m_managedVpcUrl;
        }

        if(provisionedMatches){
            RS_LOG_DEBUG("IAMHLP", "Code flow for regular provisioned cluster");
            if (strlen(pIamProps->szClusterId) > 0) {
                clusterId = pIamProps->szClusterId;
            } else {
                clusterId = requiredClusterId;
            }
        }
        else if(serverlessMatches){
            // serverless vanilla
            // do nothing, regular serverless logic flow
            RS_LOG_DEBUG("IAMHLP", "Code flow for regular serverless cluster");
            settings.m_isServerless=true;
        }
        else if (nlbMatches && !settings.m_isServerless) {
            // Workflow for connection with NLB for provisioned clusters
            RS_LOG_DEBUG("IAMHLP", "Code flow for nlb provisioned cluster");
            if (strlen(pIamProps->szClusterId) > 0) {
                clusterId = pIamProps->szClusterId;
            }
        }
        else if(settings.m_isServerless){
            // hostname doesn't match serverless regex but serverless set to true explicitly by user
            // when ready for implementation, remove setting of the isServerless property automatically in parseUrl(),
            // set it here instead
            if(!(settings.m_workGroup.empty())){
                // workgroup specified by user - serverless nlb call
                // check for serverlessAcctId to enter serverless NLB logic flow, for when we implement this for serverless after server side is ready
                // currently do nothing as regular code flow is sufficient
                RS_LOG_DEBUG("IAMHLP", "Code flow for nlb serverless cluster");
            }
            else if (strlen(pIamProps->szClusterId) > 0) {
                // Workflow for using GetClusterCredentials API with serverless cluster
                RS_LOG_DEBUG("IAMHLP", "Code flow for using GetClusterCredentials with serverless cluster");
                clusterId = pIamProps->szClusterId;
                settings.m_isServerless = false;
            }
            else{
                // attempt serverless cname call
                // currently sets isCname to true which will be asserted on later
                RS_LOG_DEBUG("IAMHLP", "Code flow for cname serverless cluster");
                settings.m_isCname = true;
            }
        }
        else {
            // Workflow for using CNAME with provisioned cluster
            RS_LOG_DEBUG("IAMHLP", "Code flow for cname provisioned cluster");
            clusterId = pIamProps->szClusterId;
            // attempt provisioned cname call
            // cluster id will be fetched upon describing custom domain name
            settings.m_isCname = true;
        }
        
        settings.m_accessKeyID = pIamProps->szAccessKeyID;
        settings.m_secretAccessKey = pIamProps->szSecretAccessKey;
        settings.m_sessionToken = pIamProps->szSessionToken;
        settings.m_accessDuration = pIamProps->lIAMDuration;
        if (settings.m_accessDuration > 3600)
            settings.m_accessDuration = 3600;
        else
        if (settings.m_accessDuration < 900)
            settings.m_accessDuration = 900;

        settings.m_clusterIdentifer = clusterId;
        RS_LOG_DEBUG("IAMHLP", "Cluster Identifier:%s",
                     settings.m_clusterIdentifer.c_str());
        //settings.m_clusterIdentifer = pIamProps->szClusterId;


        if(!settings.m_isServerless && !settings.m_isCname && (settings.m_clusterIdentifer.empty())){
            RS_LOG_DEBUG("IAMHLP", "Invalid connection property setting. cluster_identifier must be provided when IAM is enabled");
        }

        settings.m_dbUser = pIamProps->szDbUser;
        temp = pIamProps->szDbGroups;
        settings.m_dbGroups = IAMUtils::convertStringToWstring(temp);
        settings.m_awsProfile = pIamProps->szProfile;
        temp = pIamProps->szStsEndpointUrl;
        settings.m_stsEndpointUrl = IAMUtils::convertStringToWstring(temp);

        settings.m_oktaAppName = pIamProps->szAppName;
        settings.m_partnerSpid = pIamProps->szPartnerSpid;
        settings.m_loginToRp = pIamProps->szLoginToRp;
        temp = pIamProps->szIdpHost;
        settings.m_idpHost = IAMUtils::convertStringToWstring(temp);
        settings.m_idpPort = pIamProps->iIdpPort;

        settings.m_idpTenant = pIamProps->szIdpTenant;
        settings.m_clientSecret = pIamProps->szClientSecret;
        settings.m_clientId = pIamProps->szClientId;
        settings.m_scope = pIamProps->szScope;
        settings.m_idp_response_timeout = pIamProps->lIdpResponseTimeout;
        settings.m_login_url = pIamProps->szLoginUrl;
        settings.m_role_arn = pIamProps->szRoleArn;
        //Added the autoCreate keyword from the user input connection string
        settings.m_userAutoCreate = pIamProps->isAutoCreate;

        settings.m_duration = pIamProps->lDuration;
        settings.m_role_session_name = pIamProps->szRoleSessionName;
        settings.m_dbGroupsFilter = pIamProps->szDbGroupsFilter;
        settings.m_listen_port = pIamProps->lListenPort;
        temp = pIamProps->szAppId;
        settings.m_appId = IAMUtils::convertStringToWstring(temp);
        temp = pIamProps->szPreferredRole;
        settings.m_preferredRole = IAMUtils::convertStringToWstring(temp);

        settings.m_useInstanceProfile = pIamProps->isInstanceProfile;
        settings.m_authProfile = pIamProps->szAuthProfile;
        settings.m_disableCache = pIamProps->isDisableCache;
        settings.m_stsConnectionTimeout = pIamProps->iStsConnectionTimeout;

        if(pHttpsProps) {
            settings.m_httpsProxyHost = pHttpsProps->szHttpsHost;
            settings.m_httpsProxyPort = pHttpsProps->iHttpsPort;
            settings.m_httpsProxyUsername = pHttpsProps->szHttpsUser;
            settings.m_httpsProxyPassword = pHttpsProps->szHttpsPassword;
            settings.m_useProxyForIdpAuth = pHttpsProps->isUseProxyForIdp;
        }

        settings.m_groupFederation = pIamProps->isGroupFederation;
    } else { 
        // Only IdC based programmatic and browser based plugins follow this flow.
        settings.m_managedVpcUrl = pIamProps->szManagedVpcUrl;
        if (!settings.m_managedVpcUrl.empty()) {
            settings.m_host = settings.m_managedVpcUrl;
        }
        settings.m_clusterIdentifer = pIamProps->szClusterId;
        settings.m_idpAuthToken = pIamProps->szBasicAuthToken;
        settings.m_idpAuthTokenType = pIamProps->szTokenType;
        settings.m_issuerUrl = pIamProps->szIssuerUrl;
        settings.m_idcRegion = pIamProps->szIdcRegion;
        settings.m_listen_port = pIamProps->lListenPort;
        settings.m_idp_response_timeout = pIamProps->lIdpResponseTimeout;
        settings.m_idcClientDisplayName = pIamProps->szIdcClientDisplayName;

        if (pIamProps->szPluginName[0] != '\0' && (_stricmp(pIamProps->szPluginName, PLUGIN_IDP_TOKEN_AUTH) == 0)) {
            // Explicitly disable caching for idc programmatic plugin. This is set false by default in RsSettings.h
            settings.m_disableCache = true;
        } 
    }

    settings.m_caPath = pIamProps->szCaPath;
    settings.m_caFile = pIamProps->szCaFile;
}