void STSProfileCredentialsProvider::Reload()

in src/aws-cpp-sdk-identity-management/source/auth/STSProfileCredentialsProvider.cpp [165:310]


void STSProfileCredentialsProvider::Reload()
{
    // make a copy of the profiles map to be able to set credentials on the individual profiles when assuming role
    auto loadedProfiles = Aws::Config::GetCachedConfigProfiles();
    auto profileIt = loadedProfiles.find(m_profileName);

    if(profileIt == loadedProfiles.end())
    {
        AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << m_profileName <<" was not found in the shared configuration file.");
        m_credentials = {};
        return;
    }

    ProfileState profileState = CheckProfile(profileIt->second, true/*topLevelProfile*/);

    if (profileState == ProfileState::Static)
    {
        m_credentials = profileIt->second.GetCredentials();
        AWSCredentialsProvider::Reload();
        return;
    }

    if (profileState == ProfileState::Process)
    {
        const auto& creds = GetCredentialsFromProcess(profileIt->second.GetCredentialProcess());
        if (!creds.IsExpiredOrEmpty())
        {
            m_credentials = creds;
            AWSCredentialsProvider::Reload();
        }
        return;
    }

    if (profileState == ProfileState::Invalid)
    {
        AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << profileIt->second.GetName() << " is invalid. Check its configuration.");
        m_credentials = {};
        return;
    }

    if (profileState == ProfileState::SourceProfile)
    {
        // A top level profile with a 'SourceProfile' state (determined by CheckProfile rules) means that its static
        // credentials will be ignored. So, it's ok to clear them out here to simplify the logic in the chaining loop
        // below.
        profileIt->second.SetCredentials({});
    }

    AWS_LOGSTREAM_INFO(CLASS_TAG, "Profile " << profileIt->second.GetName()
            << " has a role ARN. Attempting to load its source credentials from profile "
            << profileIt->second.GetSourceProfile());

    Aws::Vector<Config::AWSProfileConfigLoader::ProfilesContainer::iterator> sourceProfiles;
    Aws::Set<Aws::String> visitedProfiles;

    auto currentProfile = profileIt;
    sourceProfiles.push_back(currentProfile);

    // build the chain (DAG)
    while(!currentProfile->second.GetSourceProfile().empty())
    {
        ProfileState currentProfileState = CheckProfile(currentProfile->second, false /*topLevelProfile*/);
        auto currentProfileName = currentProfile->second.GetName();
        if (currentProfileState == ProfileState::Invalid)
        {
            AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << profileIt->second.GetName() << " is invalid. Check its configuration.");
            m_credentials = {};
            return;
        }

        // terminate the chain as soon as we hit a profile with either static credentials or credential process
        if (currentProfileState == ProfileState::Static || currentProfileState == ProfileState::Process)
        {
            break;
        }

        if (currentProfileState == ProfileState::SelfReferencing)
        {
            sourceProfiles.push_back(currentProfile);
            break;
        }

        // check if we have a circular reference in the graph.
        if (visitedProfiles.find(currentProfileName) != visitedProfiles.end())
        {
            // TODO: print the whole DAG for better debugging
            AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << currentProfileName << " has a circular reference. Aborting.");
            m_credentials = {};
            return;
        }

        visitedProfiles.emplace(currentProfileName);

        const auto it = loadedProfiles.find(currentProfile->second.GetSourceProfile());
        if(it == loadedProfiles.end())
        {
            // TODO: print the whole DAG for better debugging
            AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << currentProfileName << " has an invalid source profile " << currentProfile->second.GetSourceProfile());
            m_credentials = {};
            return;
        }
        currentProfile = it;
        sourceProfiles.push_back(currentProfile);
    }

    // The last profile added to the stack is not checked. Check it now.
    if (!sourceProfiles.empty())
    {
        if (CheckProfile(sourceProfiles.back()->second, false /*topLevelProfile*/) == ProfileState::Invalid)
        {
            AWS_LOGSTREAM_ERROR(CLASS_TAG, "Profile " << sourceProfiles.back()->second.GetName() << " is invalid. Check its configuration.");
            m_credentials = {};
            return;
        }
    }

    while (sourceProfiles.size() > 1)
    {
        const auto profile = sourceProfiles.back()->second;
        sourceProfiles.pop_back();
        AWSCredentials stsCreds;
        if (profile.GetCredentialProcess().empty())
        {
            assert(!profile.GetCredentials().IsEmpty());
            stsCreds = profile.GetCredentials();
        }
        else
        {
            stsCreds = GetCredentialsFromProcess(profile.GetCredentialProcess());
        }

        // get the role arn from the profile at the top of the stack (which hasn't been popped out yet)
        const auto arn = sourceProfiles.back()->second.GetRoleArn();
        const auto& assumedCreds = GetCredentialsFromSTS(stsCreds, arn);
        sourceProfiles.back()->second.SetCredentials(assumedCreds);
    }

    if (!sourceProfiles.empty())
    {
        assert(profileIt == sourceProfiles.back());
        assert(!profileIt->second.GetCredentials().IsEmpty());
    }

    m_credentials = profileIt->second.GetCredentials();
    AWSCredentialsProvider::Reload();
}