Apache Camel Http和SSL

我一直试图让一个双向的ssl / https代理与Camel一起工作。 我已经能够使用双向ssl设置Jetty组件,现在我正在尝试使用Http4组件来完成代理的客户端。

当我将docker流量路由到日志组件时,一切都很顺利,2路ssl信任链也没问题。 当我抛出Http4组件时,它会爆发一个未经过身份validation的对等exception。 我使用的是Camel 2.7.0

这是我到目前为止所拥有的

public static void main(String[] args) throws Exception { CamelContext context = new DefaultCamelContext(); JettyHttpComponent jetty = context.getComponent("jetty", JettyHttpComponent.class); SslSelectChannelConnector sslConnector = new SslSelectChannelConnector(); sslConnector.setPort(9443); sslConnector.setKeystore("/home/brian/jboss.keystore"); sslConnector.setKeyPassword("changeit"); sslConnector.setTruststore("/home/brian/jboss.truststore"); sslConnector.setTrustPassword("changeit"); sslConnector.setPassword("changeit"); sslConnector.setNeedClientAuth(true); Map connectors = new HashMap(); connectors.put(9443, sslConnector); jetty.setSslSocketConnectors(connectors); final Endpoint jettyEndpoint = jetty.createEndpoint("jetty:https://localhost:9443/service"); KeyStore keystore = KeyStore.getInstance("PKCS12"); keystore.load(new FileInputStream(new File("/home/brian/User2.p12")), "Password1234!".toCharArray()); X509KeyManager keyManager = new CTSKeyManager(keystore, "user2", "Password1234!".toCharArray()); KeyManager[] keyManagers = new KeyManager[] { keyManager }; X509TrustManager trustManager = new EasyTrustManager(); TrustManager[] trustManagers = new TrustManager[] { trustManager }; SSLContext sslcontext = SSLContext.getInstance("TLS"); sslcontext.init(keyManagers, trustManagers, null); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("https", 443, new SSLSocketFactory(sslcontext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER))); HttpComponent http4 = context.getComponent("http4", HttpComponent.class); http4.setClientConnectionManager(new ThreadSafeClientConnManager(registry)); final Endpoint https4Endpoint = http4 .createEndpoint("https4://soafa-lite-staging:443/axis2/services/SigActService?bridgeEndpoint=true&throwExceptionOnFailure=false"); context.addRoutes(new RouteBuilder() { @Override public void configure() { from(jettyEndpoint).to(https4Endpoint); } }); context.start(); context.stop(); } private static class EasyTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }; private static class CTSKeyManager extends X509ExtendedKeyManager { private final KeyStore keystore; private final char[] privateKeyPassword; private final String privateKeyAlias; public CTSKeyManager(KeyStore keystore, String privateKeyAlias, char[] privateKeyPassword) { this.keystore = keystore; this.privateKeyAlias = privateKeyAlias; this.privateKeyPassword = privateKeyPassword; } @Override public String[] getServerAliases(String keyType, Principal[] issuers) { String[] serverAliases = null; try { List aliasList = new ArrayList(); int count = 0; Enumeration aliases = keystore.aliases(); while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); aliasList.add(alias); count++; } serverAliases = aliasList.toArray(new String[count]); } catch (Exception e) { } return serverAliases; } @Override public PrivateKey getPrivateKey(String alias) { PrivateKey privateKey = null; try { privateKey = (PrivateKey) keystore.getKey(alias, privateKeyPassword); } catch (Exception e) { } return privateKey; } @Override public String[] getClientAliases(String keyType, Principal[] issuers) { return privateKeyAlias == null ? null : new String[] { privateKeyAlias }; } @Override public X509Certificate[] getCertificateChain(String alias) { X509Certificate[] x509 = null; try { Certificate[] certs = keystore.getCertificateChain(alias); if (certs == null || certs.length == 0) { return null; } x509 = new X509Certificate[certs.length]; for (int i = 0; i < certs.length; i++) { x509[i] = (X509Certificate) certs[i]; } } catch (Exception e) { } return x509; } @Override public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { return privateKeyAlias; } @Override public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { return privateKeyAlias; } @Override public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) { return privateKeyAlias; } @Override public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { return privateKeyAlias; } } } 

据我所知,在代理连接两端使用的所有密钥库/信任库之间的信任应该没问题。

这是我的堆栈跟踪

 [qtp25584663-14] HttpProducer DEBUG执行http POST方法:https4:// soafa-lite-staging:443 / axis2 / services / SigActService?bridgeEndpoint = true&throwExceptionOnFailure = false
 [qtp25584663-14] DefaultErrorHandler DEBUG exchangeId的交付失败:ID-ubuntu-46528-1303140195358-0-1。 在传递尝试时:0捕获:javax.net.ssl.SSLPeerUnverifiedException:peer未经过身份validation
 [qtp25584663-14] DefaultErrorHandler ERROR exchangeId的交付失败:ID-ubuntu-46528-1303140195358-0-1。 在传递尝试后耗尽:1捕获:javax.net.ssl.SSLPeerUnverifiedException:peer未经过身份validation
 javax.net.ssl.SSLPeerUnverifiedException:peer未经过身份validation
     at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
    在org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
     at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:390)
     at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
    在org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
    在org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
     at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:561)
    在org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
    在org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
    在org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
    在org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
    在org.apache.camel.component.http4.HttpProducer.executeMethod(HttpProducer.java:187)
    在org.apache.camel.component.http4.HttpProducer.process(HttpProducer.java:101)
     at org.apache.camel.impl.converter.AsyncProcessorTypeConverter $ ProcessorToAsyncProcessorBridge.process(AsyncProcessorTypeConverter.java:50)
     at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
    在org.apache.camel.processor.SendProcessor $ 2.doInAsyncProducer(SendProcessor.java:104)
    在org.apache.camel.impl.ProducerCache.doInAsyncProducer(ProducerCache.java:272)
    在org.apache.camel.processor.SendProcessor.process(SendProcessor.java:98)
     at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
     at org.apache.camel.processor.DelegateAsyncProcessor.processNext(DelegateAsyncProcessor.java:98)
    在org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:89)
    在org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:99)
     at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
     at org.apache.camel.processor.RedeliveryErrorHandler.processErrorHandler(RedeliveryErrorHandler.java:299)
     at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:208)
    在org.apache.camel.processor.DefaultChannel.process(DefaultChannel.java:269)
    在org.apache.camel.processor.UnitOfWorkProcessor.process(UnitOfWorkProcessor.java:109)
     at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
     at org.apache.camel.processor.DelegateAsyncProcessor.processNext(DelegateAsyncProcessor.java:98)
    在org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:89)
    在org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:68)
    在org.apache.camel.component.jetty.CamelContinuationServlet.service(CamelContinuationServlet.java:109)
    在javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    在org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:534)
    在org.eclipse.jetty.servlet.ServletHandler $ CachedChain.doFilter(ServletHandler.java:1351)
    在org.eclipse.jetty.servlets.MultiPartFilter.doFilter(MultiPartFilter.java:97)
    在org.apache.camel.component.jetty.CamelMultipartFilter.doFilter(CamelMultipartFilter.java:41)
    在org.eclipse.jetty.servlet.ServletHandler $ CachedChain.doFilter(ServletHandler.java:1322)
    在org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:473)
     at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:929)
    在org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:403)
     at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:864)
    在org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
    在org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:114)
    在org.eclipse.jetty.server.Server.handle(Server.java:352)
    在org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:596)
     at org.eclipse.jetty.server.HttpConnection $ RequestHandler.content(HttpConnection.java:1068)
    在org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:805)
    在org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:218)
    在org.eclipse.jetty.server.HttpConnection.handle(HttpConnection.java:426)
    在org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:508)
    在org.eclipse.jetty.io.nio.SelectChannelEndPoint.access $ 000(SelectChannelEndPoint.java:34)
    在org.eclipse.jetty.io.nio.SelectChannelEndPoint $ 1.run(SelectChannelEndPoint.java:40)
    在org.eclipse.jetty.util.thread.QueuedThreadPool $ 2.run(QueuedThreadPool.java:451)
    在java.lang.Thread.run(Thread.java:662) 

好了,现在,事实certificate,我对Camel中的端点和协议有一个基本的误解。 我本来应该使用https4协议注册一个方案,并在其上设置我的SSLSocketFactory / SSLContext。 由于它使用https注册了一个方案,因此它从未被Http4组件使用。

这是我的工作解决方案,有2个警告。

  1. 为什么我不能将SchemeRegistry传递给ThreadSafeClientConnManager并且在构造HttpClient时不使用它? 我不得不使用HttpClientConfigurer

  2. Jetty存在一个问题,即必须通过SslSelectChannelConnector上的路径而不是通过SSLContext设置Keystore和Truststore(bug至少是jetty 7.2.2和7.4.0 – > latest)

码:

 public class CamelProxy { /** * @param args */ public static void main(String[] args) throws Exception { CamelContext context = new DefaultCamelContext(); final Endpoint jettyEndpoint = configureJetty(context); final Endpoint https4Endpoint = configureHttpClient(context); context.addRoutes(new RouteBuilder() { @Override public void configure() { from(jettyEndpoint).to("log:com.smithforge.request?showAll=true").to(https4Endpoint); } }); context.start(); context.stop(); } private static Endpoint configureHttpClient(CamelContext context) throws Exception { KeyStore keystore = KeyStore.getInstance("PKCS12"); keystore.load(new FileInputStream(new File("/home/brian/User2.p12")), "Password1234!".toCharArray()); KeyStore truststore = KeyStore.getInstance("JKS"); truststore.load(new FileInputStream(new File("/home/brian/jboss.truststore")), "changeit".toCharArray()); KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("SunX509"); keyFactory.init(keystore, "Password1234!".toCharArray()); TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("SunX509"); trustFactory.init(truststore); SSLContext sslcontext = SSLContext.getInstance("TLSv1"); sslcontext.init(keyFactory.getKeyManagers(), trustFactory.getTrustManagers(), null); SSLSocketFactory factory = new SSLSocketFactory(sslcontext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); SchemeRegistry registry = new SchemeRegistry(); final Scheme scheme = new Scheme("https4", 443, factory); registry.register(scheme); HttpComponent http4 = context.getComponent("http4", HttpComponent.class); http4.setHttpClientConfigurer(new HttpClientConfigurer() { @Override public void configureHttpClient(HttpClient client) { client.getConnectionManager().getSchemeRegistry().register(scheme); } }); http4.setClientConnectionManager(new ThreadSafeClientConnManager()); return http4 .createEndpoint("https4://soafa-lite-staging:443/axis2/services/SigActService?bridgeEndpoint=true&throwExceptionOnFailure=false"); } private static Endpoint configureJetty(CamelContext context) throws Exception { JettyHttpComponent jetty = context.getComponent("jetty", JettyHttpComponent.class); SslSelectChannelConnector sslConnector = new SslSelectChannelConnector(); sslConnector.setPort(4443); sslConnector.setKeystore("/home/brian/jboss.keystore"); sslConnector.setKeyPassword("changeit"); sslConnector.setTruststore("/home/brian/jboss.truststore"); sslConnector.setTrustPassword("changeit"); sslConnector.setPassword("changeit"); sslConnector.setNeedClientAuth(true); sslConnector.setAllowRenegotiate(true); Map connectors = new HashMap(); connectors.put(4443, sslConnector); jetty.setSslSocketConnectors(connectors); return jetty.createEndpoint("jetty:https://localhost:4443/service"); } // .to("log:com.smithforge.response?showHeaders=true"); } 

我必须使用以下代码处理ssl代理

路线

 public class MyRouteBuilder extends RouteBuilder { public void configure() { configureSslForJetty(); configureSslForHttp4(); from("jetty:https://0.0.0.0:4443/topython/?matchOnUriPrefix=true") .to("https4://backend.fake.com:4444/?q=ssl&bridgeEndpoint=true&throwExceptionOnFailure=false"); } ... 

jetty的配置 (当我们充当服务器时提供证书)

 private void configureSslForJetty() { KeyStoreParameters ksp = new KeyStoreParameters(); ksp.setResource("c:\\Projects\\blah\\fakefilter.jks"); ksp.setPassword("123456"); KeyManagersParameters kmp = new KeyManagersParameters(); kmp.setKeyStore(ksp); kmp.setKeyPassword("export-password"); SSLContextParameters scp = new SSLContextParameters(); scp.setKeyManagers(kmp); JettyHttpComponent jettyComponent = getContext().getComponent("jetty", JettyHttpComponent.class); jettyComponent.setSslContextParameters(scp); } 

https4的配置 (作为客户端时我们信任的证书签名者)

 private void configureSslForHttp4() { KeyStoreParameters trust_ksp = new KeyStoreParameters(); trust_ksp.setResource("c:\\Projects\\blah\\fakeca.jks"); trust_ksp.setPassword("123456"); TrustManagersParameters trustp = new TrustManagersParameters(); trustp.setKeyStore(trust_ksp); SSLContextParameters scp = new SSLContextParameters(); scp.setTrustManagers(trustp); HttpComponent httpComponent = getContext().getComponent("https4", HttpComponent.class); httpComponent.setSslContextParameters(scp); } 

}

值得注意的事情

  • 您需要配置组件https4而不是http4
  • 命令行中的-Djavax.net.debug=ssl提供了大量有用的日志记录

看起来你有’ 不安全的ssl重新谈判 ‘的问题。 请确认您使用的是最新的JDK / JRE(至少1.6.0_24)。