Add SoapHeader to org.springframework.ws.WebServiceMessage - java

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);
}
}

Related

CXF: Multiple parts in soap header

I need a soap header like this:
<MyHeader xmlns:foo="http://foourl" xmlns:bar="http://barurl" bar:someParam="true", otherParam="hereiam">WORLD</MyHeader>
I tried to create it like:
new SoapHeader(new QName("http://foourl", "MyHeader", "foo"),
"WORLD", new JAXBDataBinding(String.class)));
But I just get
<MyHeader xmlns:foo="http://foourl">WORLD</MyHeader>
How can I set the other parts of the header (xmlns:bar, bar:someParam, otherParam)? TIA!
I found a solution for myself:
https://manoj29.wordpress.com/2011/12/29/apache-cxf-adding-custom-soap-headers-to-a-soap-message/
Example:
private void addHeader(String localPart, String valueElement, QName attributeQname, String attributeValue, List<Header> headers) {
var qname = new QName("http://www.w3.org/2005/08/addressing", localPart, "wsa");
var soapElement = createSoapElement(qname, attributeQname, attributeValue, valueElement);
headers.add(new Header(qname, soapElement));
}
private SOAPElement createSoapElement(QName elementQname, QName attributeQname, String attributeValue, String valueElement) {
SOAPElement element = null;
try {
SOAPFactory factory = SOAPFactory.newInstance();
element = factory.createElement(elementQname);
if (Objects.nonNull(attributeQname) && Objects.nonNull(attributeValue))
element.addAttribute(attributeQname, attributeValue);
if (Objects.nonNull(valueElement))
element.addTextNode(valueElement);
} catch (SOAPException e) {
log.error("Can not create new element", e);
} finally {
return element;
}}

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.

SOAPExceptionImpl Bad response: 404Not Found if i don't do soapMessage.writeTo(System.out);

I'm creating a Soap client in java and I'm getting a strange error.
Abstract client
public abstract class AbstractSoapClient {
private ServerContext context;
private String path;
private static final String WSSE = "";
private static final String CURL = "";
private static final String CURL_PASSWORD = "";
private static final String SECURITY_NODE = "";
private static final String USERNAME_TOKEN = "";
private static final String USERNAME_NODE = "";
private static final String PASSWORD_NODE = "";
public AbstractSoapClient(ServerContext context) {
this.context = context;
}
protected SOAPMessage createRequest(String path) throws SOAPException {
this.path = assembleEndpoint(path);
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
SOAPConnection soapConnection = soapConnectionFactory.createConnection();
SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(), this.path);
soapConnection.close();
return soapResponse;
}
protected void setCredentials(SOAPEnvelope envelope) throws SOAPException {
SOAPHeader tHeader = envelope.getHeader();
Name tWsseHeaderName = envelope.createName(SECURITY_NODE, WSSE, CURL);
SOAPHeaderElement tSecurityElement = tHeader.addHeaderElement(tWsseHeaderName);
tSecurityElement.setMustUnderstand(false);
Name tUserTokenElementName = envelope.createName(USERNAME_TOKEN, WSSE, CURL);
SOAPElement tUserTokenElement = tSecurityElement.addChildElement(tUserTokenElementName);
tUserTokenElement.removeNamespaceDeclaration(WSSE);
tUserTokenElement.addNamespaceDeclaration("wsu", CURL);
// user name child
Name tUsernameElementName = envelope.createName(USERNAME_NODE, WSSE, CURL);
SOAPElement tUsernameElement = tUserTokenElement.addChildElement(tUsernameElementName);
tUsernameElement.removeNamespaceDeclaration(WSSE);
tUsernameElement.addTextNode(context.getUsername());
// password child
Name tPasswordElementName = envelope.createName(PASSWORD_NODE, WSSE, CURL);
SOAPElement tPasswordElement = tUserTokenElement.addChildElement(tPasswordElementName);
tPasswordElement.removeNamespaceDeclaration(WSSE);
tPasswordElement.setAttribute("Type", CURL_PASSWORD);
tPasswordElement.addTextNode(context.getPassword());
}
private String assembleEndpoint(String path) {
return context.getUrl().concat(path);
}
protected abstract SOAPMessage createSOAPRequest() throws SOAPException;
public ServerContext getContext() {
return context;
}
public String getPath() {
return path;
}
}
Soap Client implementation
public class SoapClient extends AbstractSoapClient {
public SoapClient(ServerContext context) {
super(context);
}
#Override
public SOAPMessage createSOAPRequest() throws SOAPException {
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
setCredentials(envelope);
buildBody(envelope);
soapMessage.saveChanges();
try {
soapMessage.writeTo(System.out);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return soapMessage;
}
private void buildBody(SOAPEnvelope envelope) throws SOAPException {
envelope.addNamespaceDeclaration("sch", "------");
SOAPBody soapBody = envelope.getBody();
SOAPElement soapBodyElem = soapBody.addChildElement("sampleData", "sampleData");
SOAPElement soapBodyElem1 = soapBodyElem.addChildElement("sampleData");
soapBodyElem1.addTextNode("sampleData");
SOAPElement soapBodyElem2 = soapBodyElem.addChildElement("sampleData");
soapBodyElem2.addTextNode("sampleData");
SOAPElement soapBodyElem3 = soapBodyElem.addChildElement("sampleData");
soapBodyElem3.addTextNode("Y");
SOAPElement soapBodyElem4 = soapBodyElem.addChildElement("sampleData");
soapBodyElem4.addTextNode("sampleData");
SOAPElement soapBodyElem5 = soapBodyElem.addChildElement("sampleData");
soapBodyElem5.addTextNode("sampleData");
SOAPElement soapBodyElem6 = soapBodyElem.addChildElement("sampleData");
soapBodyElem6.addTextNode("sampleData");
}
public static void main(String[] args) throws SOAPException, IOException {
SoapClient client = new SoapClient(
new ServerContext("url", "user", "password"));
SOAPMessage response = client.createRequest("endpoint");
response.writeTo(System.out);
}
}
The strange point is in this part of the code:
try {
soapMessage.writeTo(System.out);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
If I comment this code that only print the request before to send it I get the following exception:
ago 12, 2016 12:58:17 PM com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection post
GRAVE: SAAJ0008: respuesta errĂ³nea; Not Found
Exception in thread "main" com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Bad response: (404Not Found
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.call(HttpSOAPConnection.java:149)
at
AbstractSoapClient.createRequest(AbstractSoapClient.java:44)
at SoapClient.main(SoapClient.java:67)
Caused by: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Bad response: (404Not Found
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.post(HttpSOAPConnection.java:264)
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.call(HttpSOAPConnection.java:145)
... 2 more
CAUSE:
com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Bad response: (404Not Found
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.post(HttpSOAPConnection.java:264)
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.call(HttpSOAPConnection.java:145)
at AbstractSoapClient.createRequest(AbstractSoapClient.java:44)
at SoapClient.main(SoapClient.java:67)
But if I don't comment this line I can get the response correctly.
This doesn't make sense: why is it sending a 404Not Found if I don't write the request in the console before sending it?
If you check the writeTo implementation you will see that they add a SOAPAction header.
Try the following:
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
soapMessage.getMimeHeaders().addHeader("SOAPAction", "\"\"");
By default, SOAPMessage interface is implemented by SoapMessageImpl.
This implementation has the side effect of adding a SOAPAction header if it's not present.
After calling to writeTo, you can remove it by calling:
soapMessage.getMimeHeaders().removeHeader("SOAPAction");
Having said that, instead of adding extra code only to log the call and response, i suggest to use a proxy instead.
If you're using Eclipse, take a look at the TCP/Monitor View
Identify the correct "SOAPAction" and then post the request. This will resolve the 404 FileNotFoud Error.
eg:
String SOAPAction = "/Service/Service.serviceagent/ServicesEndpoint1/ACTIONNAMEFROMSERVERSIDE";
httpConn.setRequestProperty("Content-Length", String.valueOf(b.length));
httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
httpConn.setRequestProperty("SOAPAction", SOAPAction);

SOAP handlers using java keystore

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.

Categories