In my soap application, I'm using apache cxf.
Here's my code which will submit data to the server.
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.bus.spring.SpringBusFactory;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.ws.security.wss4j.DefaultCryptoCoverageChecker;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
SpringBusFactory bf = new SpringBusFactory();
URL busFile = Submission.class.getResource(WSSEC_XML);
File f = new File(busFile.getPath());
Bus bus = bf.createBus(busFile.toString());
BusFactory.setDefaultBus(bus);
BusFactory.setThreadDefaultBus(bus);
DefaultCryptoCoverageChecker coverageChecker = new DefaultCryptoCoverageChecker();
coverageChecker.setSignBody(true);
coverageChecker.setSignTimestamp(true);
coverageChecker.setEncryptBody(true);
coverageChecker.setSignAddressingHeaders(true);
MyClaimservice service = new MyClaimservice();
Myclaims port = service.getMyClaimsSoap11();
BindingProvider provider = (BindingProvider) port;
provider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, ENDPOINT_ADDRESS);
provider.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, SOAP_ACTION);
Client client = ClientProxy.getClient(port);
client.getOutInterceptors().add(new LoggingOutInterceptor());
client.getInInterceptors().add(new LoggingInInterceptor());
client.getInInterceptors().add(new WSS4JInInterceptor(getInProps()));
client.getOutInterceptors().add(new WSS4JOutInterceptor(getOutProps()));
client.getInInterceptors().add(coverageChecker);
SubmissionResponse response = port.submission(request);
My request data is formed like this.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
....
....
....
</soap:Envelope>
I need to add additional namespace to <soap:Envelope>
. My expected data should be like this,
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:prefix1="url1" xmlns:prefix2="url2" xmlns:prefix3:"url3">
....
....
....
</soap:Envelope>
I tried adding those prefixes and namespace urls to DefaultCryptoCoverageChecker
using Map and XpathExpressions. But seems like it does not made any changes to my request data.
Map<String, String> prefixes = new HashMap<String, String>();
prefixes.put("prefix1", "url1");
prefixes.put("prefix2", "url2");
prefixes.put("prefix3", "url3");
prefixes.put("prefix4", "url4");
prefixes.put("prefix5", "url5");
List<XPathExpression> xpaths = Arrays.asList(
new XPathExpression("//prefix1:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix2:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix3:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix4:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix5:Envelope", CoverageType.SIGNED));
DefaultCryptoCoverageChecker coverageChecker = new DefaultCryptoCoverageChecker();
coverageChecker.addPrefixes(prefixes);
coverageChecker.addXPaths(xpaths);
coverageChecker.setSignBody(true);
coverageChecker.setSignTimestamp(true);
coverageChecker.setEncryptBody(true);
coverageChecker.setSignAddressingHeaders(true);
Any help would be greatly appreciated.
Update 2:
I've tried Apache cxf's transformation feature.
Map<String, String> outTransformMap = Collections.singletonMap("{http://schemas.xmlsoap.org/soap/envelope/}Envelope", "Envelope");
TransformOutInterceptor transformOutInterceptor = new TransformOutInterceptor();
transformOutInterceptor.setOutTransformElements(outTransformMap);
client.getOutInterceptors().add(transformOutInterceptor);
According to http://cxf.apache.org/docs/transformationfeature.html#TransformationFeature-JAX-WS, above code will remove that specific namespace from Envelope
node. And I can also confirm it by seeing the xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/
is being removed from <soap:Envelope>
I tried the reverse of transformOutInterceptor.setOutTransformElements(outTransformMap);
by replacing it with transformOutInterceptor.setOutAppendElements(outTransformMap);
, where the outTransformMap
will now contains Collections.singletonMap("{url1 (which I need to add)}Envelope", "Envelope");
. But it's not appending it as a new Namespace to Envelope
. What am I doing wrong here.. Is it really difficult to add additional namespace to <soap:Envelope>
other than the default namesapce.
SOAP messages must declare the namespace of the Envelope element to be the standard SOAP 1.1 envelope namespace, "http://schemas.xmlsoap.org/soap/envelope/". If a SOAP application receives a message based on some other namespace, it must generate a fault.
An XML namespace is a means of qualifying element and attribute names to disambiguate them from other names in the same document. This section provides a brief description of XML namespaces and how they are used in SOAP. For complete information, see http://www.w3.org/TR/REC-xml-names/
The namespace URI specifies the XML namespace used to compose the SOAP request envelope for the given SOAP operation. The domain component from URL clause is used when the namespace URI is not defined.
SOAP defines two namespaces (see [8] for more information on XML namespaces): The SOAP envelope has the namespace identifier "http://schemas.xmlsoap.org/soap/envelope/" The SOAP serialization has the namespace identifier "http://schemas.xmlsoap.org/soap/encoding/"
After digging on cxf forums, I found the answer.
Map<String, String> nsMap = new HashMap<>();
nsMap.put("prefix1", "url1");
nsMap.put("prefix2", "url2");
nsMap.put("prefix3", "url3");
nsMap.put("prefix4", "url4");
nsMap.put("prefix5", "http://www.w3.org/2001/04/xmlenc#");
Client client = ClientProxy.getClient(port);
client.getRequestContext().put("soap.env.ns.map", nsMap);
I would be appreciated if anyone know on how to do the same for <soap:Header>
You can add headers like this:
UserCredentials authHeader = new UserCredentials();
authHeader.setUsername(username);
authHeader.setPassword(password);
ArrayList<Header> headers = new ArrayList<Header>(1);
try {
Header soapHeader = new Header(new QName(TQIntegrationV2.TQIntegrationV2Soap.getNamespaceURI(), "UserCredentials"), authHeader, new JAXBDataBinding(UserCredentials.class));
headers.add(soapHeader);
} catch (JAXBException ex) {
LOGGER.error("Exception trying to serialize header: {}", ex);
}
client.getRequestContext().put(Header.HEADER_LIST, headers);
you can leave setUsername/setPassword if you dont want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With