提交 6b065f52 编写于 作者: A allenxwang

Merge pull request #60 from zarfide/master

add hook for custom ssl factory and AcceptAllSocketFactory implementation
......@@ -65,6 +65,9 @@ public enum CommonClientConfigKey implements IClientConfigKey {
TrustStore("TrustStore"),
TrustStorePassword("TrustStorePassword"),
IsClientAuthRequired("IsClientAuthRequired"), // if this is a secure rest client, must we use client auth too?
CustomSSLSocketFactoryClassName("CustomSSLSocketFactoryClassName"),
IsHostnameValidationRequired("IsHostnameValidationRequired"), // must host name match name in certificate?
IgnoreUserTokenInConnectionPoolForSecureClient("IgnoreUserTokenInConnectionPoolForSecureClient"), // see also http://hc.apache.org/httpcomponents-client-ga/tutorial/html/advanced.html
......
/*
*
* Copyright 2013 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.netflix.http4.ssl;
import com.netflix.client.IClientConfigAware;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.IClientConfig;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
*
* SSL Socket factory that will accept all remote endpoints.
*
* This should be used only for testing connections/connectivity.
*
* Following similar pattern as load-balancers here, which is to take an IClientConfig
*
* @author jzarfoss
*
*/
public class AcceptAllSocketFactory extends SSLSocketFactory implements IClientConfigAware {
public AcceptAllSocketFactory() throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
super(new TrustStrategy() {
@Override
public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
}
/**
* In the case of this factory the intent is to ensure that a truststore is not set,
* as this does not make sense in the context of an accept-all policy
*/
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
if (clientConfig == null) {
return;
}
if(clientConfig.getProperty(CommonClientConfigKey.TrustStore) != null){
throw new IllegalArgumentException("Client configured with an AcceptAllSocketFactory cannot utilize a truststore");
}
}
}
......@@ -31,6 +31,7 @@ import java.util.Map;
import javax.ws.rs.core.MultivaluedMap;
import com.netflix.client.ClientFactory;
import org.apache.http.HttpHost;
import org.apache.http.client.HttpClient;
import org.apache.http.client.UserTokenHandler;
......@@ -394,6 +395,23 @@ public class RestClient extends AbstractLoadBalancerAwareClient<HttpRequest, Htt
});
}
// custom SSL Factory handler
String customSSLFactoryClassName = (String) ncc.getProperty(CommonClientConfigKey.CustomSSLSocketFactoryClassName);
if(customSSLFactoryClassName != null){
try{
SSLSocketFactory customSocketFactory = (SSLSocketFactory) ClientFactory.instantiateInstanceWithClientConfig(customSSLFactoryClassName, ncc);
httpClient4.getConnectionManager().getSchemeRegistry().register(new Scheme(
"https",443, customSocketFactory));
}catch(Exception e){
throw new IllegalArgumentException("Invalid value associated with property:"
+ CommonClientConfigKey.CustomSSLSocketFactoryClassName, e);
}
}
ApacheHttpClient4Handler handler = new ApacheHttpClient4Handler(httpClient4, new BasicCookieStore(), false);
return new ApacheHttpClient4(handler, config);
......
/*
*
* Copyright 2013 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.netflix.niws.client.http;
import com.netflix.client.ClientFactory;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.http.HttpRequest;
import com.netflix.client.http.HttpResponse;
import com.netflix.client.testutil.SimpleSSLTestServer;
import com.netflix.config.ConfigurationManager;
import com.sun.jersey.core.util.Base64;
import org.apache.commons.configuration.AbstractConfiguration;
import org.junit.*;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URI;
import java.util.Random;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
*
* Test that the AcceptAllSocketFactory works against a dumbed down TLS server, except when it shouldn't...
*
* @author jzarfoss
*
*/
public class SecureAcceptAllGetTest {
private static int TEST_PORT;
private static String TEST_SERVICE_URI;
private static File TEST_FILE_KS;
private static File TEST_FILE_TS;
private static SimpleSSLTestServer TEST_SERVER;
@BeforeClass
public static void init() throws Exception {
// setup server 1, will use first keystore/truststore with client auth
TEST_PORT = new Random().nextInt(1000) + 4000;
TEST_SERVICE_URI = "https://127.0.0.1:" + TEST_PORT + "/";
// jks format
byte[] sampleTruststore1 = Base64.decode(SecureGetTest.TEST_TS1);
byte[] sampleKeystore1 = Base64.decode(SecureGetTest.TEST_KS1);
TEST_FILE_KS = File.createTempFile("SecureAcceptAllGetTest", ".keystore");
TEST_FILE_TS = File.createTempFile("SecureAcceptAllGetTest", ".truststore");
FileOutputStream keystoreFileOut = new FileOutputStream(TEST_FILE_KS);
keystoreFileOut.write(sampleKeystore1);
keystoreFileOut.close();
FileOutputStream truststoreFileOut = new FileOutputStream(TEST_FILE_TS);
truststoreFileOut.write(sampleTruststore1);
truststoreFileOut.close();
try{
TEST_SERVER = new SimpleSSLTestServer(TEST_FILE_TS, SecureGetTest.PASSWORD, TEST_FILE_KS, SecureGetTest.PASSWORD, TEST_PORT, false);
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
@AfterClass
public static void shutDown(){
try{
TEST_SERVER.close();
}catch(Exception e){
e.printStackTrace();
}
}
@Test
public void testPositiveAcceptAllSSLSocketFactory() throws Exception{
// test connection succeeds connecting to a random SSL endpoint with allow all SSL factory
AbstractConfiguration cm = ConfigurationManager.getConfigInstance();
String name = "GetPostSecureTest" + ".testPositiveAcceptAllSSLSocketFactory";
String configPrefix = name + "." + "ribbon";
cm.setProperty(configPrefix + "." + CommonClientConfigKey.CustomSSLSocketFactoryClassName, "com.netflix.http4.ssl.AcceptAllSocketFactory");
RestClient rc = (RestClient) ClientFactory.getNamedClient(name);
TEST_SERVER.accept();
URI getUri = new URI(TEST_SERVICE_URI + "test/");
HttpRequest request = HttpRequest.newBuilder().uri(getUri).queryParams("name", "test").build();
HttpResponse response = rc.execute(request);
assertEquals(200, response.getStatus());
}
@Test
public void testNegativeAcceptAllSSLSocketFactoryCannotWorkWithTrustStore() throws Exception{
// test config exception happens before we even try to connect to anything
AbstractConfiguration cm = ConfigurationManager.getConfigInstance();
String name = "GetPostSecureTest" + ".testNegativeAcceptAllSSLSocketFactoryCannotWorkWithTrustStore";
String configPrefix = name + "." + "ribbon";
cm.setProperty(configPrefix + "." + CommonClientConfigKey.CustomSSLSocketFactoryClassName, "com.netflix.http4.ssl.AcceptAllSocketFactory");
cm.setProperty(configPrefix + "." + CommonClientConfigKey.TrustStore, TEST_FILE_TS.getAbsolutePath());
cm.setProperty(configPrefix + "." + CommonClientConfigKey.TrustStorePassword, SecureGetTest.PASSWORD);
boolean foundCause = false;
try{
ClientFactory.getNamedClient(name);
}catch(Throwable t){
while(t != null && ! foundCause){
if(t instanceof IllegalArgumentException && t.getMessage().startsWith("Invalid value associated with property:CustomSSLSocketFactoryClassName")){
foundCause = true;
break;
}
t = t.getCause();
}
}
assertTrue(foundCause);
}
@Test
public void testNegativeAcceptAllSSLSocketFactory() throws Exception{
// test exception is thrown connecting to a random SSL endpoint without explicitly setting factory to allow all
String name = "GetPostSecureTest" + ".testNegativeAcceptAllSSLSocketFactory";
// don't set any interesting properties -- really we're just setting the defaults
RestClient rc = (RestClient) ClientFactory.getNamedClient(name);
TEST_SERVER.accept();
URI getUri = new URI(TEST_SERVICE_URI + "test/");
HttpRequest request = HttpRequest.newBuilder().uri(getUri).queryParams("name", "test").build();
boolean foundCause = false;
try{
rc.execute(request);
}catch(Throwable t){
while(t != null && ! foundCause){
if(t instanceof SSLPeerUnverifiedException && t.getMessage().startsWith("peer not authenticated")){
foundCause = true;
break;
}
t = t.getCause();
}
}
assertTrue(foundCause);
}
}
......@@ -257,7 +257,7 @@ public class SecureGetTest {
private static File FILE_TS2;
private static File FILE_KS2;
private static String PASSWORD = "changeit";
public static final String PASSWORD = "changeit";
@BeforeClass
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册