I have to use a WCF service in a Java client. I have generated proxy code using Axis2 library. I have successfully configured proxy classes but getting issue when calling WCF service method.
Following is the code in my java client.
ServiceXMLStub stub = new ServiceXMLStub("https://qa1-myservice.com/integration/ServiceXML.svc");
GetMetadata meta = new GetMetadata();
meta.setStateCode("WA");
meta.setUserName("tpstester1");
stub._getServiceClient().getOptions().setProperty(Constants.Configuration.MESSAGE_TYPE,HTTPConstants.MEDIA_TYPE_APPLICATION_ECHO_XML);
stub._getServiceClient().getOptions().setProperty(Constants.Configuration.DISABLE_SOAP_ACTION,Boolean.TRUE);
stub._getServiceClient().engageModule("addressing");
stub._getServiceClient().getOptions().setUserName("myuser");
stub._getServiceClient().getOptions().setPassword("myp#ssw0rd");
GetMetadataResponse response = stub.getMetadata(meta);
Following is the issue I am getting when calling this service from this client.
org.apache.axis2.AxisFault: The message could not be processed. This is most likely because the
action 'http://Integration.ContractsXML/IServiceXML/GetMetadata' is incorrect or because the message
contains an invalid or expired security context token or because there is a mismatch between
bindings.
The security context token would be invalid if the service aborted the channel due to inactivity. To
prevent the service from aborting idle sessions prematurely increase the Receive timeout on the
service endpoint's binding.
I tested this code in .Net client and it works fine there
ServiceReference1.ServiceXMLClient serviceClient = new ServiceReference1.ServiceXMLClient();
serviceClient.ClientCredentials.UserName.UserName = "myuser";
serviceClient.ClientCredentials.UserName.Password = "myp#ssw0rd";
var result = serviceClient.GetMetadata("tpstester1", "SA");
What am I missing here ?
Related
I've created a SOAP web-service client on Netbeans. The web-service is exposed on Navision with NTML authentication. During class generation, a login pop-up picks the required credentials and uses them for authentication.
The issue is once the classes are generated and I try to invoke any method;
ServicePort webservice_port = new WService().getServicePort();
webservice_port.retrieveData();
I get an exception.
java.io.IOException: Server returned HTTP response code: 401 for URL: ...
Exception in thread "main" com.sun.xml.ws.wsdl.parser.InaccessibleWSDLException: 2 counts of InaccessibleWSDLException.
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.tryWithMex(RuntimeWSDLParser.java:275)
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:246)
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:209)
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:178)
at com.sun.xml.ws.client.WSServiceDelegate.parseWSDL(WSServiceDelegate.java:363)
at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:321)
at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:230)
at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:211)
at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:207)
at com.sun.xml.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:114)
at javax.xml.ws.Service.<init>(Service.java:57)
at com.ntml.remote.MSACCO.<init>(MSACCO.java:42)
Is this an issue with NTLM authentication or is there another way to pass the credentials?
Found a working solution. Injecting an authentication mechanism to the client using the web service port.
Port webservice_port = new Wservice().getServicePort();
Client client = ClientProxy.getClient(webservice_port);
HTTPConduit conduit = (HTTPConduit) client.getConduit();
AuthorizationPolicy authorization = conduit.getAuthorization();
authorization.setUserName(username);
authorization.setPassword(password);
conduit.getClient().setAllowChunking(false);
conduit.getClient().setAutoRedirect(true);
webservice_port.callWebMethod();
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 having some issues and almost no documentation on internet about id session tokens and Java web services. We have a server (Tomcat providing web services on JAX-WS + SOAP) that is providing an API to query an SQL server.
I have to code a simple Java client that communicates with the server through this web services. The issue is that before being able to use any of its server WSDL methods, the client has to authenticate through a web server method where you send the user/pass, and the server gives back to client a session-id (alfanumeric string).
The rest of the methods do not have any kind of parameter where i can pass the session id, so i suppose it has to be used as a "context". I have found information about how in JAX-WS you can maintain session-id:
https://weblogs.java.net/blog/ramapulavarthi/archive/2006/06/maintaining_ses.html
Hello port = new HelloService().getHelloPort();
((BindingProvider)port).getRequestContext().put(BindingProvider.
SESSION_MAINTAIN_PROPERTY,true);
in my case, if i want to receive the cookie session-id, i have to:
org.tempuri.RUWebService service = new org.tempuri.RUWebService();
org.tempuri.RUWebServiceSoap myport = new org.tempuri.RUWebServiceSoap();
String session-id = myport.Auth(user,pass);
where the session-id is an UUID variable is a String of a hex variable: 8-4-4-4-8 .. that i can change to real hex like:
java.util.UUID uuidFromHyphens = java.util.UUID.fromString("6f34f25e-0b0d-4426-8ece-a8b3f27f4b63");
I tried the following code, where i change "port" variable to "myport", trying to match both examples:
((BindingProvider)myport).getRequestContext().put(BindingProvider.
SESSION_MAINTAIN_PROPERTY,true);
It compiles, but when i consult the web server through some of its methods, i receive a "null", the same as if i do not make the auth procedure. My issue i think is that i don't know what i am doing wrong with cookie session-id auth procedure.
If somebody could help me, i would be grateful.
regards.
Either you pass it as Request Parameter using GET or POST methods
(or)
Put the session id in outgoing HTTP header, like
GET / HTTP/1.0
Accept: text/plain
Accept: text/html
Session-Id:DFF55566_SOMEID
But for both of this to work, your web server must expect the Session Id from client in some format either at server level (or) your application level.
I am implementing a TV listing service and I have decided to use ROVI as my data provider.
They provide me with an API that allows me to exchange data between my application and their servers by means of SOAP requests.
Since I am programming in Java, I used wsimport to generate the classes that would enable me to interact with their server.
//Connection
service = new ListingsService();
port = service.getListingsServiceSoap();
I have come across a problem which Google doesn't seem to have the answer for.
According to their API, whenever I want to make a call to a SOAP service I have to add my API Key to the end of url.
The problem is, I don't know how to do that. Using the stubs generated by wsimport, I can create a request object as it should be; however the URL is not displayed as per their specification. The url I currently get is: http://api.rovicorp.com/v9/listingsservice.asmx and what is required is: http://api.rovicorp.com/v9/listingsservice.asmx?apikey=myAPIkey. I obtained that by printing the following code:
System.out.println(port.toString());
Trying to run the following code:
GetServicesRS servicesRS = port.getServices(getServicesRQ, auth)
Yields the following error:
Exception in thread "main" com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 403: Forbidden
What java method can I use to append this parameter into the SOAP request URL.
Thanks for your help.
Edit.
I am still struggling with this and haven't been lucky with responses, if anyone could point me in the direction of a framework or something that could facilitate this would be great!
Cheers
I manage to work around my problem using something called BindingProvider.
I added the following to my code:
//Connection
service = new ListingsService();
port = service.getListingsServiceSoap();
BindingProvider bindingProvider = (BindingProvider) port;
bindingProvider.getRequestContext()
.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://api.rovicorp.com/v9/listingsservice.asmx?apikey=" + APIKey);
With the aforementioned code the call to the API is successful:
GetServicesRS servicesRS = port.getServices(getServicesRQ, auth)
Hope it helps someone in the future.
I use Netbeans to generate web service client code, client-style JAX-WS, so i can invoke a web service API.
However, when I invoke the web service API, I get the exception:
com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 307: Temporary Redirect
Why do I get this? What is the workaround? I know the problem isn't with the web service itself, because I can get responses fine via soapUI and .Net.
Faced the same problem about a month ago.
Web service client classes were generated using Apache CXF and web service returned HTTP
status 307, which led to the same exception.
Invocation of the same web service method using soapUI with property Follow Redirects set to true was successful and returned needed data.
After googling awhile, it looked like there is no property to enable following redirects in the JAX-WS for this.
So, below is the code which is currently working, though I'm not sure it is compliant with any standards:
Supposing generated client classes looks like:
// generated service class
public class MyWebServiceClient extends javax.xml.ws.Service {
// ...
private final QName portName = "...";
// ...
public RetrieveMyObjects getRetrieveMyObjects() {
return super.getPort(portName, RetrieveMyObject.class);
}
// ...
}
// generated port interface
// annotations here
public interface RetrieveMyObjects {
// annotations here
List<MyObject> getAll();
}
Now, upon executing following code:
MyWebServiceClient wsClient = new MyWebServiceClient("wsdl/location/url/here.wsdl");
RetrieveMyObjectsPort retrieveMyObjectsPort = wsClient.getRetrieveMyObjects();
wsClient should return instance which is both instance of RetrieveMyObjects & javax.xml.ws.BindingProvider interfaces. It is not stated anywhere on the surface of JAX-WS, but it seems that a lot of code is based on that fact. One can re-assure him\herself by executing something like:
if(!(retrieveMyObjectsPort instanceof javax.xml.ws.BindingProvider)) {
throw new RuntimeException("retrieveMyObjectsPort is not instance of " + BindingProvider.class + ". Redirect following as well as authentication is not possible");
}
Now, when we are sure that retrieveMyObjectsPort is instance of javax.xml.ws.BindingProvider we can send plain HTTP POST request to it, simulating SOAP request (though it looks incredibly incorrect & ugly, but this works in my case and I didn't find anything better while googling) and check whether web service will send redirect status as a response:
// defined somewhere before
private static void checkRedirect(final Logger logger, final BindingProvider bindingProvider) {
try {
final URL url = new URL((String) bindingProvider.getRequestContext().get(ENDPOINT_ADDRESS_PROPERTY));
logger.trace("Checking WS redirect: sending plain POST request to {}", url);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setInstanceFollowRedirects(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/html; charset='UTF-8'");
connection.setDoOutput(true);
if(connection.getResponseCode() == 307) {
final String redirectToUrl = connection.getHeaderField("location");
logger.trace("Checking WS redirect: setting new endpoint url, plain POST request was redirected with status {} to {}", connection.getResponseCode(), redirectToUrl);
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, redirectToUrl);
}
} catch(final Exception e) {
logger.warn("Checking WS redirect: failed", e);
}
}
// somewhere at the application start
checkRedirect(logger, (BindingProvider) retrieveMyObjectsPort);
Now, what this method does is: it takes BindingProvider.ENDPOINT_ACCESS_PROPERTY of retrieveMyObjectsPort i.e. the url to which this port method will be sending SOAP requests and sends plain HTTP POST request as described above. Then it checks whether response status is 307 - Temporary Redirect (other statuses like 302 or 301 may also be included) and if it is, gets the URL to which web service is redirecting and sets new endpoint for the specified port.
In my case this checkRedirect method is called once for each web service port interface and then everything seems to work fine:
Redirect is checked on url like http://example.com:50678/restOfUrl
Web service redirects to url like https://example.com:43578/restOfUrl (please note that web service client authentication is present) - endpoint of a port is set to that url
Next web service requests executed via that port are successful
Disclaimer: I'm quite new to webservices and this is what I managed to achieve due to the lack of solutions for this questions, so please correct me if something is wrong here.
Hope this helps
Yes I know this post is old, but I've had similar errors, and thought maybe somebody would benefit from my solution.
the one that plagued me the most was:
com.sun.xml.ws.client.ClientTransportException: The server sent HTTP status code 200: OK
Which turns out to mean an incomplete response header. Apparently jax-ws does some kind of validation that includes validating the HTTP headers as well. And the server I was using was just sending an empty header.
It worked like a charm after adding 'application/soap+xml' to the Content-Type header.