We have a Java web service that we're enhancing so the client can send up some extremely large messages to the server. To support these large attachments, we're using MTOM.
Unfortunately, we're also adding WSSE security information to our SOAP headers, and this is causing problems in combination with the extra-large SOAP messages.
Our code to attach WSSE security information is within a SOAPHandler, and looks like this:
public void addSecurity(String username, String password, SOAPMessageContext context) throws SOAPException {
SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
SOAPHeader header = envelope.getHeader();
SOAPElement security = null;
if (header == null) {
header = envelope.addHeader();
}
security = header.addChildElement("Security", "wsse", WSSE_NS_URI);
context.getMessage().saveChanges();
SOAPElement usernameToken
= security.addChildElement("UsernameToken", "wsse");
usernameToken.addAttribute(new QName("xmlns:wsu"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
SOAPElement usernameElement
= usernameToken.addChildElement("Username", "wsse");
usernameElement.addTextNode(username);
SOAPElement passwordElement
= usernameToken.addChildElement("Password", "wsse");
passwordElement.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
passwordElement.addTextNode(password);
}
The failure occurs in the statement context.getMessage().getSOAPPart().getEnvelope(). The context.getMessage() call appears to try to fetch the entire message, and since the message is huge, we get a heap space error:
Caused by: java.lang.OutOfMemoryError: Java heap space
at com.sun.xml.internal.messaging.saaj.util.ByteOutputStream.ensureCapacity(ByteOutputStream.java:99)
at com.sun.xml.internal.messaging.saaj.util.ByteOutputStream.write(ByteOutputStream.java:106)
at org.apache.xml.serializer.WriterToUTF8Buffered.flushBuffer(WriterToUTF8Buffered.java:447)
at org.apache.xml.serializer.WriterToUTF8Buffered.write(WriterToUTF8Buffered.java:191)
at org.apache.xml.serializer.WriterToUTF8Buffered.write(WriterToUTF8Buffered.java:244)
at org.apache.xml.serializer.ToStream.characters(ToStream.java:1623)
at org.apache.xalan.transformer.TransformerIdentityImpl.characters(TransformerIdentityImpl.java:1126)
at org.apache.xml.serializer.TreeWalker.dispatachChars(TreeWalker.java:246)
at org.apache.xml.serializer.TreeWalker.startNode(TreeWalker.java:416)
at org.apache.xml.serializer.TreeWalker.traverse(TreeWalker.java:145)
at org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:390)
at com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer.transform(EfficientStreamingTransformer.java:399)
at com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl.output(EnvelopeImpl.java:289)
at com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl.output(EnvelopeImpl.java:302)
at com.sun.xml.internal.messaging.saaj.soap.SOAPPartImpl.getContentAsStream(SOAPPartImpl.java:311)
at com.sun.xml.internal.messaging.saaj.soap.MessageImpl.getHeaderBytes(MessageImpl.java:1015)
at com.sun.xml.internal.messaging.saaj.soap.MessageImpl.saveChanges(MessageImpl.java:1166)
at com.sun.xml.internal.ws.api.message.saaj.SAAJFactory.readAsSOAPMessage(SAAJFactory.java:277)
at com.sun.xml.internal.ws.api.message.saaj.SAAJFactory.readAsSAAJ(SAAJFactory.java:197)
at com.sun.xml.internal.ws.api.message.saaj.SAAJFactory.read(SAAJFactory.java:186)
at com.sun.xml.internal.ws.message.AbstractMessageImpl.toSAAJ(AbstractMessageImpl.java:217)
at com.sun.xml.internal.ws.api.message.MessageWrapper.readAsSOAPMessage(MessageWrapper.java:156)
at com.sun.xml.internal.ws.handler.SOAPMessageContextImpl.getMessage(SOAPMessageContextImpl.java:70)
at com.ciminc.compass.singleSignOn.basic.SsoCookieRequestAppender.addSecurity(SsoCookieRequestAppender.java:147)
Ideally I'd like to add my WSSE information to the SOAP header without pulling in the entire multi-megabyte SOAP message. Is that possible?
Let me know if I can provide any other information to clarify.
Related
I'm attempting to make a SOAP request to an end point programmatically through Java. I'm relatively new to Java and web services so I'm not sure what I'm doing wrong here.
Also I print out the SOAP message and can paste that into a tool like postman and enter the end point and a post is successful. So i think something with my request is not correct here.
Here is my code:
System.out.println("hey now!!!!");
try {
SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
SOAPConnection connection = scf.createConnection();
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage message = mf.createMessage();
SOAPBody body = message.getSOAPBody();
SOAPHeader header = message.getSOAPHeader();
SOAPElement getOpenPOs = body.addChildElement("GetOpenPOs", "", "https://www.autocrib.net");
SOAPElement U = getOpenPOs.addChildElement("U");
U.addTextNode("u");
SOAPElement P = getOpenPOs.addChildElement("P");
P.addTextNode("p");
SOAPElement N = getOpenPOs.addChildElement("N");
N.addTextNode("n");
SOAPElement Processed = getOpenPOs.addChildElement("Processed");
Processed.addTextNode("false");
SOAPElement StationEnd = getOpenPOs.addChildElement("StationEnd");
StationEnd.addTextNode("");
SOAPPart sp = message.getSOAPPart();
SOAPEnvelope envelope = sp.getEnvelope();
//MimeHeaders headers = message.getMimeHeaders();
//header.setHeader("Content-Type", "text/xml");
//message.getMimeHeaders().addHeader("SOAPAction", "GetOpenPOs");
message.getMimeHeaders().addHeader("Content-Type", "text/xml");
header.setAttribute("Content-Type", "text/xml");
message.saveChanges();
System.out.println("Envelope Body");
message.writeTo(System.out);
System.out.println();
SOAPMessage reply = connection.call(message,
"https://www24.autocrib.net/WebServices/AutoCribWS.asmx");
//String reply2 = connection.call(message, "https://www24.autocrib.net/WebServices/AutoCribWS.asmx").toString();
//sp = reply.getSOAPPart();
//envelope = sp.getEnvelope();
//body = envelope.getBody();
//System.out.println(body.toString());
System.out.println("Done!!!!!!!!!!!!!!!!!!!");
} catch (Throwable t) {
System.out.println("Something went wrong!!! " + t.toString());
}
}
I get this error when I run this code:
Oct 24, 2016 1:56:57 PM com.sun.xml.internal.messaging.saaj.soap.MessageImpl identifyContentType
SEVERE: SAAJ0537: Invalid Content-Type. Could be an error message instead of a SOAP message
Something went wrong!!! com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Invalid Content-Type:text/html. Is this an error message instead of a SOAP response?
I'm guessing I need to add the Content-Type header. Am I doing this incorrectly? Any guidance would be great.
Thanks,
Tim
com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Invalid
Content-Type:text/html.
The SAAJ API throws an exception because it considers that you web service returns as response text/html content instead of soap/xml content.
So, one advise : study the content returned by postman. Are you sure it is soap/xml format ? It you notice that is not soap/xml content, work on the implementation of your WS and if needed adapt the return to be compliant with the SOAP norm.
Wilco I would like to give you credit for the answer but I don't think I can do that for comments. Your tip helped me figure out that it was indeed returning text/html because of the user agent header I had.
THanks again!!
I'm working with spring-ws, I need to perform simple username and password validation on my webservice calls. For that, I need to obtain the default soap header attributes for username and password. I have no idea how to do that with spring-ws and I've spent a lot of time trying to figure it out.
I'm using SoapUI and sending the username and password by setting them in the "Aut" tab.
My interceptor intercepts my calls, but I've debugged the messageContext and I have no idea where those fields are.
This is my code, it never enters to the code in the while, so the iterator is return false in the hasNext.
#Override
public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
logger.info("Intercepting call");
SoapMessage soapMessage = (SoapMessage) messageContext.getRequest();
SoapHeader soapHeader = soapMessage.getSoapHeader();
Iterator<SoapHeaderElement> it = soapHeader.examineAllHeaderElements();
while(it.hasNext()) {
SoapHeaderElement element = it.next();
QName qname = element.getName();
logger.info("QName: " + qname.getLocalPart());
logger.info("Value? " + soapHeader.getAttributeValue(qname));
}
return true;
}
If you would kindly point me towards any documentation on the subject, or better yet, some examples, it will be a great help.
Thanks a lot.
Ok, so I think that I've found the answer, my problem wasn't the code, but the eclipse plugin for SoapUI which was not really sending the authorization header. I've downloaded the desktop client, configured properly, and now I see the header.
With that enabled, I wrote this code, and was able to obtain the user and password:
TransportContext transportContext = TransportContextHolder.getTransportContext();
HttpServletRequest servletRequest = ((HttpServletConnection) transportContext.getConnection()).getHttpServletRequest();
String authorizationHeader = servletRequest.getHeader("authorization");
String userAndPasswordBase64 = authorizationHeader.substring("Basic ".length());
String userAndPassword = new String(Base64.decodeBase64(userAndPasswordBase64));
int colonIndex = userAndPassword.indexOf(':');
String user = userAndPassword.substring(0, colonIndex);
String password = userAndPassword.substring(colonIndex + 1);
This question was the one that really helped me unlock this though: How to access HTTP headers in Spring-ws endpoint?
Thanks a l
SOAPMessage soapMessage = context.getMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
soapEnvelope.getHeader();
I'm trying to invoke some WS. I have server and client on my local machine. I'm 100% sure about content of message and it comes from server to client with no changes. Problem is that the client creates not correct SOAPMessage object which have envelope field under soapPart equals to null.
Client side code:
SOAPMessage responseMsg = conn.call(msg, urlEndpoint);
Server side code:
SOAPEnvelope envelope = sp.getEnvelope();
SOAPHeader hdr = envelope.getHeader();
SOAPBody bdy = envelope.getBody();
bdy.addBodyElement(envelope.createName("response", "soa", "http://www.sbg.com"));
return msg;
Id debug window I see the following:
1) Server side debug window
2) Client side debug window
I'm using SAAJ for communication and JDK 1.6.
Can anybody assist with the issue?
Are you responsible for both (client and server)? What is the message that the client sends?
In my experience, it helps to use a tool like SoapUI to test the message:
http://www.soapui.org/
Try this:
SOAPMessage sm = MessageFactory.newInstance().createMessage();
sm.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
sm.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8");
SOAPPart sp = sm.getSOAPPart();
SOAPEnvelope se = sp.getEnvelope();
se.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
se.setAttribute("xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/");
se.setAttribute("xmlns:soa", "http://www.sbg.com");
SOAPBody sb = sm.getSOAPBody();
SOAPBodyElement el = sb.addBodyElement(new QName("http://www.sbg.com", "response", "soa"));
el.setAttribute("_ctxID", "cid=xref_members,cn=admin");
el.setAttribute("status", "OK");
SOAPElement in = el.addChildElement("response_code");
in.setValue("0000");
sm.writeTo(System.out);
I am trying to create a client for a Web Service that gets an int[] as input and as an output.
I found a sample of a Soap Request that shows how the SoapRequest can transfer an Array with Xml.
<element name="myFavoriteNumbers"
type="SOAP-ENC:Array"/>
<myFavoriteNumbers
SOAP-ENC:arrayType="xsd:int[2]">
<number>3</number>
<number>4</number>
</myFavoriteNumbers>
My code until now
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage sm = mf.createMessage();
SOAPHeader sh = sm.getSOAPHeader();
sh.setPrefix("S");
SOAPEnvelope envelope = sm.getSOAPPart().getEnvelope();
envelope.removeNamespaceDeclaration(envelope.getPrefix());
envelope.setPrefix("S");
envelope.addNamespaceDeclaration("S",
"http://schemas.xmlsoap.org/soap/envelope/");
SOAPBody sb = sm.getSOAPBody();
sb.setPrefix("S");
SOAPElement container=sb.addChildElement("sum", "ns2", webServicePkg);
SOAPElement a = container.addChildElement("number1");
a.addTextNode(Integer.toString(arg1));
SOAPElement b = container.addChildElement("number2");
b.addTextNode(Integer.toString(arg2));
All i need is to transform my current SoapMessage so it can reproduce the Example of Xml given so it can send this 2 numbers as an array and not each one apart.
Thank you very much
I am creating a Java client for a SOAP service that takes an attachment. I'm using java.xml.soap classes, which I have uses before, but not with attachments. The server claims that my attachment is not included.
I used SoapUI, which works, and wireshark to compare my SOAP message to a working SOAP message. One big difference is that my header does not include "start=".
The working Content-Type looks like this:
Content-Type: multipart/related; type="text/xml"; start=""; boundary="----=_Part_23_6341950.1286312374228"
The Content-Type I get from my Java code is like this:
Content-Type: multipart/related; type="text/xml"; boundary="----=_Part_23_6341950.1286312374228"
No start= even when the content ID is set on the root element. The working and failing SOAP messages are otherwise nearly identical. How can I get the start tag generated, or what are other reasons the server might not see the attachment?
Thanks
SOAPMessage soapMessage =
MessageFactory.newInstance().createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPBody body = soapEnvelope.getBody();
SOAPHeader header = soapMessage.getSOAPHeader();
soapPart.setContentId("<rootpart#here.com>");
MimeHeaders mimeHeaders = soapMessage.getMimeHeaders();
mimeHeaders.addHeader("SOAPAction", "addDocument");
mimeHeaders.addHeader("Accept-Encoding", "gzip,deflate");
Name bodyName = soapEnvelope.createName("Document", "doc",
"http://ns/Document");
SOAPBodyElement document = body.addBodyElement(bodyName);
Name filenameName = soapEnvelope.createName("Filename", "doc",
"http://ns/Document");
SOAPElement filename = document.addChildElement(filenameName);
filename.setValue("filename.txt");
AttachmentPart attachment = soapMessage.createAttachmentPart();
attachment.setContent("Some text", "application/octet-stream");
attachment.setMimeHeader("Content-Transfer-Encoding", "binary");
soapMessage.addAttachmentPart(attachment);
SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
SOAPConnection soapConnection = scf.createConnection();
URL url = new URL("http://host/Service");
SOAPMessage reply = soapConnection.call(soapMessage, url);
This works for me:
soapMessage.getMimeHeaders().setHeader("Content-Type",
soapMessage.getMimeHeaders().getHeader("Content-Type")[0]+
"; start=\"<rootpart#here.com>\"");