Change HTTP response code in CXF SOAP Fault - soap

I have this error
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Message part {http://soap.ws.server.wst.fit.cvut.cz/}createOrders was not recognized. (Does it exist in service WSDL?)</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
which is completely fine. But the problem is that CXF is returning Internal Server Error (HTTP 500). I would expect it to return 400 Bad Request because a wrong request is causing this. How can I change that?
DETAILS
The wrong request which produces the error above - there should be <soap:createOrder/> instead of <soap:createOrders/>.
POST http://localhost:8080/wst-server-1.0.0/services/soap/order
POST data:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://soap.ws.server.wst.fit.cvut.cz/">
<soapenv:Header/>
<soapenv:Body>
<soap:createOrders/>
</soapenv:Body>
</soapenv:Envelope>
[no cookies]
Request Headers:
Content-Length: 238
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded

I know maybe this is too late for the answer but another way to handle HTTP status code is using CXF interceptors.
you can add an interceptor in your server CXF configure
public class ServiceConfigurer implements CxfConfigurer {
#Override
public void configureServer(Server server) {
server.getEndpoint().getOutFaultInterceptors().add(new ChangingStatusCodeInterceptor();
}
}
and in your interceptor, you can change this
public class SaveInfluxDataInterceptor extends WSS4JOutInterceptor {
#Override
public void handleMessage(SoapMessage soapMessage) {
((Fault)exchange.get(Exception.class)).setStatusCode(202); // this is because of soap12OutFaultInterceptor look to this fault
// or you can use this
// exchange.getOutFaultMessage().put(Message.RESPONSE_CODE, 202);
}
}
I used Camel with CXF. maybe this solution should change in yours.

Related

How to handle soap:mustUnderstand header in Spring WS

An external system is sending my service a SOAP message and I have a listener in place
#Endpoint
public class NotificationListener {
private static final String NAMESPACE_URI = "http://test.com/test";
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "Notification")
#ResponsePayload
public void getSOAPMessage(#RequestPayload HistoryMessage request) {
// calls to methods in other classes which handle the business logic
}
The request body contains the following headers:
<soap:Header>
<wsa:To soap:mustUnderstand="1"
xmlns:wsa="http://www.w3.org/2005/08/addressing">{destination endpoint}
</wsa:To>
<wsa:From
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>
</wsa:From>
<wsa:ReplyTo
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>
</wsa:ReplyTo>
<wsa:FaultTo
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>
</wsa:FaultTo>
<wsa:Action soap:mustUnderstand="1"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
</wsa:Action>
<wsa:MessageID
xmlns:wsa="http://www.w3.org/2005/08/addressing">urn:uuid:fa163e6e-ef55-1eec-b9ac-5e80af1d126a
</wsa:MessageID>
I get the following error on calling my endpoint:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:MustUnderstand</faultcode>
<faultstring xml:lang="en">One or more mandatory SOAP header blocks not understood</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I understand that the mustUnderstand attribute in the header is set to 1 which means true and that header must be handled. But how do I handle it?
I'm using Spring WS to build the listener service.
TIA:)

Basic auth credentials using headers in soap on groovy

I'm trying to connect to WSDL server, which requires basic auth along with the body. I tried hitting with SOAPUI, and was able to do so. While working for the same in groovy and using wslite package for SOAP call, I'm getting error as "Password required".
I tried the tutorial on https://github.com/jwagenleitner/groovy-wslite, but the method described (in Usage block) didn't help.
I'm using groovy for this.
Below is the raw code from SOAP UI, with response 200OK
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:w="http://xmlns.oracle.com/Enterprise/Tools/schemas/W_CHKLST_CREATE_REQ.1">
<soapenv:Header><wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><wsse:UsernameToken wsu:Id="UsernameToken-83C962CC24EAB67F1D15586306447678"><wsse:Username>userName</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Password</wsse:Password><wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">JLTdeK6Yg3D64+2qz5xnbA==</wsse:Nonce><wsu:Created>2019-05-23T16:57:24.767Z</wsu:Created></wsse:UsernameToken></wsse:Security></soapenv:Header>
<soapenv:Body>
<w:helloWorld/>
</soapenv:Body>
</soapenv:Envelope>
which results in a 200OK from SOAPUI
HTTP/1.1 200 OK
Date: Wed, 22 May 2019 21:54:12 GMT
Content-Type: text/xml; charset=UTF-8
Content-Length: 3570
My Groovy Code,
def client = new SOAPClient("URL of WSDL")
def response = client.send(SOAPAction: "someAction",
connectTimeout:10000,
readTimeout:20000,
useCaches:false,
followRedirects:false) {
version SOAPVersion.V1_2 // SOAPVersion.V1_1 is default
soapNamespacePrefix "soapenv" // "soap-env" is default
envelopeAttributes "xmlns:ns":"http://example.weather.org"
header {
security("xmlns:ns20":"http://SecurityOpenXSD"){
"ns20:Username"("username")
"ns20:Password"("password")
}
}
body {
"ns:helloWorld" {
}
}
}
which gives soap xml as
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand='1'
xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>
<wsse:UsernameToken wsu:Id='UsernameToken-83C962CC24EAB67F1D15586299636605'>
<wsse:Username>userName</wsse:Username>
<wsse:Password
Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'>
password
</wsse:Password>
<wsse:Nonce
EncodingType='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary'>
JLTdeK6Yg3D64+2qz5xnbA==
</wsse:Nonce>
<wsu:Created>2019-05-23T10:07:52.913Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
But i get error as password required,
<?xml version="1.0" ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<Code><Value>SOAP-ENV:Receiver</Value></Code>
<Reason><Text>null</Text></Reason>
<Detail><IBResponse type="error" xmlns=""><DefaultTitle> Error Response</DefaultTitle>
<StatusCode>20</StatusCode>
<DefaultMessage><![CDATA[User Password required]]></DefaultMessage>
</IBResponse></Detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>

Customizing Spring Integration Web Service SOAP Envelope/Header

I am trying to send a SOAP request using Spring Integration like
<int:chain input-channel="wsOutChannel" output-channel="stdoutChannel">
<int-ws:header-enricher>
<int-ws:soap-action value="..."/>
</int-ws:header-enricher>
<int-ws:outbound-gateway
uri="..."/>
</int:chain>
but you can only add the SOAP body, and Spring Integration adds the envelope, header, and body tags like
<SOAP-ENV:Envelope>
<SOAP-ENV:Header>
<SOAP-ENV:Body>
...
</SOAP-ENV:Body>
<SOAP-ENV:Header>
</SOAP-ENV:Envelope>
I need to customize the envelope and header tags with specific attributes, for example:
<soapenv:Envelope attribute1="value1" attribute2="value2">
and child elements, for example:
<soapenv:Header>
<child>...<child>
<soapenv:Header>
Is this possible with Spring Integration Web Services, or should I not use int-ws:outbound-gateway and take a different approach?
You can add a ClientInterceptor (via the interceptor attribute) which allows you to modify the request before it's sent out.
EDIT
#Artem's suggestion is simpler but the interceptor gives you access to the response too; but either way, the code is similar.
For the interceptor:
public class MyInterceptor extends ClientInterceptorAdapter {
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
SoapMessage request = (SoapMessage) messageContext.getRequest();
SoapEnvelope envelope = request.getEnvelope();
envelope.addAttribute(new QName("foo"), "bar");
SoapHeader header = envelope.getHeader();
header.addHeaderElement(new QName("http://fiz/buz", "baz"));
return super.handleRequest(messageContext);
}
}
For the callback version:
#Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
SoapEnvelope envelope = ((SoapMessage) message).getEnvelope();
envelope.addAttribute(new QName("foo"), "bar");
SoapHeader header = envelope.getHeader();
header.addHeaderElement(new QName("http://fiz/buz", "baz"));
}
I thing you can inject WebServiceMessageCallback:
<xsd:attribute name="request-callback" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Reference to a Spring Web Services WebServiceMessageCallback. This enables changing
the Web Service request message after the payload has been written to it but prior
to invocation of the actual Web Service.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.ws.client.core.WebServiceMessageCallback"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
and cast the message to the SoapMessage and use its getEnvelope() to customize a desired way.

Moodle: Invalid parameter exception

I'm trying to make a
http://domain.com/webservice/rest/server.php?wstoken=4725a345345435342322a6560b068547297748e17&wsfunction=mod_forum_get_forum_discussions_paginated
with post data:
{
"forumid":2438
}
Headers:
Accept: application/json
Content-Type: application/json
But I get the error:
<?xml version="1.0" encoding="UTF-8" ?>
<EXCEPTION class="invalid_parameter_exception">
<ERRORCODE>invalidparameter</ERRORCODE>
<MESSAGE>Invalid parameter value detected</MESSAGE>
</EXCEPTION>
I have my moodle session as a cookie. What am I doing wrong here?
Maybe try putting forumid in the url?
http://domain.com/webservice/rest/server.php?forumid=2438&wstoken=4725a345345435342322a6560b068547297748e17&wsfunction=mod_forum_get_forum_discussions_paginated
https://tracker.moodle.org/browse/MDL-46458

Spring Integration should route Message (with SOAP Headers)

I am trying to write configure a gateway, which should take a complete SOAP Message and then delegate it to another SOAP Provider (incl. all SOAP headers of the first request).
What I have done so far:
1) web.xml
MessageDispatcherServlet with Mapping:
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/appservices/*</url-pattern>
</servlet-mapping>
2) Configuration with an Endpoint-Mapping
<bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
<property name="defaultEndpoint" ref="ws-in-gw"/>
</bean>
3) Configuration of Spring Integration inbound-gateway and outbound-gateway
<int-ws:inbound-gateway id="ws-in-gw"
request-channel="in"
reply-channel="out"
mapped-request-headers="*" />
<int:channel id="in" />
<int:channel id="out" />
<int-ws:outbound-gateway
id="ws-out-gw-status"
request-channel="in-status"
reply-channel="out-status"
uri="http://${delegationServer}/${delegation.contextroot}/soap/AnotherService"
interceptor="soapEnricher"
</int-ws:outbound-gateway>
<bean id="soapEnricher" class="foo.bar.SoapHeaderEnricher" />
public class SoapHeaderEnricher implements ClientInterceptor {
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
try {
SoapMessage soapMessage = (SoapMessage) messageContext.getRequest();
SoapHeader sh = soapMessage.getSoapHeader();
// can use sh.addHeaderElement(new QName(...)) now, but where are the original Headers???
} catch () {
}
}
My first Problem was, that the original SOAP Headers had been cut of, so I introduced the ' mapped-request-headers="*" ' attribute at the inbound gateway.
When I now configure a wire-tap, I see the Headers (myToken:MySecretToken) are received:
DEBUG 10:46:53 - [Payload DOMSource content=javax.xml.transform.dom.DOMSource#24a6ce98][Headers={errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel#43456ff4, myToken:MySecretToken=org.springframework.ws.soap.saaj.SaajSoapHeaderElement#3b91ead, ...}]
This is the SOAP Message for my test:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:stat="http://status.service.promakler.provinzial.com/">
<soapenv:Header>
<myToken:MySecretToken xmlns=""
xmlns:myToken="http://foo.bar">12345</myToken:MySecretToken>
</soapenv:Header>
<soapenv:Body>
<stat:getStatus/>
</soapenv:Body>
</soapenv:Envelope>
So the Headers are now in my Message, but in the ClientInterceptor, there is no way to get the Headers (just the payload)?! I can add new Headers, but how can I get the original Header?
Can anybody give me a hint (or perhaps there is even a quiet simpler solution??)
Regards
Timo
Try to introduce a custom extension of DefaultSoapHeaderMapper and override populateUserDefinedHeader to extract those SaajSoapHeaderElement from the MessageHeaders and populate them to the SoapHeader. And finally inject your solution to the header-mapper of your <int-ws:outbound-gateway>.