开发者

Can I enforce strict validation of base64Binary data in JAX-WS?

tl;dr version: Is there a way to force a strict mode for JAX-WS that rejects invalid base64 for the base64Binary XSD data type?


Longer version: I have a web service that receives binary data which gets mapped to the XSD type base64Binary. While testing the service I found out that JAX-WS is very lenient when it comes to parsing of Base64 strings. No matter how invalid my input was, I could not get JAX-WS to produce an error.

I created a small test service and client that illustrates the problem. It can be copied more or less verbatim:

Service interface:

@WebService
public interface ITest2 {
    @WebMethod
    void foo(byte[] bs);
}

Service implementation and test:

@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 = {
        "////==",
        "///==",
        "//==",
        "/==",
        "/==/==/==",
        "&lt;&gt;",
        "=====",
        "%%%///%%%==%%"
    };

    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, 0, 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'm using Jetty which logs quite a lot to the console and didn't want to bother with that):

[client] >////==<
[server] ><null><
[client] >///==<
[server] ><null><
[client] >/w==<
[server] >/w==<
[client] >/==<
[server] ><null><
[client] >/==/==/==<
[server] >/////w==<
[client] >&lt;&gt;<
[server] ><empty><
[client] >=====<
[server] >/w==<
[client] >%%%///%%%==%%<
[server] >//8=<

So it's a complete mess. Sometimes I receive null, sometimes an empty string and sometimes garbage gets replaced by other garbage. Also every request produces an HTTP reply 200 so nobody knows that anywhere something went wrong.

I know that you can force JAXB to validate this by adding a schema to an Unmarshaller. Since JAX-WS uses JAXB internally I hope that there is a possibility to turn that on for web services as well. Does anybody know if that's possible and how?

I use the default JAX-WS implementation from Oracle Java 1.6.0_24 on Ubuntu.


You can enable schema validation in Metro (the JAXWS-RI) by adding the com.sun.xml.internal.ws.developer.SchemaValidation annotation on your endpoint implementation - Test2.

This causes a SOAP fault of 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 believe that faultcode should be S:Client, but what do I know.

To the best of my knowledge there is no implementation agnostic way to do this; so if you deploy the code in another JAX-WS container, you'll have to use the mechanism for that container.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜