绑定CXF Client源IP地址

Binding CXF Client source IP address

我有一个连接到 Web 服务的 CXF 客户端。此客户端安装在同一网络中有两个 IP 地址的机器上(例如 172.16.1.101 和 172.16.1.102)。

如何将 CXF 客户端配置为使用特定源 IP 地址,以便服务器看到来自该特定 IP 地址而不是其他 IP 地址的请求?

如果我可以访问 Socket,我会做类似的事情:

Socket s = new Socket(); 
s.bind(new InetSocketAddress("172.16.1.102", 0));  //this Ip address is the one I need to specify
s.connect(new InetSocketAddress("google.com", 80));

是否可以配置由 CXF 创建的套接字以便指定源 IP 地址?

编辑:我需要指定源 IP 地址,因为在客户端和 Web 服务器之间有一个防火墙,该防火墙对其中一个 IP 地址有规则(来自另一个 IP 地址的连接被阻止)。

不确定我是否正确理解了你的问题,但我认为你不需要在客户端上专门设置一个 IP 地址来让服务器读取`

Message message = PhaseInterceptorChain.getCurrentMessage();
HttpServletRequest request = (HttpServletRequest)message.get(AbstractHTTPDestination.HTTP_REQUEST);
request.getRemoteAddr()

在服务器上添加这段代码,它实际上可以从请求中找到IP,你可以在服务器上对IP进行比较。让我知道这是否是您要找的。

编辑:-----

嗯,我的理解是防火墙看不到 Header 中的 IP 或消息中的负载。它检查原始服务器的 IP。

如果我错了请纠正我,但我觉得如果你在添加了防火墙规则的服务器上部署你的客户端并调用服务器,没有理由它不工作。

让我知道你遇到了什么样的错误,比如堆栈跟踪或其他东西,我们可以看到发生了什么。

CXF 客户端使用 java.net.URLConnection 连接到服务。可以通过这种方式将 URLConnection 配置为 select 本地 IP 地址(参见 How can I specify the local address on a java.net.URLConnection?

URL url = new URL(yourUrlHere);
Proxy proxy = new Proxy(Proxy.Type.DIRECT, 
    new InetSocketAddress( 
        InetAddress.getByAddress(
            new byte[]{your, ip, interface, here}), yourTcpPortHere));
URLConnection conn = url.openConnection(proxy);

我检查了工件 cxf-rt-rs-clientcxf-rt-transports-http 的代码以了解 CXF 如何创建连接。在 ProxyFactory 中是创建 UrlConnection

所需的 Proxy 对象的代码
private Proxy createProxy(final HTTPClientPolicy policy) {
    return new Proxy(Proxy.Type.valueOf(policy.getProxyServerType().toString()),
                     new InetSocketAddress(policy.getProxyServer(),
                                           policy.getProxyServerPort()));
}

如您所见,无法配置 IP 地址,所以恐怕问题的答案是 您无法使用 CXF 配置源 IP 地址

但是,我认为修改源代码以允许设置源IP地址并不难

HTTPClientPolicy

将以下代码添加到 org.apache.cxf.transports.http.configuration.HTTPClientPolicy cxf-rt-transports-http

public class HTTPClientPolicy {
    protected byte[] sourceIPAddress;
    protected int port;

    public boolean isSetSourceIPAddress(){
        return (this.sourceIPAddress != null);
    }

ProxyFactory

将以下代码修改为org.apache.cxf.transport.http.ProxyFactory at cxf-rt-transports-http

 //added || policy.isSetSourceIPAddress()
 //getProxy() calls finally to createProxy
 public Proxy createProxy(HTTPClientPolicy policy, URI currentUrl) {
    if (policy != null) {
        // Maybe the user has provided some proxy information
        if (policy.isSetProxyServer() || policy.isSetSourceIPAddress())
            && !StringUtils.isEmpty(policy.getProxyServer())) {
            return getProxy(policy, currentUrl.getHost());
        } else {
            // There is a policy but no Proxy configuration,
            // fallback on the system proxy configuration
            return getSystemProxy(currentUrl.getHost());
        }
    } else {
        // Use system proxy configuration
        return getSystemProxy(currentUrl.getHost());
    }
}

//Added condition to set the source IP address (is set)
//Will work also with a proxy
private Proxy createProxy(final HTTPClientPolicy policy) {
    if (policy.isSetSourceIPAddress()){
        Proxy proxy = new Proxy(Proxy.Type.DIRECT, 
            new InetSocketAddress( 
                InetAddress.getByAddress(
                    policy.getSourceIPAddress(), policy.getPort()));
    } else {
        return new Proxy(Proxy.Type.valueOf(policy.getProxyServerType().toString()),
                     new InetSocketAddress(policy.getProxyServer(),
                                           policy.getProxyServerPort()));
    }                
}

用法

Client client = ClientProxy.getClient(service);
HTTPConduit http = (HTTPConduit) client.getConduit();
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setSourceIPAddress(new byte[]{your, ip, interface, here}));
httpClientPolicy.setPort(yourTcpPortHere);
http.setClient(httpClientPolicy);

自定义 URLStreamHandlerFactory 有效。

示例:

        ...
        URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
            @Override
            public URLStreamHandler createURLStreamHandler(String protocol) {
                if (protocol.equals("http")) {
                    return new HttpHandler();
                } else if (protocol.equals("https")) {
                    return new sun.net.www.protocol.https.Handler();
                }
                return null;
            }
        });
        ...

private class HttpHandler extends java.net.URLStreamHandler {

    protected int getDefaultPort() {
        return 80;
    }

    @Override
    protected URLConnection openConnection(URL u) throws IOException {
        return openConnection(u, (Proxy) null);
    }

    @Override
    protected URLConnection openConnection(URL u, Proxy p) throws IOException {
        return new HttpURLConnection(u, p) {

            @Override
            protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout)
                    throws IOException {
                return new HttpClient(url, (String) null, -1, true, connectTimeout) {

                    @Override
                    protected Socket createSocket() throws IOException {
                        Socket s = new Socket();

                        s.bind(new InetSocketAddress(InetAddress.getByName("1.2.3.4"),
                                0)); // yours IP here

                        return s;
                    }

                };
            }

            @Override
            protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout,
                    boolean useCache) throws IOException {
                return getNewHttpClient(url, p, connectTimeout);
            }

        };
    }
}

对于 HTTPS 也可以使用自定义 SSLSocketFactory

HttpsURLConnection.setDefaultSSLSocketFactory(...);