JAX-WS - Adding SOAP Headers
Solution 1
Not 100% sure as the question is missing some details but if you are using JAX-WS RI, then have a look at Adding SOAP headers when sending requests:
The portable way of doing this is that you create a
SOAPHandler
and mess with SAAJ, but the RI provides a better way of doing this.When you create a proxy or dispatch object, they implement
BindingProvider
interface. When you use the JAX-WS RI, you can downcast toWSBindingProvider
which defines a few more methods provided only by the JAX-WS RI.This interface lets you set an arbitrary number of Header object, each representing a SOAP header. You can implement it on your own if you want, but most likely you'd use one of the factory methods defined on
Headers
class to create one.import com.sun.xml.ws.developer.WSBindingProvider; HelloPort port = helloService.getHelloPort(); // or something like that... WSBindingProvider bp = (WSBindingProvider)port; bp.setOutboundHeader( // simple string value as a header, like <simpleHeader>stringValue</simpleHeader> Headers.create(new QName("simpleHeader"),"stringValue"), // create a header from JAXB object Headers.create(jaxbContext,myJaxbObject) );
Update your code accordingly and try again. And if you're not using JAX-WS RI, please update your question and provide more context information.
Update: It appears that the web service you want to call is secured with WS-Security/UsernameTokens. This is a bit different from your initial question. Anyway, to configure your client to send usernames and passwords, I suggest to check the great post Implementing the WS-Security UsernameToken Profile for Metro-based web services (jump to step 4). Using NetBeans for this step might ease things a lot.
Solution 2
Data can be transferred in SOAP header (JaxWS) by using @WebParam(header = true):
@WebMethod(operationName = "SendRequest", action = "http://abcd.ru/")
@Oneway
public void sendRequest(
@WebParam(name = "Message", targetNamespace = "http://abcd.ru/", partName = "Message")
Data message,
@WebParam(name = "ServiceHeader", targetNamespace = "http://abcd.ru/", header = true, partName = "ServiceHeader")
Header serviceHeader);
If you want to generate a client with SOAP Headers, you need to use -XadditionalHeaders:
wsimport -keep -Xnocompile -XadditionalHeaders -Xdebug http://12.34.56.78:8080/TestHeaders/somewsdl?wsdl -d /home/evgeny/DEVELOPMENT/JAVA/gen
If don't need @Oneway web service, you can use Holder:
@WebMethod(operationName = "SendRequest", action = "http://abcd.ru/")
public void sendRequest(
@WebParam(name = "Message", targetNamespace = "http://abcd.ru/", partName = "Message")
Data message,
@WebParam(name = "ServiceHeader", targetNamespace = "http://abcd.ru/", header = true, partName = "ServiceHeader")
Holder<Header> serviceHeader);
Solution 3
I'm adding this answer because none of the others worked for me.
I had to add a Header Handler to the Proxy:
import java.util.Set;
import java.util.TreeSet;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class SOAPHeaderHandler implements SOAPHandler<SOAPMessageContext> {
private final String authenticatedToken;
public SOAPHeaderHandler(String authenticatedToken) {
this.authenticatedToken = authenticatedToken;
}
public boolean handleMessage(SOAPMessageContext context) {
Boolean outboundProperty =
(Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
try {
SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
SOAPFactory factory = SOAPFactory.newInstance();
String prefix = "urn";
String uri = "urn:xxxx";
SOAPElement securityElem =
factory.createElement("Element", prefix, uri);
SOAPElement tokenElem =
factory.createElement("Element2", prefix, uri);
tokenElem.addTextNode(authenticatedToken);
securityElem.addChildElement(tokenElem);
SOAPHeader header = envelope.addHeader();
header.addChildElement(securityElem);
} catch (Exception e) {
e.printStackTrace();
}
} else {
// inbound
}
return true;
}
public Set<QName> getHeaders() {
return new TreeSet();
}
public boolean handleFault(SOAPMessageContext context) {
return false;
}
public void close(MessageContext context) {
//
}
}
In the proxy, I just add the Handler:
BindingProvider bp =(BindingProvider)basicHttpBindingAuthentication;
bp.getBinding().getHandlerChain().add(new SOAPHeaderHandler(authenticatedToken));
bp.getBinding().getHandlerChain().add(new SOAPLoggingHandler());
Solution 4
Also, if you're using Maven to build your project, you'll need to add the following dependency:
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>{currentversion}/version>
</dependency>
This provides you with the class com.sun.xml.ws.developer.WSBindingProvider
.
Link: https://mvnrepository.com/artifact/com.sun.xml.ws/jaxws-rt
Solution 5
you can add the username and password to the SOAP Header
BindingProvider prov = (BindingProvider)port;
prov.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"your end point"));
Map<String, List<String>> headers = new HashMap<String, List<String>>();
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword");
prov.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, headers);
Jordan Allan
Updated on September 18, 2020Comments
-
Jordan Allan over 3 years
I am trying to create a standalone client to consume some web services. I must add my username and password to the SOAP Header. I tried adding the credentials as follows:
OTSWebSvcsService service = new OTSWebSvcsService(); OTSWebSvcs port = service.getOTSWebSvcs(); BindingProvider prov = (BindingProvider)port; prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername"); prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword"); ...
When I call a method on the service I get the following exception:
com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5048E: One of "SOAP Header" elements required.
What am I doing wrong? How would I add these properties to the SOAP Header?
Edited: I was using JAX-WS 2.1 included in JDK6. I am now using JAX-WS 2.2. I now get the following exception:
com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5509E: A security token whose type is [http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken] is required.
How do I go about creating this token?
-
Buhake Sindi over 11 years+1, the
-XadditionalHeaders
is an important attribute in this case. -
kkessell about 11 yearsI cannot get eclipse to import this
com.sun.xml.internal.ws.developer.WSBindingProvider
class. -
james2611nov about 9 yearsWill there be any portability issues if we use the classes from com.sum package?
-
Zeus over 8 yearsheader=true did the trick for me. I had make a copy the existing stub and set the header = true on the copy for the maven wsimport not to overwrite the generated stubs.
-
Abdul Razak AK about 6 yearsWhat is the equivalent in maven plugin for -additionalHeader ?
-
apetrelli almost 6 years@AbdulRazakAK <args>-XadditionalHeaders</args>
-
vab2048 almost 5 yearsFor those who are using
wsdl2java
instead ofwsimport
the equivalent of-XadditionalHeaders
is-exsh true
(exsh stands for extended soap header binding and 'true' enables this) with an example command being:.\wsdl2java.bat -exsh true -autoNameResolution <wsdl-url>
-
FiruzzZ over 4 yearsby far, the easiest and simple solution. PD: I didn't have any of the problems mentioned above using Maven, no need for
<args>-XadditionalHeaders</args>
, no extra dependencies -
Søren Boisen over 3 yearsLink to post about WS-Security is dead.
-
JGlass almost 3 years@pihentagy - I have
import javax.xml.ws.BindingProvider;
-
hello_earth almost 3 yearsthis wouldn't work if UsernameToken is required - this modifies the HTTP headers, not the SOAP message headers...
-
hello_earth almost 3 yearsnote that adding handlers this way won't work, because bp.getBinding().setHandlerChain(...) needs to be called - see rumberomelo's answer
-
hello_earth almost 3 yearsalso here's a better example specifically for UsernameToken headers scenario: ibm.com/docs/en/sc-and-ds/…
-
hello_earth almost 3 yearsalthough Basic Authentication headers might also be required in UsernameToken scenario too....
-
SavinI over 2 yearsFrom which package you get Header class?
-
nephewtom over 2 yearsThanks @hello_earth, those 2 comments are exactly what it was need to bring light to this issue.