Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add namespace declarations in a SOAPEnvelope

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.

like image 981
The Coder Avatar asked Jul 02 '15 09:07

The Coder


People also ask

How do you set namespace in SOAP envelope?

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.

What is namespace in SOAP XML?

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/

What is namespace URI in SOAP?

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.

Which of the following two namespaces must be present in SOAP request response?

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/"


2 Answers

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>

like image 75
The Coder Avatar answered Oct 10 '22 14:10

The Coder


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.

like image 28
Garry Avatar answered Oct 10 '22 15:10

Garry