首页 > 解决方案 > 附加调试器给我凭据,删除它并且凭据为空

问题描述

我在 Qt 应用程序上遇到了 AWS sdk 的问题。
单击 QML 按钮后,我从 Cognito 获取 STS 令牌。
该功能运行良好,并且正在向我打印令牌...只要附加了调试器[F5]。如果我在没有调试器的情况下启动项目(绿色箭头上没有错误),则返回的对象为空。

如果没有附加调试器,我在 aws 日志中有以下内容,否则我没有:

[INFO] 2020-09-18 12:33:02.569 CognitoCachingCredentialsProvider [140678610167936] 父身份来自与匿名身份不同的 cognito。现在换掉。
[INFO] 2020-09-18 12:33:02.569 CognitoCachingCredentialsProvider [140678610167936] 凭证将在 0 时到期

周围的其他日志看起来都一样,我什至在这两种情况下都将 STS 令牌显示在这上面几行:

[调试] 2020-09-18 12:33:02.569 CURL [140678610167936] (DataIn) {"Credentials":{"AccessKeyId":"###","Expiration":1.600435982E9,"SecretKey":"## #","SessionToken":"##########"},"IdentityId":"<MY_IDENTITY_ID>"}

我什至编辑了 SDK 并添加了导致此结果的以下日志(附加了调试器,第一行也<MY_IDENTITY_ID>显示出来了)。

AWS_LOGSTREAM_INFO("TOTO", "parentIdentityId" << parentIdentityId);
AWS_LOGSTREAM_INFO("TOTO", "m_identityRepository->GetIdentityId() " << m_identityRepository->GetIdentityId()) ;

[信息] 2020-09-18 12:33:02.569 TOTO [140678610167936] parentIdentityId
[信息] 2020-09-18 12:33:02.569 TOTO [140678610167936] m_identityRepository->GetIdentityId() <MY_IDENTITY_ID>

在此处添加https://github.com/aws/aws-sdk-cpp/blob/6d6dcdbfa377393306bf79585f61baea524ac124/aws-cpp-sdk-identity-management/source/auth/CognitoCachingCredentialsProvider.cpp#L52 没有评论第 56 行不能解决我的问题问题。

附件是我的最小项目,如果您愿意,可以重现该行为(您需要有一个 AWS 设置和一个 openID 提供程序)。
我尝试了纯 C++,即使没有调试器,我也能得到一切。
实例化时出现问题QtCoreApplication
在基本应用程序上,我尝试设置 a QTimer::singleShot(100, /*...*/),但仍然遇到问题。

您可以从这里https://github.com/aws/aws-sdk-cpp安装 aws SDK ,如果您不想安装整个 SDK,该项目只需要 sdk 的一小部分,因此添加-DBUILD_ONLY="identity-management"到 cmake只构建所需的部分。

Qt 5.12.5
aws-sdk-cpp on tag: 1.8.42 (与以前的补丁版本有同样的问题,最近的变化很频繁)

问题

附加调试器有什么魔力可以让应用程序实例化QCoreApplication从 aws sdk 获取令牌?

我在这里再说一遍:我没有 DEBUG 和 RELEASE 版本,我只是在 qtcreator 中使用带有错误的箭头 vs 箭头。据我所知,环境是一样的,只是 qtcreator 附加或不附加调试器。
确实在发行版中我遇到了同样的问题(附加调试器时显示 STS,未附加时显示为空)。

最小的工作示例

main.cpp (注释代码应该与 相同credentials = cognitoAuth.GetAWSCredentials();,所以我有相同的行为。)

#include <QCoreApplication>
#include <QDebug>
#include <QFile>

#include <aws/cognito-identity/model/GetCredentialsForIdentityRequest.h>
#include <aws/cognito-identity/model/GetIdRequest.h>
#include <aws/core/Aws.h>
#include <aws/identity-management/auth/CognitoCachingCredentialsProvider.h>
#include <aws/identity-management/auth/PersistentCognitoIdentityProvider.h>

Aws::String m_region = Aws::Region::<PICK_YOUR_REGION>;
Aws::String m_providerUrl = "<PROVIDER_URL>";
Aws::String m_accountId = "<ACCOUNT_ID>";
Aws::String m_identityPoolId = "<IDENTITY_POOL_ID>";

Aws::Auth::AWSCredentials getSTS(const std::string idToken) {
  const char *persistentFile = "/tmp/aws.identities";
  QFile::remove(persistentFile);

  Aws::Auth::AWSCredentials credentials;
  //    Aws::CognitoIdentity::Model::Credentials credentials;

  std::shared_ptr<Aws::CognitoIdentity::CognitoIdentityClient> cognitoClient;
  Aws::SDKOptions options;
  options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace;

  Aws::InitAPI(options);
  {
    Aws::Client::ClientConfiguration config;
    config.region = m_region;
    cognitoClient =
        std::make_shared<Aws::CognitoIdentity::CognitoIdentityClient>(config);
    std::shared_ptr<Aws::Auth::PersistentCognitoIdentityProvider_JsonFileImpl>
        identityProvider = std::make_shared<
            Aws::Auth::PersistentCognitoIdentityProvider_JsonFileImpl>(
            m_identityPoolId, m_accountId, persistentFile);
    Aws::Map<Aws::String, Aws::Auth::LoginAccessTokens> logins;
    Aws::Auth::LoginAccessTokens loginAccessTokens;
    loginAccessTokens.accessToken = idToken;
    logins[m_providerUrl] = loginAccessTokens;
    identityProvider->PersistLogins(logins);

    // QThread::sleep(5);

    Aws::Auth::CognitoCachingAuthenticatedCredentialsProvider cognitoAuth{
        identityProvider, cognitoClient};
    ///////////////////////////////////////////////////////////////////////////
    // Aws::CognitoIdentity::Model::GetIdRequest idRequest;
    // idRequest.SetIdentityPoolId(m_identityPoolId.c_str());
    // idRequest.AddLogins(m_providerUrl, idToken.c_str());
    ////idRequest.SetIdentityPoolId((region + ":" + identityPoolId).c_str());
    //
    // auto idResult = cognitoClient->GetId(idRequest);
    // if(!idResult.IsSuccess())
    //{
    //    qCWarning(mqttAwsWebsocket) << "(GetId): " <<
    //    idResult.GetError().GetExceptionName().c_str() << ":"
    //                                <<
    //                                idResult.GetError().GetMessage().c_str();
    //    // throw
    //}
    //
    // QThread::sleep(5);
    //
    // Aws::CognitoIdentity::Model::GetCredentialsForIdentityRequest
    // credForIdRequest;
    // credForIdRequest.SetIdentityId(idResult.GetResult().GetIdentityId());
    // credForIdRequest.AddLogins(m_providerUrl, idToken.c_str());
    //
    // auto credForIdResult =
    // cognitoClient->GetCredentialsForIdentity(credForIdRequest);
    // if(!idResult.IsSuccess())
    //{
    //    qCWarning(mqttAwsWebsocket) << "(GetCredentialsForIdentity): "
    //                                <<
    //                                credForIdResult.GetError().GetExceptionName().c_str()
    //                                << ":"
    //                                <<
    //                                credForIdResult.GetError().GetMessage().c_str();
    //    // throw
    //}
    //
    // qDebug() << "COGNITO STS TOKEN RESULTS";
    // qDebug() << "cognitoClient->GetId: " << idResult.IsSuccess();
    // qDebug() << "cognitoClient->GetCredentialsForIdentity: " <<
    // credForIdResult.IsSuccess(); credentials =
    // credForIdResult.GetResult().GetCredentials();
    ///////////////////////////////////////////////////////////////////////////
    // QThread::sleep(5);

    credentials = cognitoAuth.GetAWSCredentials();

    qDebug() << credentials.IsEmpty() << tries;
    qDebug() << credentials.GetAWSAccessKeyId().c_str();
    qDebug() << credentials.GetAWSSecretKey().c_str();
    qDebug() << credentials.GetSessionToken().c_str();
    qDebug() << credentials.IsExpired()
             << credentials.GetExpiration()
                    .ToLocalTimeString(Aws::Utils::DateFormat::RFC822)
                    .c_str();
  }
  Aws::ShutdownAPI(options);

  return credentials;
}

int main(int argc, char **argv) {
  // Comment just this line and the problem is fixed.
  QCoreApplication app(argc, argv);

  getSTS("<PAST_OPEN_ID_TOKEN_GOTTEN_FROM_REAL_APP>");
  return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(aws-sts LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt5 COMPONENTS Core)

set(BUILD_SHARED_LIBS ON)
find_package(AWSSDK REQUIRED COMPONENTS identity-management)

add_executable(aws-sts main.cpp)

target_link_libraries(aws-sts PRIVATE
    Qt5::Core
    ${AWSSDK_LINK_LIBRARIES}
    )

更新

我简化了最小的工作示例,因为实际上只需添加(或注释 ot)QCoreApplication app(argc, argv);就足以重现该行为。我的意思只是对象创建,不需要它是 aQGuiApplication或使用app.exec().

标签: c++amazon-web-servicesqt

解决方案


事实证明,aws sdk 使用的是 cJSON,它在解析数字时可能会或可能不会获得本地环境来解码小数点。但是在这两种情况下,它都会调用double strtod(const char *nptr, char **endptr);将字符串转换为双精度,在我们可以阅读的手册页中(强调我的)

十进制数由可能包含基数字符(小数点,取决于语言环境,通常为 '.')的十进制数字的非空序列组成,可选地后跟十进制指数。[...]

显然 cJSON 需要这个编译变量才能在 Android上编译。

AWS 在此处复制了 lib,但没有复制编译变量ENABLE_LOCALES,如上面链接的问题中所述,默认情况下应启用该变量。

我在 Ubuntu 18.04 上,环境为英语,但日期/数字为法语(小数点','在法国)。

我在AWS SDK repo上创建了一个问题来设置编译变量ENABLE_LOCALES,并在cJSON上创建了一个问题来讨论并避免像这样的进一步错误。

一个潜在的解决方法也可能是强制应用程序使用英语语言环境,但这并不总是可行的。


推荐阅读