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:
I struggled with all the answers here, starting with Pascal's solution, which is getting harder with the Java compiler not binding against rt.jar
by default any more (and using internal classes makes it specific to that runtime implementation).
The answer from edubriguenti brought me close. The way the handler is hooked up in the final bit of code didn't work for me, though - it was never called.
I ended up using a variation of his handler class, but wired it into the javax.xml.ws.Service
instance like this:
Service service = Service.create(url, qname);
service.setHandlerResolver(
portInfo -> Collections.singletonList(new SOAPHeaderHandler(handlerArgs))
);
The best option (for my of course) is do it yourserfl. It means you can modify programattly all parts of the SOAP message
Binding binding = prov.getBinding();
List<Handler> handlerChain = binding.getHandlerChain();
handlerChain.add( new ModifyMessageHandler() );
binding.setHandlerChain( handlerChain );
And the ModifyMessageHandler source could be
@Override
public boolean handleMessage( SOAPMessageContext context )
{
SOAPMessage msg = context.getMessage();
try
{
SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
SOAPHeader header = envelope.addHeader();
SOAPElement ele = header.addChildElement( new QName( "http://uri", "name_of_header" ) );
ele.addTextNode( "value_of_header" );
ele = header.addChildElement( new QName( "http://uri", "name_of_header" ) );
ele.addTextNode( "value_of_header" );
ele = header.addChildElement( new QName( "http://uri", "name_of_header" ) );
ele.addTextNode( "value_of_header" );
...
I hope this helps you
Adding an object to header we use the examples used here,yet i will complete
ObjectFactory objectFactory = new ObjectFactory();
CabeceraCR cabeceraCR =objectFactory.createCabeceraCR();
cabeceraCR.setUsuario("xxxxx");
cabeceraCR.setClave("xxxxx");
With object factory we create the object asked to pass on the header. The to add to the header
WSBindingProvider bp = (WSBindingProvider)wsXXXXXXSoap;
bp.setOutboundHeaders(
// Sets a simple string value as a header
Headers.create(jaxbContext,objectFactory.createCabeceraCR(cabeceraCR))
);
We used the WSBindingProvider to add the header. The object will have some error if used directly so we use the method
objectFactory.createCabeceraCR(cabeceraCR)
This method will create a JAXBElement like this on the object Factory
@XmlElementDecl(namespace = "http://www.creditreport.ec/", name = "CabeceraCR")
public JAXBElement<CabeceraCR> createCabeceraCR(CabeceraCR value) {
return new JAXBElement<CabeceraCR>(_CabeceraCR_QNAME, CabeceraCR.class, null, value);
}
And the jaxbContext we obtained like this:
jaxbContext = (JAXBRIContext) JAXBContext.newInstance(CabeceraCR.class.getPackage().getName());
This will add the object to the header.
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.
Use maven and the plugin jaxws-maven-plugin. this will generate a web service client. Make sure you are setting the xadditionalHeaders to true. This will generate methods with header inputs.
In jaxws-rt-2.2.10-ources.jar!\com\sun\xml\ws\transport\http\client\HttpTransportPipe.java
:
public Packet process(Packet request) {
Map<String, List<String>> userHeaders = (Map<String, List<String>>) request.invocationProperties.get(MessageContext.HTTP_REQUEST_HEADERS);
if (userHeaders != null) {
reqHeaders.putAll(userHeaders);
So, Map<String, List<String>>
from requestContext with key MessageContext.HTTP_REQUEST_HEADERS
will be copied to SOAP headers.
Sample of Application Authentication with JAX-WS via headers
BindingProvider.USERNAME_PROPERTY
and BindingProvider.PASSWORD_PROPERTY
keys are processed special way in HttpTransportPipe.addBasicAuth()
, adding standard basic authorization Authorization
header.
See also Message Context in JAX-WS