I'm in the process of creating a Java web services client from a wsdl. I used Eclipses's Dynamic Web Project and new Web Services Client to generate the code with wsdl2java with Apache Axis 1.4. I need to add SOAP authentication to this code in order for it to work with the service. I couldn't find a place to do that in the generated code. After copious research I found this, which I've used as the backbone for my code so far.
Adding ws-security to wsdl2java generated classes
Before I was getting a "Error occurred while processing security for the message" or something along those lines. Now I am getting
"Exception: Did not understand "MustUnderstand" header(s):{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security Message: null"
I've tried many things to get past this exception. This is the code I've arrived at now.
javax.xml.namespace.QName headerName = new javax.xml.namespace.QName(
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security");
org.apache.axis.message.SOAPHeaderElement header = new org.apache.axis.message.SOAPHeaderElement(headerName);
header.setActor(null);
header.setMustUnderstand(true);
// Add the UsernameToken element to the WS-Security header
javax.xml.soap.SOAPElement utElem = header.addChildElement("UsernameToken");
utElem.setAttribute("Id", "uuid-3453f017-d595-4a5b-bc16-da53e5831cd1-1");
javax.xml.soap.SOAPElement userNameElem = utElem.addChildElement("Username");
userNameElem.setValue("username");
javax.xml.soap.SOAPElement passwordElem = utElem.addChildElement("Password");
passwordElem.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
passwordElem.setValue("password");
header.setProcessed(true);
// Finally, attach the header to the binding.
setHeader(header)
This code is located in my Binding_ServiceStub class (in its' createCall method).
We have created clients in both C# and VB with this wsdl, and there it's as easy as just changing the ClientCredentials variable which is an extension of the proxy class generated. I was hoping for something similar here.
Here's the security policy from the wsdl code as well.
<wsp:Policy><sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:WssUsernameToken10/></wsp:Policy></sp:UsernameToken></wsp:Policy>
Does anyone know what else I can do here? Why this exception is happening? I've tried many different combinations of prefixes and setProcesses and setMustUnderstand values all in vain (and based on my research of this exception).
And if anyone knows a way in which to add Soap header authentication to wsdl2java code I would take that too. Just need this to work and you would think something like this would be a little more straightforward or at least have more examples out there.
Update-
Confirmed that the same header passed using SOAPUI works fine. Must be something with the framework? I created a custom handler to process the SOAP Message but that didn't help. Is Axis 1.4 and JAX-RPC the problem? (I know they're outdated but still...)
Cool. I decided to just use Apache CXF as my framework and using this it's as easy as adding
javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider) port;
bp.getRequestContext().put("ws-security.username", username);
bp.getRequestContext().put("ws-security.password", password);
Wow that's much better. Don't use Axis 1.4 lesson learned.
Related
i have created a java client in netbeans 7.2 from a wsdl
the issue is that the header send Soapaction but the server is expecting to receive SOAPAction
i try to overwrite the properties using this code
BindingProvider prov = (BindingProvider)port;
prov.getRequestContext().put(BindingProvider.SOAPACTION_USE_PROPERTY, false);
prov.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://www.microsoft.com");
but again in the server it receives Soapaction instead of receiving SOAPAction
can someone tell me how can i overright this value?
thank you
I think you try to add it in a wrong place.
BindingProvider is only the stub object, "provides access to the protocol binding and associated context objects for request and response message processing."
What you really need here is an SOAP message interceptor, which you can use to customize your SOAP messages generated by your WS library.
In case you use JAX-WS, you can use for example SOAPHandlers to do this.
Here is an example:
http://www.mkyong.com/webservices/jax-ws/jax-ws-soap-handler-in-client-side/
If this is not your case, please provide more details about your application (what kind of project it is, what kind of WS implementation you are using etc).
I'm getting the error "Transport level information does not match with SOAP Message namespace URI". Request you provide the details to fix the issue.
I have set the below in the client side.
HttpTransportProperties.ProxyProperties proxyProperties = new HttpTransportProperties.ProxyProperties();
proxyProperties.setProxyName(proxyAddress);
proxyProperties.setProxyPort(proxyPort);
stub._getServiceClient().getOptions().setProperty(HTTPConstants.CHUNKED,Boolean.FALSE);
stub._getServiceClient().getOptions().setProperty(HTTPConstants.PROXY, proxyProperties);
stub._getServiceClient().getOptions().setProperty(HTTPConstants.HEADER_CONTENT_TYPE,"application/soap+xml");
stub._getServiceClient().getOptions().setProperty("type","application/soap+xml");
stub._getServiceClient().getOptions().setProperty(HTTPConstants.HEADER_SOAP_ACTION, Action_URL);
stub._getServiceClient().getOptions().setProperty ( HTTPConstants.HTTP_PROTOCOL_VERSION, HTTPConstants.HEADER_PROTOCOL_11 ) ;
stub._getServiceClient().getOptions().setProperty ( "Transfer-Encoding", "chunked" ) ;
stub._getServiceClient().getOptions().setProperty(HTTPConstants.REUSE_HTTP_CLIENT, "true");
Can you please help to solve the issue?
That error occurs if there is a mismatch between the content type and the SOAP version (as determined by the namespace URI of the SOAP envelope) of the received message. E.g. if Axis2 receives a SOAP 1.2 message with content type text/xml, it will trigger that error.
Joe - If you are getting this error, then I am assuming that you are trying to access a service that is really old and you might be using Axis that is version 2.0 . You will not be able to call the service by creating client using Axis or CXF. I have spent days trying to figure this out. Eventually I ended up using SAAJ API to create the request WSDL and post it to the service.
It is very easy and keeps you away from trying to figure out RPC/Literal/Document style etc.
See this post - Post
I have been provided a WSDL for a webservice. I am now required to digitally sign that request. The previous developer utilized the Eclipse feature to generate proxy classes. Add the WSDL to the project, then right click on it, click "Web Service", then "Generate Client".
This worked fine until we were required to digitally sign the request. I did some digging and it looks like Axis 1.4 doesn't allow you to sign requests. You can use WSS4J to do that. I mavened in WSS4j 1.5 into my project.
I'm at a loss on how to digitally sign the request. Here is my existing code that uses the proxy classes:
XiSecureWSServiceLocator service = new XiSecureWSServiceLocator();
service.setXiSecureWSServicePortEndpointAddress(paymetricPortAddress);
XiSecureWSPortType proxy = service.getXiSecureWSServicePort();
((Stub) proxy).setTimeout(paymetricTimeOutinMillisec);
SDecrypt_InputType sdi = new SDecrypt_InputType();
sdi.setStrToken(ccNumber);
sdi.setStrUserID(user);
SDecrypt_OutputType sdo = null;
sdo = proxy.pm_SingleDecrypt(sdi);
What I want to do is something similar to this article. Here is a function they used:
public Message signSOAPEnvelope(SOAPEnvelope
unsignedEnvelope) throws Exception
{
WSSignEnvelope signer = new WSSignEnvelope();
String alias = "16c73ab6-b892-458f-abf5-2f875f74882e";
String password = "security";
signer.setUserInfo(alias, password);
Document doc = unsignedEnvelope.getAsDocument();
Document signedDoc = signer.build(doc, crypto);
// Convert the signed document into a SOAP message.
Message signedSOAPMsg =
(org.apache.axis.Message)AxisUtil.toSOAPMessage(signedDoc);
return signedSOAPMsg;
}
How can i get the Soap Envelope to be signed when all of the code to create it is hidden in the generated proxy classes?
This JavaRanch Thread explains implementing Security and Encryption with WSS4J using Axis handlers.
It looks like you have to do a number of things:
Configure/write a wsdd
Call the web service with an EngineConfiguration pointing to your wsdd file
Write a password callback class
Write a crypto.properties file
ensure the crypto.properties file and the key store containing the certificate are on the class path of the app.
Props to John Farrel on the JavaRanch forum for figuring all this out.
All in all kind of a pain in the butt. If there's a way to obtain the underlying SOAP Message itself from the Axis proxy class, that might be a quicker way to do it, but I don't have a lot of experience with Axis 1.
Hello from /r/java, by the way!
Found this:
Can anyone recommend to me or point me somewhere that describes
a simple, straightforward way to sign a SOAP request with a Digital
Signature within the Axis framework?
"Have a look at the WSS4J project. They provide Axis handlers for signing and encrypting as it is described in WS Security."
http://mail-archives.apache.org/mod_mbox/axis-java-user/200403.mbox/%3CCGEOIPKACAGJDDPKCDIHEEKACCAA.abhinavm#contata.co.in%3E -
Does that help?
This seems like it should be simple, but maybe I'm missing something. I just want to make a SOAP call in Java, preferrably using only built-in APIs. I'm a little overwhelmed looking at javax.xml.soap package in the Java documentation. I have tried searching Google, but it seems like all the results are from 2000-2002, and they are all talking about libraries that can be used for SOAP calls (before SOAP libraries were built in, I guess).
I don't need to handle the SOAP request; only make one. This site has an example that is pretty simple, but it doesn't use the built-in Java SOAP libraries. How would I do basically the same thing using core Java?
// Create the parameters
Vector params = new Vector( );
params.addElement(
new Parameter("flightNumber", Integer.class, flightNumber, null));
params.addElement(
new Parameter("numSeats", Integer.class, numSeats, null));
params.addElement(
new Parameter("creditCardType", String.class, creditCardType, null));
params.addElement(
new Parameter("creditCardNumber", Long.class, creditCardNum, null));
// Create the Call object
Call call = new Call( );
call.setTargetObjectURI("urn:xmltoday-airline-tickets");
call.setMethodName("buyTickets");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
call.setParams(params);
// Invoke
Response res = call.invoke(new URL("http://rpc.middleearth.com"), "");
// Deal with the response
Soap has changed a lot since the early days. You can do things like what you describe, but it is not common.
A more common practice now is to use a wsdl2java tool to generate a client API from a WSDL description of the service. That will give you a nice, clean, API to call.
Apache CXF is one place to go for this sort of thing.
One proviso is rpc/encoded. If you are dealing with an old service, it might be rpc/encoded, and in that case your best bet is Apache Axis 1.x. Everything else has run away from rpc/encoded.
The simplest way is soap-ws library:
https://github.com/reficio/soap-ws
SoapClient client = SoapClient.builder()
.endpointUrl("http://rpc.middleearth.com")
.build();
client.post(envelope);
I am using axis 2 webservice client.
The first https call to the webservice throws a exception with the message: "Message did not contain a valid Security Element".
I think that the problem could be the security mode: maybe it has to be message level security. In this case, how can I configure it in axis?.
The code:
System.setProperty("javax.net.ssl.keyStore", jksFile);
System.setProperty("javax.net.ssl.keyStorePassword", jksPassword);
MyServicePortProxy proxy = new MyServicePortProxy();
Stub stub = (Stub) proxy.getMyServicePort();
proxy.setEndpoint(endpoint);
stub.setUsername(username);
stub.setPassword(password);
// throws exception with the above message:
proxy.serviceMethod(...);
Take a look at http://ws.apache.org/wss4j/package.html we had to define a client-config.wsdd that told axis to include username/password (if it is ws-security you are using). I am a little bit weak on the different standards and what separates them.
It's possible that in your XML service definition you need to create a service policy -[http://schemas.xmlsoap.org/ws/2004/09/policy/]
Take a look at these articles:
http://www.javaranch.com/journal/200603/Journal200603.jsp#a2
http://www.javaranch.com/journal/200709/web-services-authentication-axis2.html
Watch your clock-skew. If the timestamp in the security element provided by the client is too far into the past or the future from the server's perspective, it may reject it with exactly this message.