Android 在 SSL 上使用 NTLM 失败
Android Using NTLM over SSL failing
我正在尝试从我的 android 应用程序中访问受 SSL 和 NTLM 保护的 json 网络服务。当然,在浏览器中,我可以直接点击 url https://service.example.com/service1/
,使用 domain/user/password 进行身份验证,并获得 json 结果。
使用 JCIFS,我有 NTLM 工作,我可以通过 HTTP(在特殊网络上的测试设备上)访问这个网络服务,一切都很好。
工作代码
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getAuthSchemes().register("ntlm", new NTLMSchemeFactory());
NTCredentials creds = new NTCredentials("username", "password", "", "domain");
httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);
HttpHost target = new HttpHost(serviceHostname, 80, "http");
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("/service1");
HttpResponse response = httpclient.execute(target, httpget, localContext);
HttpEntity entity = response.getEntity();
String responseString = EntityUtils.toString(entity);
其中 NTLMSchemeFactory
来自 JCIFSEngine
代码
所以当切换到 SSL 时我发现该服务的服务器不提供中间证书(参见 https://developer.android.com/training/articles/security-ssl.html#MissingCa)
因此抛出 java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
异常。
我尝试在信任管理器中添加该特定证书,但它一直导致服务器出现 return 500 错误。因此,我什至进一步尝试允许所有使用空信任管理器的证书开始执行此操作,这也会引发 500 个错误。
代码(来自)
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
public static DefaultHttpClient getNewHttpClient() {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
}
使用原始工作代码,但将 DefaultHttpClient httpclient = new DefaultHttpClient();
替换为 DefaultHttpClient httpclient = MySSLSocketFactory.getNewHttpClient();
如何将 NTLM 身份验证与错误的 SSL 连接结合起来?
我正试图让网络服务服务器人员包括他们的中间证书,但我现在不抱太大希望。
所以我的问题的解决方案是将中间证书加载到提供网络服务的网络服务器上。 Android 只是不像浏览器那样喜欢或处理丢失的中间证书。
我正在尝试从我的 android 应用程序中访问受 SSL 和 NTLM 保护的 json 网络服务。当然,在浏览器中,我可以直接点击 url https://service.example.com/service1/
,使用 domain/user/password 进行身份验证,并获得 json 结果。
使用 JCIFS,我有 NTLM 工作,我可以通过 HTTP(在特殊网络上的测试设备上)访问这个网络服务,一切都很好。
工作代码
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getAuthSchemes().register("ntlm", new NTLMSchemeFactory());
NTCredentials creds = new NTCredentials("username", "password", "", "domain");
httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);
HttpHost target = new HttpHost(serviceHostname, 80, "http");
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("/service1");
HttpResponse response = httpclient.execute(target, httpget, localContext);
HttpEntity entity = response.getEntity();
String responseString = EntityUtils.toString(entity);
其中 NTLMSchemeFactory
来自 JCIFSEngine
代码
所以当切换到 SSL 时我发现该服务的服务器不提供中间证书(参见 https://developer.android.com/training/articles/security-ssl.html#MissingCa)
因此抛出 java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
异常。
我尝试在信任管理器中添加该特定证书,但它一直导致服务器出现 return 500 错误。因此,我什至进一步尝试允许所有使用空信任管理器的证书开始执行此操作,这也会引发 500 个错误。
代码(来自)
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
public static DefaultHttpClient getNewHttpClient() {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
}
使用原始工作代码,但将 DefaultHttpClient httpclient = new DefaultHttpClient();
替换为 DefaultHttpClient httpclient = MySSLSocketFactory.getNewHttpClient();
如何将 NTLM 身份验证与错误的 SSL 连接结合起来?
我正试图让网络服务服务器人员包括他们的中间证书,但我现在不抱太大希望。
所以我的问题的解决方案是将中间证书加载到提供网络服务的网络服务器上。 Android 只是不像浏览器那样喜欢或处理丢失的中间证书。