Getting content of a SOAP Header using Spring WS - java

I'm trying to build an endpoint that will receive SOAP messages from a client. The message I'm receiving contains a username and password inside the soap header ...
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://www.company.com/Application">
<soapenv:Header xmlns:wsse="http://__________.xsd">
<wsse:Security >
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
I'm using Spring WS - the obvious solution is to create a filter inside web.xml that will bypass Spring WS completely, parse the SOAP message, extract the username and password and then continue to Spring WS which will parse the SOAP again.
Is there a way to get the content of the header without circumventing Spring WS?
I've tried adding a bean inside sws:interceptors:
<sws:interceptors>
<!-- extract Security details from Header -->
<bean class="com.company.application.service.SecurityInterceptorService" />
<!-- log full Body of request -->
<bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
<!-- validate Request against XSD to make sure it's a valid request -->
<bean id="CompanyApplication" class="com.company.application.interceptor.ValidatingInterceptor">
<property name="schema" value="/WEB-INF/_______________.xsd" />
<property name="validateRequest" value="true" />
<property name="validateResponse" value="true" />
</bean>
</sws:interceptors>
and then implementing that class:
public class SecurityInterceptorService implements EndpointInterceptor {
#Override
public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
System.out.println("---------------");
System.out.println("handleRequest") ;
System.out.println("---------------");
return true;
}
#Override
public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
System.out.println("---------------");
System.out.println("handleResponse");
System.out.println("---------------");
return true;
}
#Override
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
System.out.println("---------------");
System.out.println("handleFault");
System.out.println("---------------");
return true;
}
#Override
public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception {
System.out.println("---------------");
System.out.println("afterCompletion");
System.out.println("---------------");
}
}
endpoint only contains data about the endpoint inside handleRequest and after traversing through many layers and layers inside messageContext while in debug mode, I can't seem to spot the content of the header.
Is the content I'm looking for inside messageContext and if so, how do I access it?

From the messageContext object, you can retrieve either the request or the response (In your case, I guess you need the request).
The request/response is basically a WebServiceMessage. If you examine the webServiceMessage, you will see that the object can be casted to a SoapMessage. From the soap message, you can now get the soap header.
WebServiceMessage webServiceMessageRequest = messageContext_.getRequest();
SoapMessage soapMessage = (SoapMessage) webServiceMessageRequest;
SoapHeader soapHeader = soapMessage.getSoapHeader()
Afterwards, You might want to get the source object and convert it to a DOMSource object and then get the Node object which make the information retrieval much easier.
Source bodySource = soapHeader .getSource();
DOMSource bodyDomSource = (DOMSource) bodySource;
Node bodyNode = _bodyDomSource.getNode();

If you are using spring-boot you can use this kind of configuration:
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
#Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
PayloadValidatingInterceptor validatingInterceptor = new PayloadValidatingInterceptor();
validatingInterceptor.setValidateRequest(true);
validatingInterceptor.setValidateResponse(true);
validatingInterceptor.setXsdSchema(resourceSchema());
interceptors.add(validatingInterceptor);
}
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/api/*");
}
#Bean(name = "registros")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("ResourcePort");
wsdl11Definition.setLocationUri("/api");
wsdl11Definition.setTargetNamespace("http://resource.com/schema");
wsdl11Definition.setSchema(resourceSchema());
return wsdl11Definition;
}
#Bean
public XsdSchema resourceSchema() {
return new SimpleXsdSchema(new ClassPathResource("registro.xsd"));
}
}
In this example the addInterceptors method is the important one, the others 3 are basic to expose a WSDL API.
Maybe it'll be useful for someone else.

There is no easy way to unmarshall Soap headers with Spring-ws (it's currently not supported)
However, you can access the SoapHeaderElement in your #PayloadRoot annotated method, and do the process of unmarshalling with JAXB.
#Endpoint
public class SubmitEndpoint implements EndpointInterface {
private static final String NAMESPACE_URI = "http://www.example.com/namespace";
private Security unmarshallSecurityFromSoapHeader(SoapHeaderElement header) {
Security security = null;
try {
JAXBContext context = JAXBContext.newInstance(Security.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
security = (Security) unmarshaller.unmarshal(header.getSource());
} catch (JAXBException e) {
e.printStackTrace();
}
return security;
}
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "submit")
#ResponsePayload
public SubmitResponse submit(#RequestPayload Submit submit, #SoapHeader(
value = "{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security") SoapHeaderElement wsseSecurityHeader) throws JAXBException {
Security security = unmarshallSecurityFromSoapHeader(wsseSecurityHeader);
}
}
Security.java
#Getter
#Setter
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(namespace = Security.SECURITY_NS, name = "Security")
public class Security {
public static final String SECURITY_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
#XmlElement(namespace = SECURITY_NS, name = "UsernameToken")
private UsernameToken usernameToken;
}
UsernameToken.java
#Getter
#Setter
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(namespace = Security.SECURITY_NS, name = "UsernameToken")
public class UsernameToken {
#XmlElement(name = "Username", namespace = Security.SECURITY_NS)
private String username;
#XmlElement(name = "Password", namespace = Security.SECURITY_NS)
private String password;
}

Related

Retreiving the SOAP message context from inside the service endpoint

I have a spring boot application which expose SOAP web service using spring-boot-starter-web-services.
I'am getting the request's messageContext using EndpointInterceptor
#Component
public class GlobalEndpointInterceptor implements EndpointInterceptor {
#Override
public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
//Here I get the messageContext
}
}
In my service EndPoint I have :
#Endpoint
public class CountryEndpoint {
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "addCountryRequest")
#ResponsePayload
public AddCountryResponse addCountry(#RequestPayload AddCountryRequest request) {
//Insert country and get the autogenerated ID
//Insert the country ID along with the messageContext retreived from the intercepter. I can't get the messageContext here !
}
}
How can I retreive the message context inside my service endpoint
You can do the following to get the SOAP Envelope:
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "addCountryRequest")
#ResponsePayload
public AddCountryResponse addCountry(#RequestPayload AddCountryRequest request, MessageContext context) {
//Insert country and get the autogenerated ID
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
messageContext.getRequest().writeTo(outputStream);
String httpMessage = new String(outputStream.toByteArray());
System.out.println(httpMessage);
} catch (IOException e) {
e.printStackTrace();
}
}

CXF webservice : interceptor not triggered

We currently have a problem with CXF 2.7.3 on Jboss EAP 6.2 with a custom SoapFault exception.
The Subcode and its value is not displayed when we send a custom SoapFault:
Here is what we want from cxf:
<?xml version="1.0" encoding="UTF-8"?>
<tns:Fault
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tns="http://www.w3.org/2003/05/soap-envelope">
<tns:Code>
<tns:Value>tns:Sender</tns:Value>
<tns:Subcode>
<tns:Value>value</tns:Value>
</tns:Subcode>
</tns:Code>
<tns:Reason>
<tns:Text xml:lang="fr">
****
</tns:Text>
</tns:Reason>
<tns:Detail>
**Custom fault***
</tns:Detail>
</tns:Fault>
Here is what we have so far:
<?xml version="1.0" encoding="UTF-8"?>
<tns:Fault
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tns="http://www.w3.org/2003/05/soap-envelope">
<tns:Code>
<tns:Value>tns:Sender</tns:Value>
</tns:Code>
<tns:Reason>
<tns:Text xml:lang="fr">
****
</tns:Text>
</tns:Reason>
<tns:Detail>
**Custom fault***
</tns:Detail>
</tns:Fault>
The subcode is completely missing.
We tried to use a custom interceptor (extending from LoggingOutInterceptor or AbstractInterceptor) from CXF like this to intercept the custom fault:
public class SoapRequestInterceptor extends LoggingOutInterceptor {
private static Logger log = Logger.getLogger(SoapRequestInterceptor.class);
public SoapRequestInterceptor() {
super(Phase.MARSHAL);
}
public void handleMessage(SoapMessage message) throws Fault{
SoapMessage soapMessage = message.getContent(SoapMessage.class);
if (soapMessage != null) {
log.info( "request intercepted:" + soapMessage.toString());
}
}
}
The interceptor is not even called when we add him either to CXF bus or to jaxws interceptor (it’s added at the start of the application though since it gets through the constructor).
How can we intercept a custom soap Fault message and edit it in CXF?
Thanks a lot!
As asked here's the way we declare the interceptor in spring applicationContext.xml :
<cxf:bus>
<cxf:outFaultInterceptors>
<ref bean="soapRequestInterceptor" />
</cxf:outFaultInterceptors>
</cxf:bus>
<bean id="soapRequestInterceptor" class="fr.test.SoapRequestInterceptor" />
<jaxws:server serviceClass="fr.test.PriseEnChargeB2ServiceSP"
address="" serviceBean="#service">
<jaxws:binding>
<soap:soapBinding version="1.2" mtomEnabled="true" />
</jaxws:binding>
</jaxws:server>
Note : the interceptor is well instancied, but not called after a soap fault throw from our WS
The exception thrown at the end of our WS is this one :
public class PecSoapFaultException extends SoapFault {
private static final long serialVersionUID = 1L;
public TypeErreur erreur;
public PecSoapFaultException(String message, TypeErreur structure) {
super(message, new QName(""));
this.erreur = structure;
}
public PecSoapFaultException(String message, TypeErreur structure, QName faultcode) {
super(message, faultcode);
this.erreur = structure;
}
public PecSoapFaultException(String message, TypeErreur structure, QName faultcode,
QName subcode) {
super(message, faultcode);
this.setSubCode(subcode);
this.erreur = structure;
}
public TypeErreur getFaultInfo() {
return erreur;
}
The problem that your interceptor is not called is that you do not override the correct method. You should have your code like this:
#Override
public void handleMessage(Message message) throws Fault {
SoapMessage soapMessage = message.getContent(SoapMessage.class);
if (soapMessage != null) {
log.info( "request intercepted:" + soapMessage.toString());
}
}
Then your interceptor will be called. But as I said in my comment: in case of a fault the soapmessage is null. So you won't get any output in your log.

How to build SOAP client in Spring?

I am able to send requests to the web service using javax.xml.soap.*, I would like to covert the code to use webServiceTemplate.
I am struggling with creating request and result objects. (sample Ive found is related to xml not SOAP)
I am also wondering if there is any advantages of using
webServiceTemplate over java.xml.soap. If there is not am I doing it correctly? Given that I need to get connected to 20 web services.
The only service it has is findEvents as follows:
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://ticketmaster.productserve.com/v2/soap.php" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<soapenv:Header/>
<soapenv:Body>
<soap:findEvents soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<request xsi:type="soap:Request">
<!--You may enter the following 7 items in any order-->
<apiKey xsi:type="xsd:string">?</apiKey>
<country xsi:type="xsd:string">?</country>
<resultsPerPage xsi:type="xsd:int">?</resultsPerPage>
<currentPage xsi:type="xsd:int">?</currentPage>
<sort xsi:type="soap:Request_Sort">
<!--You may enter the following 2 items in any order-->
<field xsi:type="xsd:string">?</field>
<order xsi:type="xsd:string">?</order>
</sort>
<filters xsi:type="soap:ArrayOfRequest_Filter" soapenc:arrayType="soap:Request_Filter[]"/>
<updatedSince xsi:type="xsd:string">?</updatedSince>
</request>
</soap:findEvents>
</soapenv:Body>
</soapenv:Envelope>
My code is as follows:
try {
SOAPConnectionFactory soapConnectionFactory =
SOAPConnectionFactory.newInstance();
SOAPConnection connection =
soapConnectionFactory.createConnection();
MessageFactory factory =
MessageFactory.newInstance();
SOAPMessage message = factory.createMessage();
SOAPHeader header = message.getSOAPHeader();
header.detachNode();
SOAPBody body = message.getSOAPBody();
SOAPFactory soapFactory =
SOAPFactory.newInstance();
Name bodyName;
bodyName = soapFactory.createName("findEvents",
"xsd", "http://ticketmaster.productserve.com/v2/soap.php");
SOAPBodyElement getList =
body.addBodyElement(bodyName);
Name childName = soapFactory.createName("findEvents");
SOAPElement eventRequest = getList.addChildElement(childName);
childName = soapFactory.createName("apiKey");
SOAPElement apiKey = eventRequest.addChildElement(childName);
apiKey.addTextNode("MYAPI");
childName = soapFactory.createName("country");
SOAPElement cid = eventRequest.addChildElement(childName);
cid.addTextNode("UK");
message.writeTo(System.out); //show message details
URL endpoint = new URL("http://ticketmaster.productserve.com/v2/soap.php");
SOAPMessage response =
connection.call(message, endpoint);
connection.close();
//SOAPBody soapBody = response.getSOAPBody();
SOAPMessage sm = response;
System.out.println("Response:");
ByteArrayOutputStream out = new ByteArrayOutputStream();
sm.writeTo(out);
String validSoap = "<?xml version=\"1.0\"?> " + out.toString();
System.out.println("It is ValidSoap: " + validSoap); //ValidSoap message
SAXBuilder builder = new SAXBuilder();
Reader in = new StringReader(validSoap); //reading character stream
Document doc = null; //empty jDom document is instantiated
doc = builder.build(in); //build the jDom document
Element root = doc.getRootElement(); //Envelope
List allChildren = root.getChildren(); //list of all its child elements
System.out.println("Root is:" + ((Element) allChildren.get(0)).getName());
listChildren(root);
} catch (Exception ex) {
ex.printStackTrace();
}
New Code
webServiceTemplate.sendSourceAndReceiveToResult
("http://ticketmaster.productserve.com/v2/soap.php",source, result);
#XmlRootElement
public class FindEvents {
#XmlElement
Request request;
public Request getRequest() {
return request;
}
public void setRequest(Request request) {
this.request = request;
}
}
#XmlSeeAlso(SortTicket.class)
public class Request {
#XmlElement
String apiKey;
#XmlElement
String country;
#XmlElement
int resultsPerPage;
#XmlElement
int currentPage;
#XmlElement(name = "Sort")
SortTicket sort;
#XmlElement
String[] filters;
#XmlElement
String updatedSince;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public int getResultsPerPage() {
return resultsPerPage;
}
public void setResultsPerPage(int resultsPerPage) {
this.resultsPerPage = resultsPerPage;
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public SortTicket getSort() {
return sort;
}
public void setSort(SortTicket sort) {
this.sort = sort;
}
public String[] getFilters() {
return filters;
}
public void setFilters(String[] filters) {
this.filters = filters;
}
public String getUpdatedSince() {
return updatedSince;
}
public void setUpdatedSince(String updatedSince) {
this.updatedSince = updatedSince;
}
}
public class SortTicket {
#XmlElement
String field;
#XmlElement
String order;
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getOrder() {
return order;
}
public void setOrder(String order) {
this.order = order;
}
}
Since you have generated DTO classes with Jaxb annotation you can create a marshaller ,unmarshaller and create objects of the DTO classes (SortTicket,Request,FindEvents) and send the objects directly instead of using the xml request
webServiceTemplate.marshalSendAndReceive(findEvents);
Something like this you'll have to configure.
Create a marshaller
<oxm:jaxb2-marshaller id="marshaller" contextPath="com.yourcontextpath" />
create web service template
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="marshaller" />
<property name="defaultUri"
value="http://ticketmaster.productserve.com/v2/soap.php" />
</bean>
and in some class's method where you want to send soap request inject webServiceTemplate using #Autowired
#Autowired
private WebServiceTemplate webServiceTemplate;
public void sendSampleSoapRequest() {
SortTicket sortTicket=new SortTicket();
// set its values
Request request=new Request();
//set its values
request.setSort(sortTicket);
FindEvents findEvents=new FindEvents();
setRequest(request)
Object response=webServiceTemplate.marshalSendAndReceive(findEvents);
}
marshalSendAndReceive message uses the Jaxb marshaller to convert your objects (marked with JaxB annotation)to xml.So above your findEvents object will be converted to its xml from.
Regarding your second point
Advantages of using webServiceTemplate over java.xml.soap. : you don't have to create those SOAPElements manually you just create an object and send it instead of big code for manually handling it.
Since you'll have to connect to 20 different web services it will be much easier for you to create DTO objects and send them directly.You may need to modify my above samples a little.May remove the deault uri
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="marshaller" />
</bean>
and while sending request give the URI request
Object response=webServiceTemplate.marshalSendAndReceive(uri,object);
For sending it to multiple server
Object response1=webServiceTemplate.marshalSendAndReceive(uri1,object);
Object response1=webServiceTemplate.marshalSendAndReceive(uri2,object)
uri1 and uri2 can be different soap service And if you don't have the wsdl you can send xml with this method
sendSourceAndReceiveToResult(uri1,source, result);
sendSourceAndReceiveToResult(uri2,source, result);
Sending a uri in the send method over rides the default URI
For example check this also check the api doc

Adding elements in SOAP Header request for authentication

I need to incorporate an authentication header (i.e. as a part of SOAP header request) in my new web service. That authentication header will verify the userId and password details. I have to verify the content of request header details for authentication in my Web Service. If authenticated, then the SOAP body of the request will be processed, else Invalid Authentication message will be send back by the Web Service to the client application invoking the service.
I am not able to understand how to create a web service where the SOAP Header will contain some elements(in my case, authentication elements such as userId and password).
Normally, whatever method exposed in the service will come as a part of the SOAP Body. Hence confused how to proceed with adding authentication elements in the SOAP Header.
Please help
Regards,
Recently I have wrote a class which adds user credentials to SOAP header. To do that you need to create a class which implements SOAPHandler<SOAPMessageContext> interface. For e.g.:
public class MyHandler implements SOAPHandler<SOAPMessageContext> {
private static final Logger LOGGER = LoggerFactory.getLogger(MyHandler.class);
private String username;
private String password;
/**
* Handles SOAP message. If SOAP header does not already exist, then method will created new SOAP header. The
* username and password is added to the header as the credentials to authenticate user. If no user credentials is
* specified every call to web service will fail.
*
* #param context SOAP message context to get SOAP message from
* #return true
*/
#Override
public boolean handleMessage(SOAPMessageContext context) {
try {
SOAPMessage message = context.getMessage();
SOAPHeader header = message.getSOAPHeader();
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
if (header == null) {
header = envelope.addHeader();
}
QName qNameUserCredentials = new QName("https://your.target.namespace/", "UserCredentials");
SOAPHeaderElement userCredentials = header.addHeaderElement(qNameUserCredentials);
QName qNameUsername = new QName("https://your.target.namespace/", "Username");
SOAPHeaderElement username = header.addHeaderElement(qNameUsername );
username.addTextNode(this.username);
QName qNamePassword = new QName("https://your.target.namespace/", "Password");
SOAPHeaderElement password = header.addHeaderElement(qNamePassword);
password.addTextNode(this.password);
userCredentials.addChildElement(username);
userCredentials.addChildElement(password);
message.saveChanges();
//TODO: remove this writer when the testing is finished
StringWriter writer = new StringWriter();
message.writeTo(new StringOutputStream(writer));
LOGGER.debug("SOAP message: \n" + writer.toString());
} catch (SOAPException e) {
LOGGER.error("Error occurred while adding credentials to SOAP header.", e);
} catch (IOException e) {
LOGGER.error("Error occurred while writing message to output stream.", e);
}
return true;
}
//TODO: remove this class after testing is finished
private static class StringOutputStream extends OutputStream {
private StringWriter writer;
public StringOutputStream(StringWriter writer) {
this.writer = writer;
}
#Override
public void write(int b) throws IOException {
writer.write(b);
}
}
#Override
public boolean handleFault(SOAPMessageContext context) {
LOGGER.debug("handleFault has been invoked.");
return true;
}
#Override
public void close(MessageContext context) {
LOGGER.debug("close has been invoked.");
}
#Override
public Set<QName> getHeaders() {
LOGGER.debug("getHeaders has been invoked.");
return null;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
}
Note that I am just adding the credentials to the header and returning true. You do what ever you want with whole message and return false if something that is expected fails.
I have implemented this one the client:
<bean id="soapHandler" class="your.package.MyHandler">
<property name="username" value="testUser"/>
<property name="password" value="testPassword"/>
</bean>
<jaxws:client "...">
<jaxws:handlers>
<ref bean="soapHandler"/>
</jaxws:handlers>
</jaxws:client>
But it also can be implemented on the endpoint.
We can get header from the envelop only not from soap message.

Add Security Header info to Java Code generated from WSDL

I used the Netbeans Web Service wizard to generate Java code given a WSDL. If I drag the web service method into a class, then it creates some Java code to call that web service (ex: SubmitApplication). I can see how to populate objects to send info to that web service, but the service also requires a security header with username/password.
There is a generated class called SecurityHeader that contains the username/password attributes. I can create this object with a valid username/password, but I cannot see how to pass that object or add it to the SubmitApplication call. How can the SecurityHeader be added to the SubmitApplication call?
Here is an example of what the SOAP request should look like:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<SecurityHeader xmlns="http://schemas.turss.com/BDS/1.0/">
<CreateTime>6/8/2012 8:32:59 PM</CreateTime>
<Owner>Sample_Owner</Owner>
<HashKey>Sample_Hash_Key</HashKey>
</SecurityHeader>
</soap:Header>
<soap:Body>
<SubmitApplication xmlns="http://schemas.turss.com/BDS/1.0/">
<newSearch>
<CurrentApplicant xmlns="http://schemas.turss.com/BDS/1.0/proxy">
<FirstName>Bob</FirstName>
<MiddleName />
<LastName>Smith</LastName>
<Suffix />
<BirthDate>1970-10-20T00:00:00</BirthDate>
<SSN />
<Address />
<City />
<State />
<PostalCode />
</CurrentApplicant>
<PermissiblePurpose xmlns="http://schemas.turss.com/BDS/1.0/proxy">TenantScreening</PermissiblePurpose>
</newSearch>
</SubmitApplication>
</soap:Body>
</soap:Envelope>
I found a sample code that add a token string to a soap security header. Here is the header form of the code below :
<TicketHeader>
<Ticket>OD01096347CCA</Ticket>
</TicketHeader>
The method to add the header to the message :
// Security token
String token;
// MyService and MySoapService are stubs generated from WSDL
MyService service = new MyService();
MyServiceSoap ep = service.getMyServiceSoap();
Binding binding = ((BindingProvider) ep).getBinding();
List handlers = binding.getHandlerChain();
handlers.add(new MySOAPHandler(token));
binding.setHandlerChain(handlers);
code of MySoapHandler :
public class MySOAPHandler implements SOAPHandler {
private String token;
public DHSOAPHandler(String token) {
this.token = token;
}
public boolean handleMessage(SOAPMessageContext messageContext) {
SOAPMessage
msg = messageContext.getMessage();
if ((Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)){
try {
SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
SOAPHeader header = envelope.addHeader();
SOAPElement el = header.addHeaderElement(envelope.createName("TicketHeader",
"", "http://ws.service.com/"));
el = el.addChildElement(envelope.createName("Ticket", "", "http://ws.service.com/"));
el.setValue(token);
msg.saveChanges();
}
catch (SOAPException e) {
return false;
}
}
return true;
}
public boolean handleFault(SOAPMessageContext messageContext) {
return true;
}
public void close(MessageContext messageContext){
}
// I'm not quite sure about what should this function do, but I guess something like this...
public Set getHeaders(){
Set headers = new HashSet();
headers.add(new QName("https://ws.service.com/", "TicketHeader"));
return headers;
}
}

Categories