【问题标题】:How can I enable NTLM and TLS 1.2 with Xamarin on Android?如何在 Android 上使用 Xamarin 启用 NTLM 和 TLS 1.2?
【发布时间】:2016-11-22 07:22:35
【问题描述】:

我正在使用 Android 上 Xamarin 中的客户端应用程序,我需要 TLS 1.2 和 NTLM。

到目前为止,我一直在使用常规的 System.Net.HttpClientHandler,它运行良好 - 它看起来像这样:

new System.Net.Http.HttpClientHandler()
        {
            Credentials = credentials
        };

但现在我有一个新客户,我需要 TLS 1.2。所以我为Android制作了这段代码:

new Xamarin.Android.Net.AndroidClientHandler()
        {
            Credentials = credentials
        };

使用环境变量:

XA_HTTP_CLIENT_HANDLER_TYPE=Xamarin.Android.Net.AndroidClientHandler

现在,这个 AndroidClientHandler 可以在证书范围内工作。但我也需要 NTLM 才能工作。在我看来,AndroidClientHandler 似乎只支持 Basic 和 Digest 身份验证方案(请参阅 Xamarin.Android.Net.AuthenticationScheme)。

我也尝试过使用 ModernHttpClient,但在我看来,它使用 Mono 的方式与 System.Net.Http.HttpClientHandler 相同,因此 TLS 1.2 在那里也不起作用。

在我看来,这应该是一个很常见的情况,但我仍然无法在网络上找到相关示例。我希望我只是错过了一些明显的东西。你们是怎么解决这个问题的?

【问题讨论】:

  • TLS 1.2 最近才出现在 Mono/Xamarin 中。您使用的最新版本是多少? tirania.org/blog/archive/2016/Sep-30.html
  • 您好 scotru,感谢您的回答!我正在使用 Mono.Android 运行时 4.0.30319。我认为这就是我使用最新版本的 Xamarin 所获得的。
  • 我认为 Miguel 引用的更新尚未进入 Mono.Android 运行时版本。看起来 ModernHttpClient 应该可以与 TLS 1.2 一起使用。 wolfprogrammer.com/2016/08/23/enabling-tls-1-2-in-xamarin-forms
  • 是的,根据那个页面看起来是这样的。但是,当我运行该客户端时,我在 Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker 中确实遇到了几乎相同的异常;
  • 这个原生处理程序是在Xamarin.Android 6.1 - developer.xamarin.com/releases/android/xamarin.android_6/… 中引入的,因为它在底层使用java.net.URLConnection,它应该支持 NTLM,因为设备支持 TLS 1.2。我相信 API 20+ 默认支持 TLS 1.2。

标签: c# xamarin xamarin.android ntlm tls1.2


【解决方案1】:

我相信通读会对您有所帮助:

https://github.com/xamarin/xamarin-android/blob/0c3597869bc4493895e755bda8a26f778e4fe9e0/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs#L40-L56

/// <para>
/// The class supports pre-authentication of requests albeit in a slightly "manual" way. Namely, whenever a request to a server requiring authentication
/// is made and no authentication credentials are provided in the <see cref="PreAuthenticationData"/> property (which is usually the case on the first
/// request), the <see cref="RequestNeedsAuthorization"/> property will return <c>true</c> and the <see cref="RequestedAuthentication"/> property will
/// contain all the authentication information gathered from the server. The application must then fill in the blanks (i.e. the credentials) and re-send
/// the request configured to perform pre-authentication. The reason for this manual process is that the underlying Java HTTP client API supports only a 
/// single, VM-wide, authentication handler which cannot be configured to handle credentials for several requests. AndroidClientHandler, therefore, implements
/// the authentication in managed .NET code. Message handler supports both Basic and Digest authentication. If an authentication scheme that's not supported
/// by AndroidClientHandler is requested by the server, the application can provide its own authentication module (<see cref="AuthenticationData"/>, 
/// <see cref="PreAuthenticationData"/>) to handle the protocol authorization.</para>
/// <para>AndroidClientHandler also supports requests to servers with "invalid" (e.g. self-signed) SSL certificates. Since this process is a bit convoluted using
/// the Java APIs, AndroidClientHandler defines two ways to handle the situation. First, easier, is to store the necessary certificates (either CA or server certificates)
/// in the <see cref="TrustedCerts"/> collection or, after deriving a custom class from AndroidClientHandler, by overriding one or more methods provided for this purpose
/// (<see cref="ConfigureTrustManagerFactory"/>, <see cref="ConfigureKeyManagerFactory"/> and <see cref="ConfigureKeyStore"/>). The former method should be sufficient
/// for most use cases, the latter allows the application to provide fully customized key store, trust manager and key manager, if needed. Note that the instance of
/// AndroidClientHandler configured to accept an "invalid" certificate from the particular server will most likely fail to validate certificates from other servers (even
/// if they use a certificate with a fully validated trust chain) unless you store the CA certificates from your Android system in <see cref="TrustedCerts"/> along with
/// the self-signed certificate(s).</para>

基本上这是说:它支持BasicDigest 身份验证。如果服务器请求的AndroidClientHandler 中不支持的身份验证方案,应用程序可以提供自己的身份验证模块来处理协议授权。

然后我们可以看到RequestedAuthentication 属性会列出服务器支持的每个方案。:

https://github.com/xamarin/xamarin-android/blob/0c3597869bc4493895e755bda8a26f778e4fe9e0/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs#L116-L124

/// <summary>
/// If the website requires authentication, this property will contain data about each scheme supported
/// by the server after the response. Note that unauthorized request will return a valid response - you
/// need to check the status code and and (re)configure AndroidClientHandler instance accordingly by providing
/// both the credentials and the authentication scheme by setting the <see cref="PreAuthenticationData"/> 
/// property. If AndroidClientHandler is not able to detect the kind of authentication scheme it will store an
/// instance of <see cref="AuthenticationData"/> with its <see cref="AuthenticationData.Scheme"/> property
/// set to <c>AuthenticationScheme.Unsupported</c> and the application will be responsible for providing an
/// instance of <see cref="IAndroidAuthenticationModule"/> which handles this kind of authorization scheme
/// (<see cref="AuthenticationData.AuthModule"/>
/// </summary>

这告诉我们,如果它返回 Unsupported 作为我们的 AuthenticationScheme,那么我们需要提交自己的 IAndroidAuthenticationModule 来处理挑战。

这是AuthenticationScheme的枚举:

https://github.com/xamarin/xamarin-android/blob/24f2aec113857b5c583e14959b9af08ad45b22b1/src/Mono.Android/Xamarin.Android.Net/AuthenticationScheme.cs

namespace Xamarin.Android.Net
{
    /// <summary>
    /// Authentication schemes supported by <see cref="AndroidClientHandler"/>
    /// </summary>
    public enum AuthenticationScheme
    {
        /// <summary>
        /// Default value used in <see cref="AuthenticationData.Scheme"/>
        /// </summary>
        None,

        /// <summary>
        /// <see cref="AndroidClientHandler"/> doesn't support this scheme, the application must provide its own value. See <see cref="AuthenticationData.Scheme"/>
        /// </summary>
        Unsupported,

        /// <summary>
        /// The HTTP Basic authentication scheme
        /// </summary>
        Basic,

        /// <summary>
        /// The HTTP Digest authentication scheme
        /// </summary>
        Digest
    }
}

因此,我们必须通过在您的实现上扩展此接口来实现自定义 IAndroidAuthenticationModule

https://github.com/xamarin/xamarin-android/blob/24f2aec113857b5c583e14959b9af08ad45b22b1/src/Mono.Android/Xamarin.Android.Net/IAndroidAuthenticationModule.cs

然后您将该实现传递给AuthenticationData.AuthModule 属性:

https://github.com/xamarin/xamarin-android/blob/24f2aec113857b5c583e14959b9af08ad45b22b1/src/Mono.Android/Xamarin.Android.Net/AuthenticationData.cs#L37

然后您将其传递给主客户端的 PreAuthenticationData 属性。

https://github.com/xamarin/xamarin-android/blob/0c3597869bc4493895e755bda8a26f778e4fe9e0/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs#L113

我希望这会有所帮助!

【讨论】:

  • Xamarin.Forms 怎么样? Droid 版本无法连接到 TLS 1.2 网站。图像加载:获取randomuser.me/api/portraits/med/men/85.jpg 的流时出错:System.Net.WebException:错误:SecureChannelFailure(身份验证或解密失败。)---> System.IO.IOException:身份验证或解密失败。 ---> System.IO.IOException: 认证或解密失败。 ---> Mono.Security.Protocol.Tls.TlsException: 认证或解密失败。
  • Xamarin Forms 与底层 TLS API 无关。您与此服务器的握手失败,因此您必须调查原因。我上面的回答是使用 NTLM 作为你的身份验证方案和新的 AndroidClientHandler。
猜你喜欢
  • 2019-08-03
  • 2019-06-04
  • 2015-03-15
  • 2018-02-03
  • 1970-01-01
  • 2019-04-29
  • 2018-10-31
  • 2017-07-22
  • 2018-10-13
相关资源
最近更新 更多