Java – can I enforce strict validation of base64binary data in jax-ws?
tl; Dr version: is there any way to force jax-ws strict mode to reject invalid Base64 of base64binary XSD data type?
Longer version: I have a web service that receives binary data, which is mapped to XSD type base64binary When testing the service, I found that Jax - WS is very loose in parsing Base64 strings No matter how invalid my input is, I can't make Jax - WS error
I created a small test service and client to illustrate the problem It can be copied more or less verbatim:
Service interface:
@WebService
public interface ITest2 {
@WebMethod
void foo(byte[] bs);
}
Service implementation and testing:
@WebService(endpointInterface="foo.bar.ITest2")
public class Test2 implements ITest2 {
private static final String requestTemplate = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:bar=\"http://bar.foo/\">" +
"<soapenv:Header/>" +
"<soapenv:Body>" +
"<bar:foo>" +
"<arg0>%s</arg0>" +
"</bar:foo>" +
"</soapenv:Body>" +
"</soapenv:Envelope>";
private static final String[] testVector = {
"////==","///==","//==","/==","/==/==/==","<>","=====","%%%///%%%==%%"
};
private static PrintWriter pw;
static {
try {
pw = new PrintWriter("/tmp/output");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
Endpoint e = Endpoint.publish("http://localhost:54321/foo",new Test2());
URL requestUrl = new URL("http://localhost:54321/foo");
for(String testVal : testVector) {
pw.println("[client] >" + testVal + "<");
HttpURLConnection urlc = (HttpURLConnection) requestUrl.openConnection();
urlc.setRequestProperty("Content-Type","text/xml;charset=UTF-8");
urlc.setDoOutput(true);
OutputStream out = urlc.getOutputStream();
String request = String.format(requestTemplate,testVal);
out.write(request.getBytes());
out.flush();
InputStream in = urlc.getInputStream();
int read = -1;
byte[] buf = new byte[1024];
while((read = in.read(buf)) != -1) {
System.err.print(new String(buf,read));
}
System.err.println();
}
pw.flush();
pw.close();
}
@Override
public void foo(byte[] bs) {
String encoded;
if(bs == null) {
encoded = "<null>";
} else if(bs.length == 0) {
encoded = "<empty>";
} else {
encoded = new String(Base64.encodeBase64(bs));
}
pw.println("[server] >" + encoded + "<");
}
}
This produces the following output in / TMP / output (I use jetty, which records a lot on the console and doesn't want to disturb it):
[client] >////==< [server] ><null>< [client] >///==< [server] ><null>< [client] >/w==< [server] >/w==< [client] >/==< [server] ><null>< [client] >/==/==/==< [server] >/////w==< [client] ><>< [server] ><empty>< [client] >=====< [server] >/w==< [client] >%%%///%%%==%%< [server] >//8=<
So this is a complete mess Sometimes I receive null, sometimes empty strings, and sometimes garbage is replaced by other garbage In addition, each request generates an HTTP reply 200, so no one knows the problem
I know you can force JAXB to verify this by adding a schema to the unmarshaller Since Jax - WS uses JAXB internally, I hope it is possible to enable it for web services Does anyone know if and how this is possible?
I use Oracle Java 1.6.0 on Ubuntu 0_ The default Jax - WS implementation of 24
Solution
You can add com. On the endpoint implementation sun. xml. internal. ws. developer. Schema validation annotation (test2) enables schema validation in Metro (jaxws - RI)
This causes soap errors in the form:
...
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>com.sun.istack.internal.XMLStreamException2:
org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1:
'foo' is not a valid value for 'base64Binary'.</faultstring>
...
Technically, I think the faultcode should be s: client, but I know what
As far as I know, there is no implementation independent way to do this; Therefore, if you deploy your code in another Jax - WS container, you must use the mechanism of that container
