move xml namespace declarations to root element with jax-ws annotations - java

I'm trying to generate an xml payload with jax-ws and it's not working out. The server expects all namespaces to be in the envelope tag. For example:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://somewhere.namespace1.com" xmlns:ns2="http://somewhere.namespace2.com">
is what I need, while
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
is what I have.
jax-ws generates a payload like
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns1:Element1 xmlns:ns1="http://somewhere.namespace1.com" xmlns:ns1="http://somewhere.namespace2.com">
<ns2:Element2>value</ns2:Element2>
</ns1:Element1>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
but I need
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://somewhere.namespace1.com" xmlns:ns2="http://somewhere.namespace2.com">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns1:Element1>
<ns2:Element2>value</ns2:Element2>
</ns1:Element1>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I have tried putting package-info.java files with the #javax.xml.bind.annotation.XmlSchema and I'm able to change the prefix but not move the actual namespace declaration from a child node to the root node. For example, I can (apparently?) define all the namespaces I need in the envelope with
#javax.xml.bind.annotation.XmlSchema(
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns = {
#XmlNs(
prefix = "ns1",
namespaceURI="http://somewhere.namespace1.com"),
#XmlNs(
prefix = "ns2",
namespaceURI="http://somewhere.namespace2.com"),
}
)
But then in the package-info.java where Element1.java and Element2.java are, I don't want the namespaces defined there. I've tried
#javax.xml.bind.annotation.XmlSchema(
namespace="http://schemas.xmlsoap.org/soap/envelope/",
location = ""
)
but it doesn't work.
Has anyone else had a similar problem? I'm sure it's just a question of annotations but I haven't been able to figure it out.

I solved this problem by making the call with Spring's WebServiceTemplate#sendAndReceive(String, WebServiceMessageCallback, WebServiceMessageExtractor<T>) where in the second parameter (the callback) I manually added the namespaces that I needed to be in the header. For example something like
wsResponse = this.webServiceTemplate.sendAndReceive(uri,
(webServiceMessage) -> {
...
SoapMessage soapMessage = (SoapMessage) webServiceMessage;
...
final SoapEnvelope envelope = soapMessage.getEnvelope();
headerNamespaces.forEach(envelope::addNamespaceDeclaration);
...
}, this.responseExtractor);

Related

How to add a SAML assertion to a SOAP security header in Spring using Wss4jSecurityInterceptor

I have a requirement to pass a SAML assertion as a token inside a SOAP security header. I am using Spring-WS as the framework.
The XML that I want to create looks like this:
I have a requirement to pass a SAML assertion as a token inside a SOAP security header.
The XML that I want to create looks as below. As can be seen, the XML contains the assertion with the wsse:Security block.
Is there a way to do this with the Wss4jSecurityInterceptor class ?
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<Assertion MinorVersion="1" MajorVersion="1" Issuer="http://www.bea.com/saml"
IssueInstant="2005-11-10T11:27:36.233Z" AssertionID="HRMC-SM172.26.5.143.1106860829320"
xmlns="urn:oasis:names:tc:SAML:1.0:assertion">
<Conditions NotOnOrAfter="2005-11-10T15:27:36.233Z" NotBefore="2005-11-10T11:22:36.233Z"/>
<AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified"
AuthenticationInstant="2005-11-10T11:27:36.233Z">
<Subject>
<NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">ANYAGENT
</NameIdentifier>
<SubjectConfirmation>
<ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</ConfirmationMethod>
</SubjectConfirmation>
</Subject>
</AuthenticationStatement>
</Assertion>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<m:DPSretrieve xmlns:m="https://tpvs.hmrc.gov.uk/dps">
<m:version>1</m:version>
<m:vendorID>your 4 digit vendorID</m:vendorID>
<m:service>PAYE</m:service>
<m:entityType>EmpRef</m:entityType>
<m:entity>as advised by SDS Team</m:entity>
<m:dataType>P6</m:dataType>
<m:got>0</m:got>
<m:nItems>0</m:nItems>
</m:DPSretrieve>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I ended up fixing it via this answer, which worked perfectly:
https://stackoverflow.com/a/59666667/3094805

SOAP XML request returning "Request is not well formed" fault

I am converting Python code to Java. The code is SOAP 1.5 client code which communicates with a SOAP server endpoint.
What doesn't make sense is that the Python code sends the XML request and gets the accepted response from the server. With the Java code however, the response is a fault stating "Request is not well formed".
Below I am showing the XML requests, the one which is sent in Python and the other in Java. How can the Java one sent by Java return a fault, but the Python is fine / accepted. They are both valid requests. Or perhaps I am missing something obvious.
Request in Python :
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:cs="urn://Ocpp/Cp/2012/06/">
<SOAP-ENV:Header>
<cs:chargeBoxIdentity>Test</cs:chargeBoxIdentity>
<wsa:MessageID>Fake OCPP571322528896</wsa:MessageID>
<wsa:Action>/ChangeConfiguration</wsa:Action>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cs:changeConfigurationRequest>
<cs:key>LaMa_ConnectionRate</cs:key>
<cs:value>5120</cs:value>
</cs:changeConfigurationRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Request in Java :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:cs="urn://Ocpp/Cp/2012/06/"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<SOAP-ENV:Header>
<cs:chargeBoxIdentity>Test</cs:chargeBoxIdentity>
<wsa:Action>/ChangeConfiguration</wsa:Action>
<wsa:MessageID>Fake OCPP571322528896</wsa:MessageID>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cs:changeConfigurationRequest>
<cs:key>LaMa_ConnectionRate</cs:key>
<cs:value>5120</cs:value>
</cs:changeConfigurationRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Fault response to Java :
<?xml version="1.0" encoding="UTF-8"?><env:Envelope
xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header/>
<env:Body>
<env:Fault>
<env:Code>
<env:Value>env:Sender</env:Value>
</env:Code>
<env:Reason>
<env:Text xml:lang="en-US">XML Request is not well formed!</env:Text>
</env:Reason>
</env:Fault>
</env:Body>
</env:Envelope>
Update :
My Java code should be sending "http://www.w3.org/2003/05/soap-envelope" for "SOAP-ENV", as shown below in my code. However it somehow sends "http://schemas.xmlsoap.org/soap/envelope/" instead. I don't understand why.
// SOAP Envelope
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope");

how to retrieve specific web service response from the server

Web service provider has provided us(Client) a wsdl to use their service and consume data. Our requirement is, we just need specific node value called "CHASE", see below test data. We don't want to get all records of info and corresponding nodes in the response.
Here is an example that we have tested in SOAPUI tool. Please suggest and help us how can we frame the web service request technically from the URL provided(http://host:port/ValueMappingInService/ValueMappingInImplBean)? Is it at all possible to drill down the request and get specific response from client side?
Web service Request:-
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:bas="http://sap.com/xi/BASIS">
<soapenv:Header/>
<soapenv:Body>
<bas:ValueMappingReadRequest>
<!--Optional:-->
<ReadContext>User</ReadContext>
<!--Zero or more repetitions:-->
<ValueMappingID>c44f541f-c8ac-11e8-86e5-0050569d98cc</ValueMappingID>
</bas:ValueMappingReadRequest>
</soapenv:Body>
</soapenv:Envelope>
Web service Response:-
<SOAP-ENV:Envelope xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-
ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns2:ValueMappingReadResponse xmlns:ns2="http://sap.com/xi/BASIS">
<ValueMapping>
<MasterLanguage>EN</MasterLanguage>
<AdministrativeData>
<ResponsibleUserAccountID>gdonna</ResponsibleUserAccountID>
<LastChangeUserAccountID>gdonna</LastChangeUserAccountID>
<LastChangeDateTime>2018-10-05T09:47:38.237-05:00</LastChangeDateTime>
<FolderPathID>/</FolderPathID>
</AdministrativeData>
<ValueMappingID>c44f541f-c8ac-11e8-86e5-0050569d98cc</ValueMappingID>
<GroupName>Mercedes</GroupName>
<Representation schemeAgencyID="LOC_BANK" schemeID="BANK">CHASE</Representation>
<Representation schemeAgencyID="LOC_SITE" schemeID="DIR">comm/as2/chase/receive/</Representation>
<Representation schemeAgencyID="LOC_COUNTRY" schemeID="CODE">US</Representation>
</ValueMapping>
<LogMessageCollection/>
</ns2:ValueMappingReadResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Try using a Groovy Script. I really like the features of the XMLSlurper, which lets me ignore the namespaces if/when they change.
Just add a new Groovy Script teststep, and put this into it. You just need to adjust the name of your Soap Request teststep, which should be placed just before this teststep.
/** The name should be modified to match the request/response you want to validate */
def holder = new com.eviware.soapui.support.GroovyUtils( context ).getXmlHolder("The Name Of Your Soap Request TestStep#Response")
def response = new XmlSlurper().parseText(holder.getXml())
for (def element : response.Body.ValueMappingReadResponse.ValueMapping.Representation)
{
log.info element
log.info element.#'schemeAgencyID'
}

Disable output escaping for spring ws

I have a bit of a problem with spring-ws WebserviceTemplate
I've created a WebserviceMessage like this
public WebServiceMessage createWebServiceMessage(String innerEnvelope)
{
SOAPMessage soapMsg=null;
MessageFactory factory;
try
{
factory = MessageFactory.newInstance();
soapMsg = factory.createMessage();
SOAPPart part = soapMsg.getSOAPPart();
SOAPEnvelope envelope = part.getEnvelope();
SOAPBody body = envelope.getBody();
QName ejbName = new QName(EJB_VALUE,"lustraciaOsoby",EJB_PREFIX);
SOAPElement ejbElement =body.addBodyElement(ejbName);
ejbElement.addNamespaceDeclaration(SOAP_ENV_PREFIX, SOAP_ENV_VALUE);
ejbElement.setAttribute("soapenv:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/");
QName transName=new QName(TRANS_ELEMENT);
SOAPElement transElement = ejbElement.addChildElement(transName);
transElement.addNamespaceDeclaration(XSI_PREFIX, XSI_VALUE);
transElement.addNamespaceDeclaration(XSD_PREFIX, XSD_VALUE);
transElement.setAttribute("xsi:type", "xsd:string");
transElement.addTextNode(innerEnvelope);
soapMsg.saveChanges();
} catch (SOAPException e)
{
LOGGER.debug("Error while creating message",e);
}
return (WebServiceMessage)new SaajSoapMessage(soapMsg);
}
which result in XML that is looking like this(this is 100% valid request for this web service, with usage of standard HttpConnection it was returning valid response)
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/><SOAP-ENV:Body><ejb:lustraciaOsoby xmlns:ejb="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<transXmlEnc xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">
<TransEnv xmlns="http://schemas.mvsr.sk/clk/clk2/lustracia_osoby_in_transxml.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
cPageSize="50" cRecNoFrom="0">
<LOI><SI>2,3,5,8,19</SI><PR>Mrkvička</PR><PR_PARTIAL>false</PR_PARTIAL><PR_FUZZY>false</PR_FUZZY><ME>Ján</ME><ME_PARTIAL>false</ME_PARTIAL><ME_FUZZY>false</ME_FUZZY><LV_ANYNAME>false</LV_ANYNAME>
</LOI></TransEnv>
</transXmlEnc>
</ejb:lustraciaOsoby>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Just for info, that escaped part is like soap in soap, which is parsed on server side.
The problem is, when I execute this with sendSourceAndReceiveToResult, the final SOAP that is sent is in this form
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ejb:lustraciaOsoby
xmlns:ejb="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<transXmlEnc xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">
&lt;TransEnv xmlns=&quot;http://schemas.mvsr.sk/clk/clk2/lustracia_osoby_in_transxml.xsd&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; cPageSize=&quot;50&quot; cRecNoFrom=&quot;0&quot;&gt;&lt;LOI&gt;&lt;SI&gt;2,3,5,8,19&lt;/SI&gt;&lt;PR&gt;Mrkvi&#269;ka&lt;/PR&gt;&lt;PR_PARTIAL&gt;false&lt;/PR_PARTIAL&gt;&lt;PR_FUZZY&gt;false&lt;/PR_FUZZY&gt;&lt;ME&gt;J&#225;n&lt;/ME&gt;&lt;ME_PARTIAL&gt;false&lt;/ME_PARTIAL&gt;&lt;ME_FUZZY&gt;false&lt;/ME_FUZZY&gt;&lt;LV_ANYNAME&gt;false&lt;/LV_ANYNAME&gt;&lt;/LOI&gt;&lt;/TransEnv&gt;
</transXmlEnc>
</ejb:lustraciaOsoby>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Its pretty hard to spot the difference, but the trick is that all & are replaced with &amp which is a problem, because the parser on the server side can't parse it due to Reference is not allowed in prologue error. Without this weird escape, the request works just fine.
So my question is, is there any way to disable this additional escaping ?
Finally i was able to resolve this. The problem was that input that was coming to transElement.addTextNode(innerEnvelope); was already escaped by StringEscapeUtils and apache tried to escape it again ,what cause the reescapting of & to &amp

Remove namespace tag in web service response using Spring-WS and Jaxb

I'm using a endpoint SOAP created On Spring Framework using JAXB, but I want that my anwers(Expected Response) return without prefix when I Send Request One, but this is returned like is showed on Current Response:.
How can I do to return a message SOAP without namespaces?
Request One
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:sap-com:document:sap:soap:functions:mc-style">
<soapenv:Header/>
<soapenv:Body>
<urn:ZProveerDatosPagoProveed2>
<Bukrs>RG10</Bukrs>
<Langu>S</Langu>
<Lifnr>00000000</Lifnr>
</urn:ZProveerDatosPagoProveed2>
</soapenv:Body>
</soapenv:Envelope>
Current Response:
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header/>
<soap-env:Body>
<n0:ZProveerDatosPagoProveed2Response xmlns:n0="urn:sap-com:document:sap:soap:functions:mc-style">
<Adrnr>0000</Adrnr>
<Bankk>0000</Bankk>
<Bankn>0000</Bankn>
<Bkont>0000</Bkont>
<Iban>ES0000</Iban>
<KoinhFi>ROBLES AVN</KoinhFi>
<Land1>TH</Land1>
<Landx>XXXXX</Landx>
<Name1>ROBLES AVN</Name1>
<Pstlz>0000</Pstlz>
<Stcd1>A0000</Stcd1>
<Stras>ROBLES AVN</Stras>
<Swift>XXXXX</Swift>
<Text1_052>ROBLES AVN</Text1_052>
<Zterm>Z000</Zterm>
</n0:ZProveerDatosPagoProveed2Response>
</soap-env:Body>
</soap-env:Envelope>
Request one and the current response, are the request/response of a web service embedded in another web service (which I implemented), the reason for this implementation is that it has requested that the final answer is this (without namespaces tags):
Expected Response
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header/>
<soap-env:Body>
<ZProveerDatosPagoProveed2Response xmlns="urn:sap-com:document:sap:soap:functions:mc-style">
<Adrnr>0000</Adrnr>
<Bankk>0000</Bankk>
<Bankn>0000</Bankn>
<Bkont>0000</Bkont>
<Iban>ES0000</Iban>
<KoinhFi>ROBLES AVN</KoinhFi>
<Land1>TH</Land1>
<Landx>XXXXX</Landx>
<Name1>ROBLES AVN</Name1>
<Pstlz>0000</Pstlz>
<Stcd1>A0000</Stcd1>
<Stras>ROBLES AVN</Stras>
<Swift>XXXXX</Swift>
<Text1_052>ROBLES AVN</Text1_052>
<Zterm>Z000</Zterm>
</ZProveerDatosPagoProveed2Response>
</soap-env:Body>
</soap-env:Envelope>
The way I was able to do it is the following:
Include the two following jars from JAXB : jaxb-core.jar and jaxb-impl.jar
In the package-info.java file, set the following settings:
Supposing your namespace is "yournamespace"
#javax.xml.bind.annotation.XmlSchema(namespace = yournamespace,
xmlns = {#javax.xml.bind.annotation.XmlNs(prefix = "",
namespaceURI = yournamespace)},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
attributeFormDefault = javax.xml.bind.annotation.XmlNsForm.UNSET)
package com.ctpayment.admin;
It seems that the current implementation of java ignore the previous settings but the jaxb jars do not. I did not push my investigation further. Last but not least, you need the two jars in order to compile.

Categories

Resources