const std::string ZTSClient::getRoleToken()

in lib/auth/athenz/ZTSClient.cc [296:409]


const std::string ZTSClient::getRoleToken() {
    RoleToken roleToken;

    // locked block
    {
        std::lock_guard<std::mutex> lock(cacheMtx_);
        roleToken = roleTokenCache_;
    }

    if (!roleToken.token.empty() && roleToken.expiryTime > (long long)time(NULL) + FETCH_EPSILON) {
        LOG_DEBUG("Got cached role token " << roleToken.token);
        return roleToken.token;
    }

    std::string completeUrl = ztsUrl_ + "/zts/v1/domain/" + providerDomain_ + "/token";
    completeUrl += "?minExpiryTime=" + std::to_string(ROLE_TOKEN_EXPIRATION_MIN_TIME_SEC);
    completeUrl += "&maxExpiryTime=" + std::to_string(ROLE_TOKEN_EXPIRATION_MAX_TIME_SEC);

    CURL *handle;
    CURLcode res;
    std::string responseData;

    handle = curl_easy_init();

    // set URL
    curl_easy_setopt(handle, CURLOPT_URL, completeUrl.c_str());

    // Write callback
    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curlWriteCallback);
    curl_easy_setopt(handle, CURLOPT_WRITEDATA, &responseData);

    // New connection is made for each call
    curl_easy_setopt(handle, CURLOPT_FRESH_CONNECT, 1L);
    curl_easy_setopt(handle, CURLOPT_FORBID_REUSE, 1L);

    // Skipping signal handling - results in timeouts not honored during the DNS lookup
    curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L);

    // Timer
    curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, REQUEST_TIMEOUT);

    // Redirects
    curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(handle, CURLOPT_MAXREDIRS, MAX_HTTP_REDIRECTS);

    // Fail if HTTP return code >= 400
    curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1L);

    if (!caCert_.scheme.empty()) {
        if (caCert_.scheme == "file") {
            curl_easy_setopt(handle, CURLOPT_CAINFO, caCert_.path.c_str());
        } else {
            LOG_ERROR("URI scheme not supported in caCert: " << caCert_.scheme);
        }
    }

    struct curl_slist *list = NULL;
    if (enableX509CertChain_) {
        if (x509CertChain_.scheme == "file") {
            curl_easy_setopt(handle, CURLOPT_SSLCERT, x509CertChain_.path.c_str());
        } else {
            LOG_ERROR("URI scheme not supported in x509CertChain: " << x509CertChain_.scheme);
        }
        if (privateKeyUri_.scheme == "file") {
            curl_easy_setopt(handle, CURLOPT_SSLKEY, privateKeyUri_.path.c_str());
        } else {
            LOG_ERROR("URI scheme not supported in privateKey: " << privateKeyUri_.scheme);
        }
    } else {
        std::string httpHeader = principalHeader_ + ": " + getPrincipalToken();
        list = curl_slist_append(list, httpHeader.c_str());
        curl_easy_setopt(handle, CURLOPT_HTTPHEADER, list);
    }

    // Make get call to server
    res = curl_easy_perform(handle);

    // Free header list
    curl_slist_free_all(list);

    switch (res) {
        case CURLE_OK:
            long response_code;
            curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &response_code);
            LOG_DEBUG("Response received for url " << completeUrl << " code " << response_code);
            if (response_code == 200) {
                ptree::ptree root;
                std::stringstream stream;
                stream << responseData;
                try {
                    ptree::read_json(stream, root);
                } catch (ptree::json_parser_error &e) {
                    LOG_ERROR("Failed to parse json of ZTS response: " << e.what()
                                                                       << "\nInput Json = " << responseData);
                    break;
                }

                roleToken.token = root.get<std::string>("token");
                roleToken.expiryTime = root.get<uint32_t>("expiryTime");
                std::lock_guard<std::mutex> lock(cacheMtx_);
                roleTokenCache_ = roleToken;
                LOG_DEBUG("Got role token " << roleToken.token)
            } else {
                LOG_ERROR("Response failed for url " << completeUrl << ". response Code " << response_code)
            }
            break;
        default:
            LOG_ERROR("Response failed for url " << completeUrl << ". Error Code " << res);
            break;
    }
    curl_easy_cleanup(handle);

    return roleToken.token;
}