SOAP handlers using java keystore - java

I am working on web services security, trying to encrypt and sign SOAP messages between the server and the client. I used BouncyCastle, WSS4j and SOAP handlers.
To test my work at first I used the same keystore file on both the server and the client sides.I followed some tutorials on the net and it worked: the messages sent by one side were encrypted and signed and then decrypted successfully on the other side.
But now that I generated different certificates for the server and the client, and imported the client's cert into the servers jks file and vice-versa, I can't seem to figure out how to finish the task. It is still crypting and signing as if it only had a jks file without an imported cert in it. below is the code:
Crypt_handler.java
public class Crypt_handler implements SOAPHandler<SOAPMessageContext> , CallbackHandler{
public Properties prop;
public InputStream input= null;
public Crypt_handler () {
try {
prop=new Properties();
input = new FileInputStream("config.properties");
if(input==null){
System.out.println("Sorry, unable to find " );
return;}
prop.load(input);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public boolean handleMessage(SOAPMessageContext messageContext) {
try {
// got the message from the context
SOAPMessage msg = messageContext.getMessage();
// is outgoing?
Boolean isOutGoing = (Boolean) messageContext
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (isOutGoing) {
// if it is outgoing code and sign
crypt.EncryptUtil.EncryptSOAPEnvelope(msg, prop);
crypt.EncryptUtil.SignSOAPEnvelope(msg, prop);
} else {
// if it is incooming decode and check signature.
crypt.EncryptUtil.CheckSignatureAndDecode(msg, this , prop);
}
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex.getMessage());
}
return true;
}
public boolean handleFault(SOAPMessageContext context) {
System.out.println("Server : handleFault()......");
return true;
}
public void close(MessageContext context) {
System.out.println("Server : close()......");
}
public Set<QName> getHeaders() {
Set<QName> HEADERS = new HashSet<QName>();
HEADERS.add(new QName(WSConstants.WSSE_NS, "Security"));
HEADERS.add(new QName(WSConstants.WSSE11_NS, "Security"));
HEADERS.add(new QName(WSConstants.ENC_NS, "EncryptedData"));
return HEADERS;
}
private void generateSOAPErrMessage(SOAPMessage msg, String reason) {
try {
SOAPBody soapBody = msg.getSOAPPart().getEnvelope().getBody();
SOAPFault soapFault = soapBody.addFault();
soapFault.setFaultString(reason);
throw new SOAPFaultException(soapFault);
}
catch(SOAPException e) { }
}
#SuppressWarnings("deprecation")
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
String password;
for (Callback cb : callbacks) {
if (cb instanceof WSPasswordCallback) {
WSPasswordCallback pc = (WSPasswordCallback) cb;
try {
password = /*prop.getProperty("password")*/"password";
} catch (Exception e) {
throw new UnsupportedCallbackException(pc, "failure recovering the key in the properties");
}
if (pc.getIdentifer() != null) {
pc.setPassword(password);
}
}
}
}
}
EncryptUtil.java:
public class EncryptUtil{
#SuppressWarnings( { "unchecked", "deprecation" })
public
static void CheckSignatureAndDecode(SOAPMessage msg, CallbackHandler cb,Properties prop) throws WSSecurityException, TransformerConfigurationException, TransformerException, SOAPException, IOException, Exception {
WSSecurityEngine secEngine = new WSSecurityEngine();
WSSignEnvelope signer = new WSSignEnvelope();
String alias = prop.getProperty("alias");// login of jks file
String password = prop.getProperty("password");// password of jks file
signer.setUserInfo("client", password);
Crypto crypto = CryptoFactory.getInstance(prop);
Document doc = toDocument(msg);
//after we set the encrypt stuff the processsecurity does all the work
Vector v = secEngine.processSecurityHeader(doc, null, cb, crypto);
if (v == null) {
throw new Exception("Access not granted.");
}
//put the decoded message into the object
updateSOAPMessage(doc, msg);
}
/**
* Updates the message with the unencrypt form
*/
private static SOAPMessage updateSOAPMessage(Document doc, SOAPMessage message) throws SOAPException {
DOMSource domSource = new DOMSource(doc);
message.getSOAPPart().setContent(domSource);
return message;
}
/**
* Changes the SOAPMessage to a dom.Document.
*/
public static org.w3c.dom.Document toDocument(SOAPMessage soapMsg) throws SOAPException, TransformerException {
Source src = soapMsg.getSOAPPart().getContent();
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMResult result = new DOMResult();
transformer.transform(src, result);
return (Document) result.getNode();
}
/**
* Signs a SOAPMessage
*
* #param mensaje
* #throws Exception
*/
#SuppressWarnings("deprecation")
public
static void SignSOAPEnvelope(SOAPMessage mensaje, Properties prop) throws Exception {
// WSSignEnvelope signs a SOAP envelope according to the
// WS Specification (X509 profile) and adds the signature data
// to the envelope.
WSSignEnvelope signer = new WSSignEnvelope();
String alias = prop.getProperty("alias");// "autentiaserver";
String password = prop.getProperty("password");// "changeit";
signer.setUserInfo(alias, password);
Crypto crypto = CryptoFactory.getInstance(prop);
Document doc = toDocument(mensaje);
signer.setMustUnderstand(false);
Document signedDoc = signer.build( doc, crypto);
DOMSource domSource = new DOMSource( signedDoc);
mensaje.getSOAPPart().setContent(domSource);
}
/**
* Codes a SOAPMessage.
*/
#SuppressWarnings("deprecation")
public
static void EncryptSOAPEnvelope(SOAPMessage mensaje,Properties prop) throws Exception {
// WSSignEnvelope signs a SOAP envelope according to the
// WS Specification (X509 profile) and adds the signature data
// to the envelope.
WSEncryptBody encriptador = new WSEncryptBody();
String alias = prop.getProperty("alias");
String password = prop.getProperty("password");
encriptador.setUserInfo(alias, password);
Crypto crypto = CryptoFactory.getInstance(prop);
Document doc = toDocument(mensaje);
encriptador.setMustUnderstand(false);
Document signedDoc = encriptador.build( doc, crypto);
DOMSource domSource = new DOMSource( signedDoc);
mensaje.getSOAPPart().setContent(domSource);
}
}
And here's my config.properties file:
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=password
org.apache.ws.security.crypto.merlin.keystore.alias=first
org.apache.ws.security.crypto.merlin.file=/home/user/workspace/crypt_server/keystore.jks
alias=first
password=password
Any help would be appreciated. Thanks in advance.

Related

Getting request and response SOAP message when dataFormat is POJO

I am using WebServices and Apache Camel and using dataFormat as POJO for requesting that webservice. I am successfully able to call the service but I want to log the request and response SOAP message which I am not able to because the SOAP message is created by CXF from the POJO class.
Is there any way in which I can log the request and response SOAP message when dataFormat is POJO?
this is the example how i am logging soap requests and response in my project, hope this helps
BindingProvider bindingProvider = ((BindingProvider) PortType);
List<Handler> handlerChain = bindingProvider.getBinding().getHandlerChain();
handlerChain.add(new SOAPLoggingHandler());
bindingProvider.getBinding().setHandlerChain(handlerChain);
and the class SOAPLoggingHandler
public class SOAPLoggingHandler implements SOAPHandler<SOAPMessageContext> {
// change this to redirect output if desired
public static Logger logger = Logger.getLogger("GetCustomerDataLand");
public Set<QName> getHeaders() {
return null;
}
public boolean handleMessage(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
public boolean handleFault(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
// nothing to clean up
public void close(MessageContext messageContext) {
}
/*
* Check the MESSAGE_OUTBOUND_PROPERTY in the context to see if this is an
* outgoing or incoming message. Write a brief message to the print stream
* and output the message. The writeTo() method can throw SOAPException or
* IOException
*/
private void logToSystemOut(SOAPMessageContext smc) {
Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:sss").format(new Date()) + "\nOutbound message:");
} else {
logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:sss").format(new Date()) + "\nInbound message:");
}
SOAPMessage message = smc.getMessage();
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
message.writeTo(stream);
String msg = new String(stream.toByteArray(), "utf-8");
logger.info(toPrettyString(msg));
// message.writeTo(out);
logger.info(""); // just to add a newline
} catch (Exception e) {
logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:sss").format(new Date()) + "Exception in handler: "
+ org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(e));
}
}
public String toPrettyString(String xml) {
try {
final InputSource src = new InputSource(new StringReader(xml));
final Node document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(src)
.getDocumentElement();
final Boolean keepDeclaration = Boolean.valueOf(xml.startsWith("<?xml"));
final DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
final DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
final LSSerializer writer = impl.createLSSerializer();
writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
writer.getDomConfig().setParameter("xml-declaration", keepDeclaration);
return writer.writeToString(document);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

Java integration with SSRS

Hi I am looking into using Java (to be deployed as servlets in Websphere 8.5) to integrate with SSRS. I have looked into some of the sample codes out there and try it out.
private static SoapHeader createExecutionIdSoapHeader(String executionId) {
Document doc = DOMUtils.createDocument();
Element executionHeaderElement = doc.createElement("ExecutionHeader");
executionHeaderElement.setAttribute("xmlns", XML_NAMESPACE);
Element executionIdElement = doc.createElement("ExecutionID");
executionIdElement.setTextContent(executionId);
executionHeaderElement.appendChild(executionIdElement);
SoapHeader soapH = new SoapHeader(new QName(XML_NAMESPACE, "ExecutionHeader"), executionHeaderElement);
return soapH;
}
public static Holder<byte[]> getReportResult(String output_type, String reportFolder, String reportName, ArrayOfParameterValue arrayOfParameterValue) {
Holder<byte[]> result = null;
try {
String historyID = null;
String executionID = null;
ReportExecutionServiceSoap service = getExecutionService();
BindingProvider bp = (BindingProvider) service;
bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, authenticator.getUsername());
bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, authenticator.getPassword());
ExecutionInfo info = new ExecutionInfo();
info = service.loadReport(REPORT_PATH, historyID);
executionID = info.getExecutionID();
List<Header> headers = new ArrayList<Header>();
SoapHeader header = createExecutionIdSoapHeader(executionID);
headers.add(header);
bp.getRequestContext().put(Header.HEADER_LIST, headers);
if (!arrayOfParameterValue.getParameterValue().isEmpty()) {
service.setExecutionParameters(arrayOfParameterValue, "en-us");
}
// Default to return HTML4.0
String deviceInfo = "";
if (output_type == null || output_type.isEmpty()) {
output_type = "HTML4.0";
}
if ("IMAGE".equalsIgnoreCase(output_type)) {
deviceInfo = RENDER_DEVICE_INFO_IMAGE;
} else {
deviceInfo = RENDER_DEVICE_INFO_HTML;
}
result = new Holder<byte[]>();
Holder<String> extension = new Holder<String>();
Holder<String> mimeType = new Holder<String>();
Holder<String> encoding = new Holder<String>();
Holder<ArrayOfWarning> warnings = new Holder<ArrayOfWarning>();
Holder<ArrayOfString> streamIDs = new Holder<ArrayOfString>();
service.render(output_type, deviceInfo, result, extension, mimeType, encoding, warnings, streamIDs);
} catch (Throwable th) {
th.printStackTrace();
}
return result;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
ArrayOfParameterValue arrayOfParameterValue = new ArrayOfParameterValue();
List<ParameterValue> parameters = arrayOfParameterValue.getParameterValue();
ParameterValue parameterValue = new ParameterValue();
parameterValue.setName(PARAMETER_NAME);
parameterValue.setValue(PARAMETER_VALUE);
parameters.add(parameterValue);
Holder<byte[]> result = GenerateReport.getReportResult(REPORT_FORMAT, REPORT_FOLDER, REPORT_NAME,
arrayOfParameterValue);
System.out.println("--------------------------------- Writing to Browser --------------------------------");
ServletOutputStream out = response.getOutputStream();
out.write(result.value);
out.flush();
out.close();
System.out.println("--------------------------------- Writing to File -----------------------------------");
DateFormat df = new SimpleDateFormat("dd_MM_yy_HH_mm_ss_");
Date date = new Date();
String filename = df.format(date) + "SSRS_Report.pdf";
FileOutputStream o = new FileOutputStream("C:\\Users\\keh\\Desktop\\Temp\\" + filename);
o.write(result.value);
o.flush();
o.close();
} catch (Exception e) {
e.printStackTrace();
}
}
When I run the codes, I have this error :
[5/17/17 19:21:02:704 SGT] 000000c4 SystemErr R javax.xml.ws.soap.SOAPFaultException: The session identifier is missing. A session identifier is required for this operation. ---> Microsoft.ReportingServices.Diagnostics.Utilities.MissingSessionIdException: The session identifier is missing. A session identifier is required for this operation.
Any expert out there can point me to a solution pls?
P.S. I have tried to use WSBindingProvider as shown in Surendra Gurjar's Blog and it ran beautifully on an Apache server, but I got a ClassCastException when I deploy it to Websphere.

Archive is not starting in opentok?

I am using Open tok rest api. and specifying " archiveMode:always " while creating session and they have specified in documentation that as soon as any one subscribe to session it will start archiving the session but it is not my code is as follows
final WSRequest request = WS.url("https://api.opentok.com/session/create");
// request.setContentType("application/json");
request.setHeader("X-TB-PARTNER-AUTH", Constants.OPENTOK_API_KEY+":"+Constants.OPENTOK_SECRET);
request.setHeader("archiveMode","always");
request.setMethod("POST");
final Promise<WSResponse> response = request.execute(); //post("X-TB-PARTNER-AUTH:"+ApiCredentials.apiKey+":"+ApiCredentials.apiSecret);
final Function<WSResponse,Document> resultFromResponse =
new Function<WSResponse , Document >() {
#Override
public Document apply(final WSResponse arg0) throws Throwable {
// TODO Auto-generated method stub
//String message = response.get(0).asXml().getBaseURI();
Logger.debug(""+response.get(0).getBody());
final Document doc = response.get(0).asXml();
final Result result =ok("temp value");
return doc;
}
};
final Promise<Document> resultDoc= response.map(resultFromResponse);
final Document document = resultDoc.get(1000*10l);
if(document == null) {
return null;
} else {
Logger.debug("document:"+document);
final String name = XPath.selectText("//session_id", document);
Logger.debug("sessionid:"+name);
if(name == null) {
return null;
} else {
sessionId = name;
//return ok("Hello " + name);
}
}
The "archiveMode" key is not an HTTP header, it's part of the HTTP POST body.

Trying to use the certificate to connect in a web server

I ve been trying to use two different certificates to communicate in a web server( Web server 1). When I use the first one, I can communicate with the web server without any problem. But when I try to use the second one, I have some problems: Even if I change the certificate and make another conection with the web server, it returns the information that a had used in the first certificate.
When I close and open the tomcat 8, I can use the second one, but I can't use the first one again.
I´ve been using more than one certificate , and using the same method in another web server(Web server 2) without problem.
Follow the code bellow:
public String sendXml(String xmlCabecalho, String xmlEnvNFse) throws ExceptionServicoAbrasf {
try {
SignXml signXml = new SignXml(this.keyStoreService.getKeystore(), this.keyStoreService.getAliasCert(), this.keyStoreService.getPasswordPfx());
xmlEnvNFse = signXml.signAndSend(xmlEnvNFse);
loadInfoCertificate();
return executarServicoEnvioNFse(xmlCabecalho, xmlEnvNFse);
} catch (Exception ex) {
throw new ExceptionServicoAbrasf("Failure to sing. " + ex.getMessage());
}
}
//add xml to sign
public String signAndSend(String xml) throws Exception {
//sign
return sign(xml, "InfDeclaracaoPrestacaoServico", "Rps");
}
//sign
private String sign(String xml, String tag, String tagParentSignature) throws Exception {
Document document = documentFactory(xml);
XMLSignatureFactory signatureFactory = XMLSignatureFactory
.getInstance("DOM");
ArrayList<Transform> transformList = signatureFactory(signatureFactory);
loadCertificates(signatureFactory);
NodeList elements = document.getElementsByTagName(tag);
org.w3c.dom.Element el = (org.w3c.dom.Element) elements.item(0);
el.setIdAttribute("Id", true);
String id = el.getAttribute("Id");
Reference ref = signatureFactory.newReference("#" + id,
signatureFactory.newDigestMethod(DigestMethod.SHA1, null),
transformList, null, null);
SignedInfo si = signatureFactory.newSignedInfo(signatureFactory
.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null), signatureFactory
.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
XMLSignature signature = signatureFactory.newXMLSignature(si, keyInfo);
DOMSignContext dsc = new DOMSignContext(privateKey, document.getElementsByTagName(tagParentSignature).item(0));
signature.sign(dsc);
return outputXML(document);
}
//load certificate
protected void loadCertificates(XMLSignatureFactory signatureFactory) throws Exception {
if (keyStore != null) {
KeyStore.PrivateKeyEntry pkEntry = null;
if (keyStore.isKeyEntry(alias)) {
char[] pin = (password == null ? "" : password).toCharArray();
pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias,
new KeyStore.PasswordProtection(pin));
privateKey = pkEntry.getPrivateKey();
X509Certificate cert = (X509Certificate) pkEntry.getCertificate();
KeyInfoFactory keyInfoFactory = signatureFactory.getKeyInfoFactory();
List<X509Certificate> x509Content = new ArrayList<>();
x509Content.add(cert);
X509Data x509Data = keyInfoFactory.newX509Data(x509Content);
keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(x509Data));
} else {
throw new Exception("Alias invalid.");
}
} else {
throw new Exception("Invalid Certificate Information.");
}
}
///normalize xml
protected String outputXML(Document doc) throws TransformerException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(os));
String xml = os.toString();
if ((xml != null) && (!"".equals(xml))) {
xml = xml.replaceAll("\\r\\n", "");
xml = xml.replaceAll(" standalone=\"no\"", "");
}
return xml;
}
//load info certificate
private void loadInfoCertificate() {
System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
System.setProperty("javax.net.ssl.keyStoreType", "PKCS12");
System.clearProperty("javax.net.ssl.keyStore");
System.clearProperty("javax.net.ssl.keyStorePassword");
System.clearProperty("javax.net.ssl.trustStore");
System.setProperty("javax.net.ssl.keyStore", this.keyStoreService.getPathPfx());
System.setProperty("javax.net.ssl.keyStorePassword", this.keyStoreService.getPasswordPfx());
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStore", this.pathCacerts);
}
//send web service
private String executarServicoEnvioNFse(String xmlCabecalho, String xmlCorpo) throws ExceptionServicoAbrasf {
Input input = new Input(xmlCabecalho, xmlCorpo);
Output output = generateReturn(input);
return output.getOutputXML();
}
//generate conection web service
private Output generateReturn(ws.Input parameters) throws ExceptionServicoAbrasf {
ws.Nfse port = loadNfseDivPort();
return port.generateReturn(parameters);
}
//return web service
private ws.Nfse loadNfseDivPort() throws ExceptionServicoAbrasf {
try {
String urlStr = "https://homolog.govdigital.com.br/ws/div?wsdl";
URL url = new URL(urlStr);
ws.NfseServiceImplDivService service = new ws.NfseServiceImplDivService(url);
ws.Nfse port = service.getNfseDivPort();
return port;
} catch (MalformedURLException ex) {
throw new ExceptionServicoAbrasf("Invalid url. " + ex.getMessage());
}
}

Add SoapHeader to org.springframework.ws.WebServiceMessage

How can I add an object into the soap header of a org.springframework.ws.WebServiceMessage
This is the structure I'm looking to end up with:
<soap:Header>
<credentials xmlns="http://example.com/auth">
<username>username</username>
<password>password</password>
</credentials>
</soap:Header>
Basically, you need to use a WebServiceMessageCallback in your client to modify the message after its creation but before it is sent. To rest of the code has been described pretty accurately by #skaffman so the whole stuff might look like this:
public void marshalWithSoapActionHeader(MyObject o) {
webServiceTemplate.marshalSendAndReceive(o, new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) {
try {
SoapMessage soapMessage = (SoapMessage)message;
SoapHeader header = soapMessage.getSoapHeader();
StringSource headerSource = new StringSource("<credentials xmlns=\"http://example.com/auth\">\n +
<username>"+username+"</username>\n +
<password>"+password"+</password>\n +
</credentials>");
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(headerSource, header.getResult());
} catch (Exception e) {
// exception handling
}
}
});
}
Personally, I find that Spring-WS sucks hard for such a basic need, they should fix SWS-479.
You can do as below:
public class SoapRequestHeaderModifier implements WebServiceMessageCallback {
private final String userName = "user";
private final String passWd = "passwd";
#Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
if (message instanceof SaajSoapMessage) {
SaajSoapMessage soapMessage = (SaajSoapMessage) message;
MimeHeaders mimeHeader = soapMessage.getSaajMessage().getMimeHeaders();
mimeHeader.setHeader("Authorization", getB64Auth(userName, passWd));
}
}
private String getB64Auth(String login, String pass) {
String source = login + ":" + pass;
String retunVal = "Basic " + Base64.getUrlEncoder().encodeToString(source.getBytes());
return retunVal;
}
}
Then
Object response = getWebServiceTemplate().marshalSendAndReceive(request, new SoapRequestHeaderModifier());
You need to cast the WebServiceMessage to SoapMessage, which has a getSoapHeader() method you can use to modify the header. In turn, SoapHeader has various methods for adding elements, including getResult() (which can be used as the output of a Transformer.transform() operation).
I tried many options and finally below one worked for me if you have to send soap header with authentication(Provided authentication object created by wsimport) and also need to set soapaction.
public Response callWebService(String url, Object request)
{
Response res = null;
log.info("The request object is " + request.toString());
try {
res = (Response) getWebServiceTemplate().marshalSendAndReceive(url, request,new WebServiceMessageCallback() {
#Override
public void doWithMessage(WebServiceMessage message) {
try {
// get the header from the SOAP message
SoapHeader soapHeader = ((SoapMessage) message).getSoapHeader();
// create the header element
ObjectFactory factory = new ObjectFactory();
Authentication auth =
factory.createAuthentication();
auth.setUser("****");
auth.setPassword("******");
((SoapMessage) message).setSoapAction(
"soapAction");
JAXBElement<Authentication> headers =
factory.createAuthentication(auth);
// create a marshaller
JAXBContext context = JAXBContext.newInstance(Authentication.class);
Marshaller marshaller = context.createMarshaller();
// marshal the headers into the specified result
marshaller.marshal(headers, soapHeader.getResult());
} catch (Exception e) {
log.error("error during marshalling of the SOAP headers", e);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
You can achieve it by creating key-value map of child elements as well:
final Map<String, String> elements = new HashMap<>();
elements.put("username", "username");
elements.put("password", "password");
Set up namespace and prefix of your child element within the soap header:
final String LOCAL_NAME = "credentials";
final String PREFIX = "";
final String NAMESPACE = "http://example.com/auth";
Then, you can invoke WebServiceTemplate's method marshalSendAndReceive where you override WebServiceMessageCallback's method doWithMessage as follows:
Object response = getWebServiceTemplate().marshalSendAndReceive(request, (message) -> {
if (message instanceof SaajSoapMessage) {
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) message;
SOAPMessage soapMessage = saajSoapMessage.getSaajMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
if (Objects.nonNull(elements)) {
try {
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPHeader soapHeader = soapEnvelope.getHeader();
Name headerElementName = soapEnvelope.createName(
LOCAL_NAME,
PREFIX,
NAMESPACE
);
SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(headerElementName);
elements.forEach((key, value) -> {
try {
SOAPElement element = soapHeaderElement.addChildElement(key, PREFIX);
element.addTextNode(value);
} catch (SOAPException e) {
// error handling
}
});
soapMessage.saveChanges();
} catch (SOAPException e) {
// error handling
}
}
}
});
The above steps result in:
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header>
<credentials xmlns="http://example.com/auth">
<password>password</password>
<username>username</username>
</credentials>
</env:Header>
<env:Body>
<!-- your payload -->
</env:Body>
</env:Envelope>
Response response = (Response)getWebServiceTemplate() .marshalSendAndReceive(request, new HeaderModifier());
Create class HeaderModifier and override doWithMessage
public class HeaderModifier implements WebServiceMessageCallback {
private static PrintStream out = System.out;
#Override
public void doWithMessage(WebServiceMessage message) throws IOException {
SaajSoapMessage soapMessage = (SaajSoapMessage) message;
SoapEnvelope soapEnvelope = soapMessage.getEnvelope();
SoapHeader soapHeader = soapEnvelope.getHeader();
//Initialize QName for Action and To
QName action = new QName("{uri}","Action","{actionname}");
QName to = new QName("{uri}","To","{actionname}");
soapHeader.addNamespaceDeclaration("{actionname}", "{uri}");
SoapHeaderElement soapHeaderElementAction = soapHeader.addHeaderElement(action);
SoapHeaderElement soapHeaderElementTo = soapHeader.addHeaderElement(to);
soapHeaderElementAction.setText("{text inside the tags}");
soapHeaderElementTo.setText("{text inside the tags}");
soapMessage.setSoapAction("{add soap action uri}");
soapMessage.writeTo(out);
}
}

Categories