Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding CXF Client source IP address

I have a CXF client that connects to a Web Service. This client is installed in a machine tha has two IP addresses in the same network (for example 172.16.1.101 and 172.16.1.102).

How can I configure the CXF client to use a specific source IP address, so that the server sees the requests coming from that specific IP address and not the other?

If I had access to the Socket, I would do something like:

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

Is it possible to configure the Sockets created by CXF so I can specify the source IP address?

EDIT: I need to specify the source IP address because between the client and the web server there is a firewall that has rules for one of the IP addresses (connections coming from the other IP address are blocked).

like image 947
user2518618 Avatar asked Jul 31 '16 23:07

user2518618


People also ask

What is CXF endpoint?

In Apache Camel, the Camel CXF component is the key to integrating routes with Web services. You can use the Camel CXF component to create a CXF endpoint, which can be used in either of the following ways: Consumer — (at the start of a route) represents a Web service instance, which integrates with the route.

What is Cxf used for?

Overview. Apache CXF™ is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.

What is the use of HTTP conduit?

http-conf:conduit ElementSpecifies the HTTP connection properties such as timeouts, keep-alive requests, content types, etc. Specifies the the parameters for configuring the basic authentication method that the endpoint uses preemptively.

How do I run Apache CXF?

You will have to make sure that you create an appropriate directory structure for your project and add the earlier shown hello. wsdl file to the specified folder. The wsdl2java plugin will compile this wsdl and create Apache CXF classes in a pre-defined folder.

What is HTTP binding in CXF?

CXF includes an "HTTP binding" which makes it easy to build REST style services. The HTTP binding allows you to take any operation and map it to arbitrary URIs and HTTP verbs (i.e. GET, PUT, POST, DELETE).

How to configure CXF simple front end server endpoint in spring?

You can configure the CXF simple front end server endpoint by using the <simple:server> tag in spring. http: The simple:server element supports many additional attributes: The endpoint name this service is implementing, it maps to the wsdl:port@name. In the format of "ns:ENDPOINT_NAME" where ns is a namespace prefix valid at this scope.

What happened to the resource binding in CXF?

This binding has been deprecated and is likely to be removed from CXF in one of its future releases. If you have a simple CRUD based Java class, CXF can try to build up a set of resources automatically for you with no annotations or configuration.

What is bindingid in jaxwsserverfactory?

The JaxWsServerFactory bean creates a Server inside CXF which starts listening for requests on the URL specified. The bindingId specifies how your service operations get mapped to resources: in this case the http binding is used. We're telling the ServiceFactory to work in "wrapped" mode.


2 Answers

CXF client uses java.net.URLConnection to connect to a service. The URLConnection can be configured to select a local IP address in this way (see 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);

I have inspected the code of artifacts cxf-rt-rs-client and cxf-rt-transports-http to see how CXF is creating the connection. In ProxyFactory is the code to create the Proxy object needed for the UrlConnection

private Proxy createProxy(final HTTPClientPolicy policy) {
    return new Proxy(Proxy.Type.valueOf(policy.getProxyServerType().toString()),
                     new InetSocketAddress(policy.getProxyServer(),
                                           policy.getProxyServerPort()));
}

As you can see, there is no way to configure the IP address, so i am afraid that the answer to the question is you can not configure source IP address with CXF

But, I think it would not be difficult to modify the source code to allow setting the source IP address

HTTPClientPolicy

Add the following code to org.apache.cxf.transports.http.configuration.HTTPClientPolicy at cxf-rt-transports-http

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

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

ProxyFactory

Modify the following code to 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()));
    }                
}

Usage

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);
like image 133
pedrofb Avatar answered Oct 01 '22 15:10

pedrofb


A custom URLStreamHandlerFactory works.

Example:

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

        };
    }
}

For HTTPS also usable a custom SSLSocketFactory

HttpsURLConnection.setDefaultSSLSocketFactory(...);
like image 33
heli Avatar answered Oct 01 '22 15:10

heli