Read SOAP request header with Spring - java

I am trying to read the SOAP request header from a endpoint in spring this way:
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
#ResponsePayload
public GetCountryResponse getCountry(#RequestPayload GetCountryRequest request, MessageContext context) {
GetCountryResponse response = new GetCountryResponse();
response.setCountry(countryRepository.findCountry(request.getName()));
return response;
}
As you can see I have the MessageContext as a parameter in the handle method of the endpoint and I do the following in order to try to read the SOAP header coming from te request:
SaajSoapMessage soapRequest = (SaajSoapMessage) messageContext.getRequest();
SoapHeader reqheader = soapRequest.getSoapHeader();
while (itr.hasNext()) {
SoapHeaderElement ele = itr.next();
}
Apparently I am getting access to the SOAP header, but at this point I´m not really sure how to read the value of any SOAP header element, I´ve tried different approaches with no success.
For example, if the following SOAP request is coming from the soapUI I want to read the value 123456 from networkCode element:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<ns1:RequestHeader
soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next"
soapenv:mustUnderstand="0"
xmlns:ns1="https://www.google.com/apis/ads/publisher/v201508">
<ns1:networkCode>123456</ns1:networkCode>
<ns1:applicationName>DfpApi-Java-2.1.0-dfp_test</ns1:applicationName>
</ns1:RequestHeader>
</soapenv:Header>
<soapenv:Body>
<getAdUnitsByStatement xmlns="https://www.google.com/apis/ads/publisher/v201508">
<filterStatement>
<query>WHERE parentId IS NULL LIMIT 500</query>
</filterStatement>
</getAdUnitsByStatement>
</soapenv:Body>
</soapenv:Envelope>
Thanks in advance and best reards.

Yoy can you QName to extract data by using necessary tag
SaajSoapMessage soapRequest = (SaajSoapMessage) messageContext
.getRequest();
SoapHeader reqheader = soapRequest.getSoapHeader();
Iterator<SoapHeaderElement> itr = reqheader.examineAllHeaderElements();
while (itr.hasNext()) {
SoapHeaderElement testedElement = itr.next();
if (testedElement.getName()
.equals(new QName("https://www.google.com/apis/ads/publisher/v201508", "networkCode", "ns1"))) {
this.messageId = testedElement.getText();
break;
}
}

In SoapUI using Script assertion,we can do this:
As your request itself contains the Header Details, we can read any element of your Request xml using xpath.
Replace the TeststepName with your TestStepName.
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def holder = groovyUtils.getXmlHolder( "TeststepName#Request" )
holder.namespaces["ns1"] = "https://www.google.com/apis/ads/publisher/v201508"
def y = holder["(//ns1:networkCode)"]
log.info "Value of networkCode"+ y
or
assert holder["(//ns1:networkCode)"]=='123456'

please try to get all the Header element from the Your Request like:
SaajSoapMessage soapRequest = (SaajSoapMessage) messageContext.getRequest();
Iterator HeaderList = soapRequest.getEnvelope().getHeader().examineAllHeaderElements();
while (HeaderList.hasNext()) {
SoapHeaderElement HeaderElements = HeaderList.next();
println("\n"+HeaderElements.getName().getLocalPart()+ " - "+HeaderElements.getText());
}
}

Related

How to retrieve From/Address value in SOAP header (in Java/SpringBoot)

I'm trying to create a Spring Boot SOAP application using this tutorial: https://www.baeldung.com/spring-boot-soap-web-service Everything works like a charm so far.
Task: I'd like to access the SOAP header.
This is what I've done so far:
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
#ResponsePayload
public GetCountryResponse getCountry(#RequestPayload GetCountryRequest request) {
[..]
}
I can just extend this with MessageContext:
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
#ResponsePayload
public GetCountryResponse getCountry(#RequestPayload GetCountryRequest request, MessageContext messageContext) {
[..]
}
This MessageContext plus a little util method fooBar is supposed to access the SOAP header:
protected static String fooBar(final MessageContext messageContext) {
SoapHeader soapHeader = ((SoapMessage) messageContext.getRequest()).getSoapHeader();
[...]
}
So far so good. This is what my SOAP message looks like:
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
[...]
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<soap:Header>
[...]
<wsa:From>
<wsa:Address>http://from-endpoint</wsa:Address>
</wsa:From>
[...]
</soap:Header>
<soap:Body>
[...]
</soap:Body>
</soap:Envelope>
I would like to get the address in <From><Address>: http://from-endpoint .. but now it starts to get awkward..
protected static String fooBar(final MessageContext messageContext) {
SoapHeader soapHeader = ((SoapMessage) messageContext.getRequest()).getSoapHeader();
Iterator<SoapHeaderElement> soapHeaderElementIterator = soapHeader.examineAllHeaderElements();
while (soapHeaderElementIterator.hasNext()) {
SoapHeaderElement soapHeaderElement = soapHeaderElementIterator.next();
if (soapHeaderElement.getName().getLocalPart().equals("From")) {
[...]
This works as expected, but this SoapHeaderElement is type org.springframework.ws.soap.SoapHeaderElement which gives me no options to access further child elements.
What am I doing wrong here?
...
...
...
✅ SOLUTION has been found - see comments
Thanks to help of M. Deinum I've found a solution:
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
#ResponsePayload
public GetCountryResponse getCountry(#RequestPayload GetCountryRequest request, MessageContext messageContext) {
Addressing10 addressing10 = new Addressing10();
MessageAddressingProperties messageAddressingProperties = addressing10.getMessageAddressingProperties((SoapMessage) messageContext.getRequest());
URI address = messageAddressingProperties.getFrom().getAddress();
}

Spring WS: Add custom SOAP header

What's my goal?
I'm rather new to Spring WS, I got a WSDL (and along some XSDs, ofcourse) and i want to add some custom header elements to the SOAP response.
I've been searching the web, tried various code pieces, but it's all without any luck... nothing seems to work properly .
What's the problem?
The response SOAP message has a body what spring calls a Payload and my SOAP client (SOAPUI) receives the response rather well.
But here it comes: how should I add new (custom) SOAP headers to the response message?
What's the response xml expected?
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<aud:HeaderInfo xmlns:bd="http://www.myws.com/">
<bd:ID>123</bd:ID>
<bd:Type>text</bd:Type>
</aud:HeaderInfo>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ne:myWS xmlns:ne="http://www.iways.com/">
<ne:INFO>
<ne:NAME>JOHN</ne:NAME>
<ne:DESIGNATION>ITA</ne:DESIGNATION>
<ne:MOBILE>9841011113</ne:MOBILE>
</ne:INFO>
</ne:myWS>
My payload
#PayloadRoot(localPart = "myWSRequest", namespace = TARGET_NAMESPACE)
public #ResponsePayload myWSResponse getInfo(#RequestPayload myWSRequest request)
{
myWSResponse response = new myWSResponse();
Person person = personService_i.getAccountDetails(request.getID());
response.setPersonDetails(person);
return response;
}
Any side info?
i use xsd which generates a load of classes based upon the XSDs I don't know how to add those custom headers to the response message,
You could implement a endpointInterceptorAdapter and do the following:
public final class MyEndpointInterceptorAdapter extends EndpointInterceptorAdapter {
#Override
public boolean handleResponse(MessageContext messageContext_, Object endpoint_)
throws IOException {
WebServiceMessage _webServiceMessage = messageContext_.getResponse();
SoapMessage _soapMessage = (SoapMessage) _webServiceMessage;
if (_soapMessage != null) {
SoapEnvelope _soapEnvelope = _soapMessage.getEnvelope();
// create your qname object
QName _myQName = ....
// adding your quname to the header
_soapEnvelope.getHeader().addHeaderElement(myQName );
}
}
}
and in your spring configuration file, just add the interceptor:
<sws:interceptors>
<ref bean="myEndpointInterceptorAdapter"/>
</sws:interceptors>

Spring WS Endpoint extract SOAP info

After reading doc on the Spring web site, still confused about how to extract information from a SOAP request.
For example, the SOAP request sent to server is like:
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:user="http://www.mysite.com/user/schemas">
<soapenv:Header/>
<soapenv:Body>
<user:UserRequest>
<!--You may enter the following 4 items in any order-->
<user:Key>key</user:Key>
<user:UserName>username</user:UserName>
<user:RequesterName>reqname</user:RequesterName>
<user:RequesterPassword>repw</user:RequesterPassword>
</user:UserRequest>
</soapenv:Body>
</soapenv:Envelope>
On my server side I create an Endpoint like:
#Endpoint
public class UserEndpoint {
private static final String NAMESPACE_URI = "http://www.mysite.com/user/schemas";
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "UserRequest")
public void handleGetUserRequest() {
//Extract here...
}
}
How should I write extraction code here?
I would suggest having a look at the Spring WS samples for code ideas, depending on what else you are using in your application. For example: the HolidayEndpoint source code.
#Endpoint("myEndpoint")
public class MyEndpoint {
/**
* Spring-WS Endpoint
* #param submitSomethingRequest
* #param header
* #return SubmitSomethingResponse
*/
#PayloadRoot(namespace="http://my.namespace.org/spec/1.0.1", localPart="submitSomethingRequest")
#ResponsePayload
public SubmitSomethingResponse submitSomethingRequest(#RequestPayload SubmitSomethingRequest submitSomethingRequest, **SoapHeader header**) {
LOG.info("Received SOAP HEADER: " + header);
if(header != null) {
Iterator<SoapHeaderElement> hdrs = header.examineAllHeaderElements();
while(hdrs.hasNext()) {
SoapHeaderElement hdrEle = hdrs.next();
System.out.prinltn(hdrEle.getName().getPrefix() + ":" + hdrEle.getName().getLocalPart());
... //Do something here to parse DOM and extract headers you care about
}
}
...

Spring WS - unable to return a JAXB response

As described in this tutorial: http://docs.spring.io/spring-ws/site/reference/html/tutorial.html
I have a Spring WS method which receives a request:
#PayloadRoot(localPart = "HolidayRequest", namespace = NAMESPACE_URI)
#Namespace(prefix = "hr", uri= NAMESPACE_URI )
#ResponsePayload
public void handleHolidayRequest(#XPathParam("//hr:HolidayRequest") Object request) throws Exception {
}
and I can read the values passed in. Now if I try to send a response:
#PayloadRoot(localPart = "HolidayRequest", namespace = NAMESPACE_URI)
#Namespace(prefix = "hr", uri= NAMESPACE_URI )
#ResponsePayload
public HolidayResponse handleHolidayRequest(#XPathParam("//hr:HolidayRequest") Object request) throws Exception {
}
HolidayResponse response = new HolidayResponse(); // JAXB object
response.setIsApproved( false );
response.setEmpId( BigInteger.ONE );
return response;
The SOAP client receives a fault response:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring xml:lang="en">javax.xml.bind.JAXBException
- with linked exception:
[java.lang.NullPointerException]</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Any ideas what I might be doing wrong?
NOTE: I have tried wrapping the response:
return new JAXBElement( new QName("HolidayResponse"), HolidayResponse.class, response );

How to properly format a SOAP message envelope using a custom SOAPHandler

I have a class that implements the SOAPHandler interface. The handleMessage is defined as:
public boolean handleMessage(SOAPMessageContext context) {
SOAPMessage msg = context.getMessage();
SOAPPart part = msg.getSOAPPart();
SOAPEnvelope envelope = part.getEnvelope();
// add namespaces
SOAPElement envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-
// add the header with additional elements
Name qname = envelope.createName("Security", "sse", "http://example.com/security.xsd");
element = envelope.addHeader().addChildElement(qname);
qname = envelope.createName("mustUnderstand");
element.addAttribute(qname, "1");
qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = envelope.getHeader().addHeaderElement(qname);
element.addTextNode("user1");
qname = envelope.createName("Password");
element = envelope.getHeader().addHeaderElement(qname);
element.addTextNode("1234");
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
This generates the following message:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<S:Header>
<sse:Security xmlns:sse="http://example.com/security.xsd" mustUnderstand="1"/>
<sse:UsernameToken xmlns:sse="http://example.com/user.xsd">user1</sse:UsernameToken>
</S:Header>
<S:Body>
....The rest of the transaction
</S:Body>
</S:Envelope>
The problem is I need to generate a message with the following format:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<sse:Security soapenv:mustUnderstand="1" xmlns:sse="http://example.com/security.xsd">
<sse:UsernameToken wsu:Id="UsernameToken-9993341" xmlns:wsu="http://example.com/user.xsd">
<sse:Username>user1</sse:Username>
<sse:Password Type="http://example.com/password#PasswordText">1234</sse:Password>
</sse:UsernameToken>
</sse:Security>
</soapenv:Header>
<soapenv:Body>
....The rest of the transaction
</soapenv:Body>
</soapenv:Envelope>
The "mustUnderstand" attribute doesn't have the soapenv prefix, the sse:Security tag is closed right away instead of having the other tags as children, and the UserName isn't properly formatted as
<sse:Username>user1</sse:Username>
. How can I format the message properly using the SOAPElement methods? The biggest thing I need to know is how to properly next the tags inside of the Security tag and how to have the username/password tags properly formatted.
I've tried different combinations of the addHeaderElement and addChildElement methods, but I can't get it formatted properly and the javadocs don't give enough detail about what they will generate.
This is taken from my working handler. Hope it works for you.
public static final String WSSE_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
public static final String PASSWORD_TEXT_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
public static final String WSSE_SECURITY_LNAME = "Security";
public static final String WSSE_NS_PREFIX = "wsse";
private String username;
private String password;
private boolean mustUnderstand = false;
public boolean handleMessage(SOAPMessageContext messageContext) {
Object bOutbound = messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (bOutbound == Boolean.TRUE) {
try {
if (username != null && username.length() != 0) {
addSecurityHeader(messageContext);
LOG.debug("Added security header");
} else {
LOG.debug("No username configured thus not adding a security header");
}
} catch (Exception e) {
LOG.error("Exception in handleMessage", e);
return false;
}
}
return true;
}
private void addSecurityHeader(SOAPMessageContext messageContext) throws SOAPException {
SOAPFactory sf = SOAPFactory.newInstance();
SOAPHeader header = messageContext.getMessage().getSOAPPart().getEnvelope().getHeader();
if (header == null) {
header = messageContext.getMessage().getSOAPPart().getEnvelope().addHeader();
}
Name securityName = sf.createName(WSSE_SECURITY_LNAME, WSSE_NS_PREFIX, WSSE_NS);
SOAPHeaderElement securityElem = header.addHeaderElement(securityName);
securityElem.setMustUnderstand(mustUnderstand);
Name usernameTokenName = sf.createName("UsernameToken", WSSE_NS_PREFIX, WSSE_NS);
SOAPElement usernameTokenMsgElem = sf.createElement(usernameTokenName);
Name usernameName = sf.createName("Username", WSSE_NS_PREFIX, WSSE_NS);
SOAPElement usernameMsgElem = sf.createElement(usernameName);
usernameMsgElem.addTextNode(username);
usernameTokenMsgElem.addChildElement(usernameMsgElem);
Name passwordName = sf.createName("Type", WSSE_NS_PREFIX, WSSE_NS);
SOAPElement passwordMsgElem = sf.createElement("Password", WSSE_NS_PREFIX, WSSE_NS);
passwordMsgElem.addAttribute(passwordName, PASSWORD_TEXT_TYPE);
passwordMsgElem.addTextNode(password);
usernameTokenMsgElem.addChildElement(passwordMsgElem);
securityElem.addChildElement(usernameTokenMsgElem);
}
Just posting my solution if someone is still wondering --
Name name = soapenv.createName("Security", "sse", "URL");
SOAPHeaderElement security = soapenv.getHeader().addHeaderElement(name);
security.setMustUnderstand(true);
SOAPElement usernameToken = security.addChildElement("UsernameToken", "sse");
SOAPElement username = usernameToken.addChildElement("Username", "sse");
username.addTextNode("TestUser");
SOAPElement password = usernameToken.addChildElement("Password", "sse");
password.addTextNode("TestPassword");
There's enough problems in this code that I'm thinking it's a troll, but heres a start:
The line :
element = envelope.addHeader().addChildElement(qname);
should read:
SOAPHeaderElement secHdrElement = envelope.addHeader().addHeaderElement(qname);
next, instead of:
qname = envelope.createName("mustUnderstand");
element.addAttribute(qname, "1");
probably:
secHdrElement.setMustUnderstand(true);
and
qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = envelope.getHeader().addHeaderElement(qname);
element.addTextNode("user1");
should be something like:
qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = secHdrElement.addHeaderElement(
envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd"));
and so on...

Categories

Resources