【发布时间】:2015-09-03 20:24:48
【问题描述】:
我正在尝试从我的 android 应用程序中访问受 SSL 和 NTLM 保护的 json 网络服务。当然,我可以从浏览器直接点击 url https://service.example.com/service1/,使用域/用户/密码进行身份验证,然后获取 json 结果。
使用 JCIFS,我有 NTLM 工作,我可以通过 HTTP(在特殊网络上的测试设备上)访问此 Web 服务,并且一切正常。
工作代码
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.
异常。
我尝试在信任管理器中添加该特定证书,但它一直导致服务器返回 500 错误。所以我什至进一步尝试允许所有使用空信任管理器的证书甚至开始处理这个问题,这也会引发 500 个错误。
代码(原文来自Trusting all certificates using HttpClient over HTTPS)
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 连接结合起来?
我正在尝试让 web 服务服务器人员包含他们的中间证书,但我现在并不抱太大希望。
【问题讨论】:
-
您使用的是什么版本的 SSL?
-
@IgorGanapolsky 我怎么会发现这个?这个应用程序仍在我最新的 android 设备上运行。
-
从命令行运行:openssl s_client -connect yourdomain.com:443
-
@IgorGanapolsky
SSL-Session: Protocol : TLSv1.2 -
看起来您的服务器没有使用 SSL 证书。只是 TLS(较新)。这里有一篇很好的文章来解释区别:luxsci.com/blog/ssl-versus-tls-whats-the-difference.html
标签: java android ssl https ntlm