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).
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.
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.
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.
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.
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).
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.
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.
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.
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);
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(...);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With