I'm Using CXF 3.1.5, I'm trying to make it work with proxy. if there is no username and password for the proxy, then it works; if there is an username and password for the proxy, then it doesn't work. here is my code:
//to create my own http conduit
bus.setExtension(new TLSAndProxySupportedHTTPConduitFactory(settings, HTTPConduitFactory.class);
//to get wsdl definition
Definition definition = bus.getExtension(WSDLManager.class).getDefinition(uri);
TLSAndProxySupportedHTTPConduitFactory implements HTTPConduitFactory, and will create a TLSAndProxySupportedHTTPConduit which extends URLConnectionHTTPConduit, in TLSAndProxySupportedHTTPConduit, here is the related code for proxy settings:
//HTTPClientPolicy settings works
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setProxyServer(proxy.getHostName());
httpClientPolicy.setProxyServerPort(proxy.getPort());
this.setClient(httpClientPolicy);
if (proxy.getUserName() != null) {
//ProxyAuthorizationPolicy settings doesn't work
this.getProxyAuthorization().setUserName(proxy.getUserName());
this.getProxyAuthorization().setPassword(proxy.getPassword());
}
Please do remember if the proxy has no username and password, everything works just fine.and if the target URL for loading WSDL definition is started with https(https is required for me), the proxy doesn't work. if it's started with http, then the proxy with username and password works well.
Find a solution:
The Reason is
The Java Secure Socket Extension (JSSE) library from Sun Microsystems lets you access a secure Web server from behind a firewall via proxy tunneling. To do this, the JSSE application needs to set the https.ProxyHost and https.ProxyPort system properties. The tunneling code in JSSE checks for "HTTP 1.0" in the proxy's response. If your proxy, like many, returns "HTTP 1.1", you will get an IOException. In this case, you need to implement your own HTTPS tunneling protocol.
Referance:http://www.javaworld.com/article/2077475/core-java/java-tip-111--implement-https-tunneling-with-jsse.html
and https://community.oracle.com/thread/1534538
Then you could overwrite method setupConnection of URLConnectionHTTPConduit.
#Override
protected void setupConnection(Message message, Address address, HTTPClientPolicy csPolicy) throws IOException {
super.setupConnection(message, address, csPolicy);
HttpURLConnection connection = (HttpURLConnection) message.get(KEY_HTTP_CONNECTION);
decorateHttpsURLConnection((HttpsURLConnection) connection);\
message.put(KEY_HTTP_CONNECTION, connection);
}
in the method decorateHttpsURLConnection:
httpsConnection.setSSLSocketFactory(new SSLTunnelSocketFactory(getProxy(), sslContext.getSocketFactory()));
Related
I am trying to find the client's IP. And I was told that 'request.getHeader("HTTP_X_FORWARDED_FOR")' cannot be trusted since it may be forged and I should use request.getRemoteAddr instead.(In my case it's ok to just get the proxy's IP)
So my question is:
why ServletRequest.getRemoteAddr cannot be forged?
another question:
what's the difference between HTTP_X_FORWARDED_FOR and X_FORWARDED_FOR?
If you do request.getRemoteAddr();
and if the user is behind a proxy server or accessing your web server through a load balancer then the above code will get the IP address of the proxy server or load balancer server, not the original IP address of a client.
So if
In my case it's ok to just get the proxy's IP
you are ok with this then request.getRemoteAddr(); is enough.
But in Ideal case you should try this
//is client behind something?
String ipAddress = request.getHeader("X-FORWARDED-FOR");
if (ipAddress == null) {
ipAddress = request.getRemoteAddr();
}
X_FORWARDED_FOR
The X-Forwarded-For (XFF) HTTP header field is a de facto standard for identifying the originating IP address of a client connecting to a web server through an HTTP proxy or load balancer.
HTTP_X_FORWARDED_FOR
A header HTTP_X_FORWARDED_FOR is set by proxy servers to identify the ip-address of the host that is making the HTTP request through the proxy.
In short they're all the same header, just referred to differently by various implementations. For more view this : HTTP Headers: What is the difference between X-FORWARDED-FOR, X_FORWARDED_FOR and HTTP_X_FORWARDED_FOR?
I created the jar from the WSDL for my client using the wsdl2java command. Now, I need to know how I can authenticate my client in order to complete an operation?
I am using CXF 2.7.16. I created my service using the generated class MyApp_Service, I am struggling with this. Isn't there a simple way to tell my client the credentials it should use to gain access to the web service?
I read about the Spring configuration, however I am unable to figure out if it applies to my case and how if yes. I tried to cast the MyApp_Service class to BindingProvider in order to use the method which consist to put the USERNAME and PASSWORD properties in the context with a value. However, MyApp_Service cannot be cast to BindingProvider.
This is my first web service client application ever. So, any help will be welcomed.
Update 2015-05-28: I tried to define the AuthenticationPolicy but is seems not working. Here is the code:
Client client = JaxWsDynamicClientFactory.newInstance().createClient(wsdlUrl);
ClientImpl clt = (ClientImpl) client;
HTTPConduit cc = (HTTPConduit) clt.getConduit();
org.apache.cxf.configuration.security.ObjectFactory secOF = new org.apache.cxf.configuration.security.ObjectFactory();
AuthorizationPolicy ap = secOF.createAuthorizationPolicy();
ap.setUserName(usagerWS);
ap.setPassword(mdpWS);
ap.setAuthorizationType("Basic");
cc.setAuthorization(ap);
Sniffing with WireShark, the Authorization header is clearly missing in the HTTP request.
What is missing?
Problem solved, here is the solution:
MyApp_Service service = new MyApp_Service(wsdlUrl, new QName(namespace, serviceName));
MyApp port = service.getMyApp();
// Set credentials
Map<String, Object> reqCtxt = ((javax.xml.ws.BindingProvider) port).getRequestContext();
reqCtxt.put(javax.xml.ws.BindingProvider.USERNAME_PROPERTY, username);
reqCtxt.put(javax.xml.ws.BindingProvider.PASSWORD_PROPERTY, password);
No more usage of the dynamic client. Only the classes generated with wsdl2java are used.
I am developing a SSL/TLS enabled server using the Java SimpleFramework. I am wondering how to validate client authentications on the server.
On the server side, I am extending org.simpleframework.http.core.ContainerServer and overriding the process() method as follows:
#Override
public void process(Socket socket) throws IOException {
// Ensures client authentication is required
socket.getEngine().setNeedClientAuth(true);
super.process(socket);
}
This is to make sure that clients authenticate. Note that if I remove the call to setNeedClientAuth(), my program works perfectly.
On the client side, the following code is used:
HttpClient client = new HttpClient();
Credentials defaultcreds = new UsernamePasswordCredentials("username", "password");
client.getState().setCredentials(AuthScope.ANY, defaultcreds);
GetMethod get = new GetMethod("https://url.to.server");
get.setDoAuthentication(true);
client.executeMethod(get);
When enabling authentication requirement, I get the following exception:
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
I am guessing this relates to the fact that the passed credentials is never validated.
To summarize my question, how should I proceed to validate clients on the server?
I am trying to send a SOAP request over SSL with my own little Java client and it fails with "java.net.ConnectException: Connection refused". The same request sent with SOAPUI does not fail, I get a valid response from the server.
This is the code I am trying to run:
public static void main(String[] args) throws MalformedURLException {
System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");
SSLUtilities.trustAllHttpsCertificates();
URL wsdlURL = new URL(MY_WSDL_LOCATION);
QName serviceName = new QName(MY_QNAME, NAME_OF_SERVICE);
Service service = Service.create(wsdlURL, serviceName);
Order myOrder = service.getPort(Order.class);
BindingProvider portBP = (BindingProvider) myOrder;
String urlUsed = (String) portBP.getRequestContext().
get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
System.out.println("Using URL: " + urlUsed);
((BindingProvider)myOrder).getRequestContext().put(
BindingProvider.USERNAME_PROPERTY, CORRECT_USERNAME);
((BindingProvider)myOrder).getRequestContext().put(
BindingProvider.PASSWORD_PROPERTY, CORRECT_PASSWORD);
AliveRequest aliveRequest = new AliveRequest();
MerchantInfo merchInfo = new MerchantInfo();
merchInfo.setMerchantId(CORRECT_MERCHANT_ID);
aliveRequest.setMerchantInfo(merchInfo);
AliveResponse aliveResponse = myOrder.alive(aliveRequest);
}
It fails with "java.net.ConnectException: Connection refused" exception. When I build a request from the same WSDL using SOAPUI, populate the same fields with same values and enter the same basic authentication credentials, a valid response is returned.
The problem was the fact that my Java client didn't send the request through the proxy, so my own company's firewall was blocking it. Unlike my own Java client, SOAPUI actually detects the proxy settings of the system (probably reads system environment variables) when SOAPUI's proxy settings are set "auto" (default). The solution was to set the following system properties:
-Dhttps.proxySet=true
-Dhttps.proxyHost=MY_PROXY_HOST
-Dhttps.proxyPort=MY_PROXY_PORT
System.setProperty("http.proxySet", "true");
System.setProperty("java.net.useSystemProxies", "true");
System.setProperty("http.proxyHost", "192.168.1.103");
System.setProperty("http.proxyPort", "3128");
System.setProperty("http.proxyUser", "user123");
System.setProperty("http.proxyPassword", "passwD123");
url = new URL("http://www.google.co.in");
every time when I am using this code IOException throws which say HTTP response code 407.
HTTP 407 means proxy authentication required. why this problem is coming while I set proxyUser and proxyPassword.
http 401 will occur if I put wrong password but it always give me 407, means my code does not take username and password. In above code user123 is username and passwD123 is password for proxy authentication.
http://blog.vinodsingh.com/2008/05/proxy-authentication-in-java.html
I found the solution thanks Mr. Vinod Singh.
Proxy authentication in Java
The usual corporate networks provide internet access via proxy servers and at times they require authentication as well. May applications do open the connections to servers which are external to the corporate intranet. So one has to do proxy authentication programmatically. Fortunately Java provides a transparent mechanism to do proxy authentications.
Create a simple class like below-
import java.net.Authenticator;
class ProxyAuthenticator extends Authenticator {
private String user, password;
public ProxyAuthenticator(String user, String password) {
this.user = user;
this.password = password;
}
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password.toCharArray());
}
}
and put these lines of code before your code opens an URLConnection-
Authenticator.setDefault(new ProxyAuthenticator("user", "password"));
System.setProperty("http.proxyHost", "proxy host");
System.setProperty("http.proxyPort", "port");
Now all calls will successfully pass through the proxy authentication.
The answer to use an Authenticator is correct for the general case. However, another cause of HTTP 407 in Java 8u111 and later is if you are using BASIC authentication against the proxy.
In this case, add this system property:
-Djdk.http.auth.tunneling.disabledSchemes=
I found this out from: https://confluence.atlassian.com/kb/basic-authentication-fails-for-outgoing-proxy-in-java-8u111-909643110.html
#GauravDS
You mentioned:
http://blog.vinodsingh.com/2008/05/proxy-authentication-in-java.html
I found the solution thanks Mr. Vinod Singh.
Proxy authentication in Java
The usual corporate networks provide internet access via proxy servers and at times they require authentication as well. May applications do open the connections to servers which are external to the corporate intranet. So one has to do proxy authentication programmatically. Fortunately Java provides a transparent mechanism to do proxy authentications.
Create a simple class like below-
.
.
.
and put these lines of code before your code opens an URLConnection-
Authenticator.setDefault(new ProxyAuthenticator("user", "password"));
System.setProperty("http.proxyHost", "proxy host");
System.setProperty("http.proxyPort", "port");
Now all calls will successfully pass through the proxy authentication.
What if the site you are connecting to also requires a username/password to allow you.
Setting a Default Authenticator(Authenticator.setDefault) will fail I guess when the external site will look for authenticated user.
Any views?....Someone ?
Edit:1
Used this code earlier and was getting the error (407) Proxy Authentication Required.
I believe that was because the authentication was requested by different hosts. and when you set a default authenticator with one user/pass for one host, then the authentication will fail for other requesting host. I made the following change yesterday to SimpleAuthenticator class and now it works like a charm.
protected PasswordAuthentication getPasswordAuthentication()
{
String requestingHost = getRequestingHost();
if (requestingHost == proxyHost){
System.out.println("getPasswordAuthentication() request recieved from->" + requestingHost );
return new PasswordAuthentication(proxyuser,proxypass.toCharArray());
}
else{
System.out.println("getPasswordAuthentication() request recieved from->" + requestingHost );
return new PasswordAuthentication(sharepointusername,sharepointpassword.toCharArray());
}
}
More info here: http://blog.ashwani.co.in/blog/2013-07-29/access-sharepoint-webservices-from-java-behind-proxy/