Consuming WCF Service with Digest authentication from Java - java

I want to create a client in Java that connects to a web service which requires Digest authentication. Since I am not familiar with java and java stack, I've made a research and came across jax-ws, axis2, xcf, and metro. I have learned JAX-WS is an API and there is a reference implementation in the JDK but it lacks the digest authorization support.
My first attempt was to use axis2 since there is a built-in support for it in the Eclipse IDE. The following code seems to follow digest authentication workflow but somehow it still fails the authorization in the end.
Service1Stub stub = new Service1Stub();
HttpTransportProperties.Authenticator authenticator = new Authenticator();
List<String> authSchemes = new ArrayList<String>();
authSchemes.add(Authenticator.DIGEST);
authenticator.setAuthSchemes(authSchemes);
authenticator.setUsername("doman user");
authenticator.setPassword("domain password");
authenticator.setPreemptiveAuthentication(true);
Options options = stub._getServiceClient().getOptions();
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, authenticator);
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED, org.apache.axis2.Constants.VALUE_FALSE);
GetData getData = new GetData();
getData.setValue(25);
GetDataResponse data = stub.getData(getData);
System.out.println(data.getGetDataResult());
My second attempt was to use metro framework but I get some errors related to JAXB versions.
java.lang.LinkageError: JAXB 2.1 API is being loaded from the bootstrap classloader, but this RI needs 2.2 API.
I have to use JDK 1.6.0_03 so I guess this is happening because of a JDK version mismatch, but I also don't want to use the suggested "endorsed directory mechanism" because it might cause lots of troubles during deployment.
I am totally lost and I am looking for the simplest, quickest and up-to-date way of consuming a web service that requires Digest authentication in Java? Preferably with as little as dependencies possible.

Java classloading is a mess, sorry. The root cause is that there are no strong names like there are in the .NET world, and therefore the runtime linker takes whatever match comes first on the classpath, regardless of whether that's the library version that the code was compiled against. The OSGi system solves this problem, but it never gained mainstream adoption.
The error message you cited:
java.lang.LinkageError: JAXB 2.1 API is being loaded from the bootstrap classloader, but this RI needs 2.2 API.
is uncharacteristically useful and specific, most of the time what happens instead is that you're left staring at a NoSuchMethodError or something of the sort. Over time, you learn to recognise these as library version mismatches. In this case, the library author(s) have written code to recognize a common error case and print a better error message (bless 'em).
Rant over, here's some info that I hope will set you on the right track:
Java classloaders are hierarchical and resolution is bottom-up
but there's a blessed class loader at the root of the hierarchy that's responsible for loading the core runtime library
vendor shenanigans have led to a lot of stuff getting included in the core runtime library that really shouldn't have been in there, as it's a shortcut to becoming dominant in an otherwise Darwinistic selection process. JAXB is one of these things, as you've just found out. JAXB2 is actually pretty decent, but it evolves independent of the core runtime and, well, here we are.
the JDK and JRE installation has a folder called lib\endorsed where you can add JAR files that need to be loaded by the root loader, bypassing even what's in rt.jar.
In summary, if you manually add the 2.2 version of the JAXB library to %JAVA_HOME%\lib\endorsed, then it should override the included 2.1 version and your web service client will deploy. This will have to happen on every system that will run the web service client, until the JDK is updated to a 7.x version that does included JAXB 2.2. If the same JVM is running other JAXB based applications, these may or may not break as a result.
Yes, this is painful. A tangent that you could investigate is to deliberately use an older version of Metro that's built for JAXB 2.1. So long as you're bound to deploying on 1.6.0_03, this may well be the better option, despite losing some of the recent improvements in Metro.
Updated: here's a blog post on this topic. It contains some links to further information.

Metro framework was way too complicated to configure and documents that I have found were incomplete. So I've done it with using Apache Axis2.
Steps to follow:
Download and extract Apache Axis2 binaries.
Reference to all jar files
Go to /bin folder and use wsdl2java to generate client code.
wsdl2java -S src -uri "wsdl_file_location"
Copy everything under the src folder to your java application and connect to the service as follows:
//Fictious is the name of the web service
FictiousStub stub = new FictiousStub("servicelocation/fictiousService.php");
HttpTransportProperties.Authenticator authenticator = new Authenticator();
List<String> authSchemes = new ArrayList<String>();
authSchemes.add(Authenticator.DIGEST);
authenticator.setAuthSchemes(authSchemes);
authenticator.setUsername("admin");
authenticator.setPassword("12345");
authenticator.setPreemptiveAuthentication(true);
Options options = stub._getServiceClient().getOptions();
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, authenticator);
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED, org.apache.axis2.Constants.VALUE_FALSE);

Related

How to handle version conflicts with my Java application using SPI extensions

I am writing a plugin API for a Java application, the idea being that eventually third parties will provide their own plugin extensions for the application and all the user needs to do is place the plugin jar into a plugins directory of the application. For the impatient, my question in short is how to handle possible version conflicts when the plugin relates to a different API than that on the system, see below for details of my situation and what I have thought about.
I have read a number of articles using service provider interfaces and have something working with that. The problem comes when considering how to deal with differing version combinations.
I am aware of the technique of when adding to an API adding extension interfaces, rather than changing the existing interface (eg. API 1.0 having MyInterface, API 1.1 adding MyInterface2 with the new methods, etc). With this technique if the user has the latest API then older plugins should work fine, but what happens if the user has an old API and newer plugins?
So as an example the user has API 1.0 only with MyInterface but installs binary plugin compiled against API 1.1 where the provider class implements MyInterface2. Whilst the application may only ever call plugins using MyInterface, what happens if the plugin internally calls MyInterface2? Will this cause an error or exception and when (IE. when the class is loaded or when the method from MyInterface2 is called). Also is this standard across JVMs or may it differ depending on the JVM used?
Finally, would it be better to use a plugin framework, would that be able to check version requirements? Searching the internet I find PF4J on github. A quick look in the source code seems to show it may support some sort of version checks.

ClassCastException while sending soap request

I am working on a project which already had metro based web-service client implemented. Now, I needed to add another client for different service. I implemented new client, but now it throws exception when there are headers ( Headers are required). If I remove all metro jars, this new client works fine , but obviously my metro client fails. I need guidance on possible options,workarounds or resolutions.
Caused by: javax.xml.ws.WebServiceException: java.lang.ClassCastException: com.sun.xml.ws.message.saaj.SAAJHeader cannot be cast to com.sun.xml.ws.security.opt.impl.outgoing.SecurityHeader
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processRequest(SecurityClientTube.java:250)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:961)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:910)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:873)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:775)
at com.sun.xml.ws.client.Stub.process(Stub.java:429)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:168)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:102)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:151)
at com.sun.proxy.$Proxy70.methodName(Unknown Source)
... 15 more
Caused by: java.lang.ClassCastException: com.sun.xml.ws.message.saaj.SAAJHeader cannot be cast to com.sun.xml.ws.security.opt.impl.outgoing.SecurityHeader
at com.sun.xml.ws.security.opt.impl.JAXBFilterProcessingContext.setJAXWSMessage(JAXBFilterProcessingContext.java:166)
at com.sun.xml.wss.jaxws.impl.SecurityTubeBase.secureOutboundMessage(SecurityTubeBase.java:381)
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processClientRequestPacket(SecurityClientTube.java:323)
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processRequest(SecurityClientTube.java:247)
I found few questions with similar problem like here, but they all end up suggesting to remove headers which is not an option for me.
P.S : For the existing webservice client that uses metro jars, we use a connector like client( its a jar that actually includes all metro related classes within itself) provided by the server parties to connect to their server (which I think is very weird). If I move anything from the connector , it voids the support agreement. So I prefer not to remove metro jars, but find alternate way to accommodate with it.
It seems fairly clear that what's happening is there are clashing versions of the metro library in the third party jar, vs the new metro libraries you are trying to use.
My first thought is, do you have any control over the ordering of the classpath? Could you put your own metro jars to either end of the classpath to see if that makes a difference?
Then perhaps it might be best to try and implement your own interface in terms of the metro libraries included in the third party library? I'm not sure if this kind of version information is available to you, but most modern IDE should be able to decompile the classes in the third party jar for you. If I were in your situation it would be the first thing I would try since it has the "least moving parts" and uses dependencies that are already available to you.
The other option is to run one or other client in a separate VM, and access through a basic RMI interface. Not ideal I know.
You might also try investigating the Maven shade plugin which supports repackaging of libraries so that they don't clash with other versions, though I'm not sure how well that works with precompiled binaries - in particular the kind of complexity that is involved in JAX-WS packages ...

WildFly RestEasy Version confusion

I want to build a REST API using RestEasy. The generated file should be deployed in a WildFly application server.
I face the issue described in the following SO-question:
AsynchronousDispatcher error
The marked solution tells me, to set the dependency to "provided". Which as far as I understand means, that the library is not included in my war file but taken directly from the app-server...
Isn't that just wrong?
My idea would be to build a self-containing war file which contains all the needed libraries in the version I need.
When provided from the app-server I do get the currently available version from there. I have not really a clue about the version... when someone has the idea to update the RestEasy library on the server, it might break my app.
I'm not sure whether I missed something or did something completely wrong?
One of the big advantages to Java EE is developing towards the API and not having to worry about the implementation. Java EE containers provide the API's and implementations for the API's. If you include implementation dependencies one of two things is likely to happen.
You're dependencies will be ignored making it pointless to include them in your deployment.
You'll get conflicts between the dependencies you included vs what the server is expecting. This could be things like:
ClassCastException because it's finding two of the same class on the class path.
MethodNotFoundException because there is a version mismatch
Various other issues with conflcts
Developing towards the API instead of the implementation also allows you to easily switch between Java EE compliant containers with no to minimal changes to your deployment. The API's are generally backwards compatible as well making version upgrades not as big of an issue.
If you want to use a fat WAR (including implementations) instead of a skinny WAR (not including the implementations) then a servlet container is probably a better solution. WildFly does have a servlet only download. I'd encourage you though to trust container to do the right thing with the implementation dependencies :). Usually the only time there is an issue with upgrading is if you're upgrading Java EE versions. Even then it's usually pretty safe.

Can I use a new version of HttpClient in my Android project?

I need to work with HttpClient 4.2.5 in an Android project (added to the classpath). The problem is that at execution time, Android takes the default HttpClient registered in its APIs. This doesn't have all classes and methods, so I have errors like:
java.lang.NoSuchMethodError: org.apache.http.impl.client.DefaultHttpClient.setRedirectStrategy
How can I fix this issue and get execution with the version in the classpath and ignore the embedded version? I tried to change order of classpath libraries - that didn't work.
You can use HttpClientAndroidLib. As for now it is based on HttpClient 4.2.3, but I think it's quite sufficient for your needs. The author of this lib bypasses restrictions by renaming all the packages of the original HttpClient.
It sounds like Android is getting HttpClient via its bootclasspath. If that is the case, then the order of the JARs on the classpath is not relevant.
If this was "real Java(tm)", you would solve this by using an alternative bootclasspath when starting the JVM, but I don't think you can so this in an Android app1.
The best I can suggest is that you snarf the sources for HttpClient and its dependencies, tweak the package names throughout, and build new JARs. Then modify your app code to use the new classes by importing with the tweaked package names.
1 - If they allowed an app to specify an alternative bootclasspath, it would provide a new potential attack vector for malicious apps. I know that Android is supposed to implement security outside of the Davlik VM, but it is still a bad idea to remove a second line of defence implemented in the VM.

WSDL Requests with Metro/JAX-WS/WSIT During Runtime

During runtime, JAX-WS fetches the WSDL of a SOAP endpoint even though it already ran wsimport in the IDE. This behavior is illustrated here: http://jax-ws.java.net/faq/index.html#wsdl_at_runtime
Is there a limit to amount of metadata that a client can retrieve during runtime? If so, is there a way to increase this limit?
Please note that I am not referring to running wsimport inside the IDE; that works fine. I'm specifically talking about fetching the WSDL metadata during runtime.
After many long hours spent on this problem, we came up with a solution. I was working in a Glassfish environment with Metro in Netbeans. If we copied the WEB-INF to the source packages folder everything worked. The java runtime could now bind to the relative path in the jaxws-catalog.xml file. Without copying that folder, it wouldn't work.
Metro/JAX-WS-ri needs the WSDL at runtime, period.
See http://jax-ws.java.net/faq/index.html#wsdl_at_runtime for an explanation.
To prevent WSDL fetch at runtime you should package it as a resource and provide it when instanciating the proxy factory :
new XYZ_Service( XYZ_Service.class.getResource( "/path/to/your/XYZ.wsdl" ), new QName( "NameSpace", "ServiceName" ) );
Based on the fact that you refer to the Metro FAQ, you obviously have read about the reasons as to why a copy of the WSDL is still needed at runtime. To reiterate the FAQ, the reason is to be able to support WS-* extensions that have no corresponding Java annotations.
There is currently no possibility in Metro to disable support for extensions and as a consequence no way to bypass the need for a WSDL at runtime.

Categories