Java Spring Webservices SOAP Authentication - java

I am using java spring webservice to send soap requests to a server. However I get an error from the server saying
The security context token is expired or is not valid
So then I added authentication to the SOAP headers, resulting in request xml something like this:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<UsernameToken>
<Username>XXXXXXXX</Username>
<Password>XXXXXXXX</Password>
</UsernameToken>
</Security>
</env:Header>
<env:Body>
The body is in the correct format here
</env:Body>
</env:Envelope>
But I still get that error. From what I understand, the client sends authentication credentials to the server, the server sends back requestToken which is used to keep connection alive between client and server and then client using the token received from the server can make any other API calls such as login, buy, sell (or whatever mentioned in API)
Am I right in this assumption? If yes, how can this be implemented using Java Spring WebServices. Do I need to generate fields on client side like BinarySecret and package that under RequestSecurityContext?
For adding the SOAP headers, I wrote a class which implements WebServiceMessageCallback and overrides doWithMessage method and writes headers in that for username and password (i.e security)
Any help would be appreciated! Thank You!

So after 2 days of finding out, I was able to figure out the solution!
1) Generate the classes from wsdl using CXF wsdl2java
2) Make sure in the pom file, you point to the correct wsdlLocation
3) Get the stub from the service class generated and inject username and password provided and then it should work. Something like this:
final YourService service = new YourService();
final YourStub stub = service.getService();
final Map ctx = ((BindingProvider)stub).getRequestContext();
ctx.put("ws-security.username", userName);
ctx.put("ws-security.password", password);
stub.callYourMethod();
PS: Please make sure you have the right libraries, I just used cxf-bundle and nothing else from cxf and it worked! Earlier it was not working as I had individually included libraries from cxf.

Related

set soapaction header in a java client

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).

Pass Crendentials from dotNet client to Java Web Service

I have a dot net application that call a java web service. I am trying to implement authentication by passing credentials to the java service. Here is the dot net code setting the credentials. How can I get these credentials in my java application? They aren't set in the headers...
System.Net.NetworkCredential serviceCredentials = new NetworkCredential("user", "pass");
serviceInstance.Credentials = serviceCredentials;
serviceInstance is an instance of SoapHttpClientProtocol.
I've tried injecting the WebServiceContext like so
#Resource
WebServiceContext wsctx;
and pulling the crentials from the headers but they aren't there.
You are not passing the credentials to your service the correct way. In order to get the Authorize http request header do the following:
// Create the network credentials and assign
// them to the service credentials
NetworkCredential netCredential = new NetworkCredential("user", "pass");
Uri uri = new Uri(serviceInstance.Url);
ICredentials credentials = netCredential.GetCredential(uri, "Basic");
serviceInstance.Credentials = credentials;
// Be sure to set PreAuthenticate to true or else
// authentication will not be sent.
serviceInstance.PreAuthenticate = true;
Note: Be sure to set PreAuthenticate to true or else authentication will not be sent.
see this article for more information.
I had to dig-up some old code for this one :)
Update:
After inspecting the request/response headers using fiddler as suggested in the comments below a WWW-Authenticate header was missing at the Java Web Service side.
A more elegant way of implementing "JAX-WS Basic authentication" can be found in this article here using a SoapHeaderInterceptor (Apache CXF Interceptors)

Adding soap header authentication to wsdl2java generated code

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.

How to digitally sign SOAP request using Eclipse generated proxy (axis 1.4) via WSS4J?

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?

HTTP Basic Authentication for WEBService call

I trying to invoke a web service, which has an Basic HTTP Authentication. I generated the client code using the WSDL2JAVA tool from AXIS.
But I am not able to set the username and password to the webservice call.
I tried to have them in the endpoint url as
http://username:password#somwserver/wsdl
But I am getting the unauthorized error for this. I am trying to figure out a way to get this set to my call in the Java code....
Note : I am able to invoke the same service via the soapUI and get the results. I provided the username and password in the "Aut" tab on the request.
Here is some of the code snippets of my Stub, if this is userful for you
_serviceClient = new org.apache.axis2.client.ServiceClient(configurationContext,_service);
_serviceClient.getOptions().setTo(new org.apache.axis2.addressing.EndpointReference(
targetEndpoint));
_serviceClient.getOptions().setUseSeparateListener(useSeparateListener);
//adding SOAP soap_headers
_serviceClient.addHeadersToEnvelope(env);
// set the message context with that soap envelope
_messageContext.setEnvelope(env);
// add the message contxt to the operation client
_operationClient.addMessageContext(_messageContext);
//execute the operation client
_operationClient.execute(true);
Any inputs will be greatly appreciated!!
HttpTransportProperties.Authenticator
auth = new HttpTransportProperties.Authenticator();
auth.setUsername("username");
auth.setPassword("password");
_serviceClient.getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.BASIC_AUTHENTICATE,auth);

Categories