我一直在尝试与 Camel 一起使用2路ssl/https代理。我已经能够使用2-way ssl设置Jetty组件,现在正尝试使其与Http4组件一起使用以完成代理的客户端。

当我将 jetty 流量路由到日志组件时,一切都很好,并且2路ssl信任链也很好。当我放入Http4组件时,它会因一个未通过身份验证的对等对象而崩溃。我正在使用 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<Integer, SslSelectChannelConnector> connectors = new HashMap<Integer, SslSelectChannelConnector>();
    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<String> aliasList = new ArrayList<String>();
            int count = 0;
            Enumeration<String> 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;
    }
}

}

据我所知,在代理连接两侧使用的所有 keystore /信任库之间的信任关系应该都很好。

这是我的堆栈跟踪

[qtp25584663-14] HttpProducer调试执行http POST方法:https4://soafa-lite-staging:443/axis2/services/SigActService?bridgeEndpoint = true&throwExceptionOnFailure = false
[qtp25584663-14] DefaultErrorHandler调试exchangeId:ID-ubuntu-46528-1303140195358-0-1的传递失败。交付尝试:0捕获:javax.net.ssl.SSLPeerUnverifiedException:对等方未通过身份验证
[qtp25584663-14] DefaultErrorHandler错误Exchange ID传递失败:ID-ubuntu-46528-1303140195358-0-1。交付尝试后用尽:1个被捕获:javax.net.ssl.SSLPeerUnverifiedException:对等方未通过身份验证
javax.net.ssl.SSLPeerUnverifiedException:对等方未通过身份验证
在com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
在org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
在org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:390)
在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)
在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)
在org.apache.camel.impl.converter.AsyncProcessorTypeConverter $ ProcessorToAsyncProcessorBridge.process(AsyncProcessorTypeConverter.java:50)处
在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)
在org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
在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)
在org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
在org.apache.camel.processor.RedeliveryErrorHandler.processErrorHandler(RedeliveryErrorHandler.java:299)
在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)
在org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:77)
在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)
在org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:929)
在org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:403)
在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)
在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)

最佳答案

事实证明,现在可以正常工作了,我对Camel中的端点和协议(protocol)有基本的误解。我应该一直在使用https4协议(protocol)注册一个方案,并在上面设置我的SSLSocketFactory/SSLContext。由于它正在使用https注册方案,因此Http4组件从未使用过它。

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

  • 为什么不能将SchemeRegistry传递给ThreadSafeClientConnManager,并且在构造HttpClient时不使用它?我必须使用HttpClientConfigurer而不是
  • Jetty有一个问题,即必须通过SslSelectChannelConnector上的路径而不是通过SSLContext设置 keystore 和信任库(错误至少存在于 jetty 7.2.2和7.4.0->最新)

  • 代码:
    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<Integer, SslSelectChannelConnector> connectors = new HashMap<Integer, SslSelectChannelConnector>();
        connectors.put(4443, sslConnector);
    
        jetty.setSslSocketConnectors(connectors);
        return jetty.createEndpoint("jetty:https://localhost:4443/service");
    }
    
    // .to("log:com.smithforge.response?showHeaders=true");
    }
    

    09-10 10:05
    查看更多