今天在使用Rest-Assured测试登录相关的功能,中间涉及到了HTTPS协议,当然,测试环境中的Certificate是自己定义的,还有一个是已经过期的!使用Rest-Assured访问的时候提示证书过期等各种问题。
花了点时间研究了一下,当然没有研究透彻,只是让它可以工作,留待后面专门研究HTTPS的整个连接创建流程后再补充完整吧。
这里说的两种方式,主要看客户端,如果只是用Java自带的HttpURLConnection等与HTTPS协议的server交互,则可以采用下面第一种方式来接受server的Certificates;如果采用的是Apache Http Client或者各种使用Apache Http Client作为底层交互的工具(如Rest-Assured),需要接受Server Certificates时,可以采用第二种方式:
- 1,客户端采用HttpURLConnection方式:
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// do nothing
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// do nothing
}
}};
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
2,客户端采用HttpClient方式:
2.1 自定义的SSLSocketFactory
import org.apache.http.conn.ssl.SSLSocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.IOException; import java.net.Socket; import java.security.*; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; public class AcceptAllCertsProtocolSocketFactory extends SSLSocketFactory { SSLContext sslContext = SSLContext.getInstance("TLS"); public AcceptAllCertsProtocolSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); TrustManager tm = new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { // do nothing } @Override public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { // do nothing } public X509Certificate[] getAcceptedIssuers() { return null; } }; sslContext.init(null, new TrustManager[]{tm}, null); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); } }
2.2 这里以使用Rest-Assured为例,在创建HttpClient实例的时候,使用上述SSLSocketFactory:
import com.jayway.restassured.config.HttpClientConfig; import org.apache.http.HttpVersion; import org.apache.http.client.HttpClient; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.HTTP; import java.security.KeyStore; public class AcceptAllCertsHttpClientFactory implements HttpClientConfig.HttpClientFactory { @Override public HttpClient createHttpClient() { try { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); AcceptAllCertsProtocolSocketFactory sf = new AcceptAllCertsProtocolSocketFactory(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); } catch (Exception e) { return new DefaultHttpClient(); } } }
- 2.3,确保Rest-Assured底层使用了上述HttpClient实例,而非默认的DefaultHttpClient:
RestAssured.config = RestAssured.config().httpClient(HttpClientConfig.httpClientConfig().httpClientFactory(new AcceptAllCertsHttpClientFactory()));
引用
- 1, Trusting all certificates using HttpClient over HTTPS
- 2, Java SSL/TLS ignore expired cert? (java.security.cert.CertPathValidatorException: timestamp check failed)