【问题标题】:Using Windows Authentication with cpprestsdk?将 Windows 身份验证与 cpprestsdk 一起使用?
【发布时间】:2020-03-12 06:40:02
【问题描述】:

现在使用 WinHTTP,并希望切换到 cpprestsdk。我正在查看文档,但没有看到任何有关 NTLM/Negotiate/Kerberos 支持的信息。我错过了什么吗?我很难相信 MS 不会支持它,但我没有看到任何关于如何使用它的示例代码。

我们需要 NTLM/Negotiate/Kerberos 支持的原因是我们通过 RemoteApp 运行我们的客户端,并且希望我们的用户在启动应用程序时只需使用他们的域凭据登录一次,并且不会提示用户输入密码第二次。

【问题讨论】:

  • 我希望我可以再增加 10 倍。祝你好运。
  • @WhozCraig - 想知道我是否应该放弃 cpprestsdk 并转向 libcurl,它似乎拥有更大的用户社区。想法?
  • @bpeikes 艰难的电话。我知道将 REST 调用与 libcurl 放在一起比 cpprestsdk 更像是一个皮塔(我们有不同的产品并同时使用两者),但如果它根据需要提供 NTLM-SSO,它可能是一个可行的替代方案。只需确保将其包装在 raii 框架中即可。在 C++ 中使用 libcurl(或任何其他基于句柄上下文的库)很容易意外泄漏内容。我在你的船上,顺便说一句。我喜欢 MS 对卡萨布兰卡所做的一切。我只是希望这能走得更远一点(我相信你现在也这样做了)。

标签: c++ casablanca cpprest-sdk


【解决方案1】:

Windows 身份验证似乎很容易内置到 Casablanca(在 Windows 机器上使用时)。看看 src/http/client/http_client_winhttp.cpp。在那里你会找到一个函数“ChooseAuthScheme”。据我了解,这将选择服务器提供的“最安全”的身份验证方案。如果服务器 e. G。声称同时支持“BASIC”和“NEGOTIATE”,它会更喜欢并选择后者作为更安全的方案。因此,使用 Widows 身份验证应该非常易于使用,只是不要设置任何凭据(用户名/密码)并尝试连接到支持 Windows 身份验证的服务器,并在 http“Authenticate”标头中宣布这一点(否则卡萨布兰卡将当然不要尝试使用 Windows 身份验证)。

但是 我也在尝试在卡萨布兰卡使用 Windows 身份验证,我目前面临两个问题:

  • 在我的场景中,Windows 身份验证的工作方式如上所述。令人困惑的是,有时它不会。就我而言,我可以在用户 Foo 登录的情况下从机器 A 连接到服务器,而我 无法 在用户 Bar 登录的情况下从机器 B 连接 同一时间,并且所有机器都在同一个网段中,中间没有任何路由器或代理。从 Fiddler 日志中我可以看到,如果发生故障,Casablanca 尝试在没有任何身份验证的情况下进行连接,然后从服务器接收到未经授权的 http 403(这是可以预料的并且非常好),但之后无法使用 NEGOTIATE 重新发送请求在标题中,它只是中止。相反,在成功的情况下, 重新发送凭据是 base64 编码的 blob(实际上具有二进制内容,大概只有 MS 知道它的含义)。我目前不清楚是什么触发了这种情况,为什么会发生这种情况以及如何解决这个问题。这很可能是卡萨布兰卡的一个错误。
  • 我有一个特殊情况,服务器具有混合操作模式,用户应该能够通过 BASIC 或 Windows 身份验证进行连接。让我们不要对以下场景和最佳实践的基本原理进行推理,我正在处理 IBM 的 TM1 数据库,这正是他们实现的。因此,允许进行基本身份验证和 Windows 身份验证的用户不一定重叠,一组必须通过集成的 Windows 进行身份验证(比如域用户),而另一组必须使用基本身份验证(比如外部用户)。到目前为止,我发现没有办法(没有修补 Casablanca)将 SDK 钳制到某种模式。如果服务器宣布 BASIC 和 NEGOTIATE,它将始终将 NEGOTIATE 切换为更安全的模式,使基本身份验证无法访问并有效地锁定 BASIC 组。因此,如果您有类似的情况,这对您来说同样是一个问题,ChooseAuthScheme() 按此顺序测试几种不同的身份验证方法,NEGOTIATE、NTLM、PASSPORT、DIGEST 和最后是 BASIC,并将顽固地选择第一个支持的客户端和服务器,放弃所有其他选项。

【讨论】:

    【解决方案2】:

    Casablanca (CpprestSDK) 完全支持NTLM 身份验证。如果服务器拒绝状态码为 401/403 且标头为 WWW-Authenticate 的请求,库将使用最安全的身份验证方法在内部处理它。在NTLM 的情况下,您可以指定登录名/密码对,或使用基于调用线程当前用户令牌的自动登录(Windows)。

    但是,当我尝试使用自动登录功能时,它在某些工作站上意外失败(Don Pedro 回答中的案例 1)。

    Windows 版本的 Cpprest 在内部使用 WinHTTP。当您尝试在远程服务器上自动进行身份验证时,automatic logon policy 生效。

    自动登录(auto-logon)策略决定何时 WinHTTP 可接受将默认凭据包含在 要求。默认凭据是当前线程令牌 或会话令牌取决于是否使用 WinHTTP 同步或异步模式。线程令牌用于 同步模式,会话令牌用于异步模式。 这些默认凭据通常是用于 登录到 Microsoft Windows。

    默认安全级别设置为WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM,它只允许内联网 服务器自动登录。管理 Intranet/Internet 服务器分类的规则在 Windows Internet 选项对话框中定义,并且有些模糊(至少在我们的例子中)。

    为了确保正确的自动登录,我使用请求本机处理程序配置将安全级别降低到 WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW

    web::http::client::http_client_config make_config()
    {
        web::http::client::http_client_config config;
        config.set_proxy(web::web_proxy::use_auto_discovery);
    
        if (!m_wsUser.empty()) {
            web::credentials cred(m_wsUser, m_wsPass);
            config.set_credentials(cred);
        }
    
        config.set_nativehandle_options([](web::http::client::native_handle handle) {
            DWORD dwOpt = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
            WinHttpSetOption(handle, WINHTTP_OPTION_AUTOLOGON_POLICY, &dwOpt, sizeof(dwOpt));
        });
    
        return config;
    }
    

    在我的情况下,这种方法是可以接受的,因为服务器和客户端始终位于组织网络边界内。否则此解决方案不安全,不应使用

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-23
      • 2011-04-09
      • 2018-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-10
      • 1970-01-01
      相关资源
      最近更新 更多