绑定CXF客户端源IP地址

时间:2016-07-31 23:39:27

标签: java web-services sockets cxf

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

如何配置CXF客户端使用特定的源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地址的连接被阻止)。

3 个答案:

答案 0 :(得分:5)

CXF客户端使用java.net.URLConnection连接到服务。可以将URLConnection配置为以这种方式选择本地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中是用于创建Proxy所需的UrlConnection对象的代码

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

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);

答案 1 :(得分:1)

自定义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(...);

答案 2 :(得分:0)

不确定我是否正确理解了您的问题,但我认为您不需要在客户端专门设置IP地址以便服务器阅读“

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

在服务器上添加此代码,它实际上可以从请求中找到IP,您可以在服务器上为IP进行比较。如果您正在寻找,请告诉我。

编辑:-----

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

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

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