Wednesday, May 25, 2011

Jersey issue when running with ADF / Oracle XDK

We have discovered a late breaking bug in WLS that prevents Jersey applications from de-serializing XML and in some cases JSON documents. (So GET will work but PUT or POST will fail) This currently affects JDeveloper 11.1.1.5.0 aka PS4. You might see an exception that looks like this:

javax.xml.parsers.FactoryConfigurationError: WebLogicSAXParser
cannot be created.SAX feature
'
http://xml.org/sax/features/external-general-entities'
not
supported.
at weblogic.xml.jaxp.RegistrySAXParser.<init>(RegistrySAXParser.java:73)
at weblogic.xml.jaxp.RegistrySAXParser.<init>(RegistrySAXParser.java:46)
at
weblogic.xml.jaxp.RegistrySAXParserFactory.newSAXParser(RegistrySAXParserFacto
ry.java:91) 
...

When you create ADF components in an application you will find that at the .EAR level a weblogic-application.xml is created at deployment time which override the default WLS xml parser version to use the Oracle XDK version. You might see something like this:

<parser-factory>
<saxparser-factory>oracle.xml.jaxp.JXSAXParserFactory</saxparser-factory>
<document-builder-factory>oracle.xml.jaxp.JXDocumentBuilderFactory</document-builder-factory>
<transformer-factory>oracle.xml.jaxp.JXSAXTransformerFactory</transformer-factory>
</parser-factory>

When Jersey tries to convert a document to JAX-B classes it sensible sets a feature on the XML parser that prevents resolving external entities to prevent certain security attacks. This code in SAXParserContentProvider does understand that some parser don't support this feature as you can see:

@Override
    protected SAXParserFactory getInstance() {
        SAXParserFactory f = SAXParserFactory.newInstance();

        f.setNamespaceAware(true);
        
        if (!disableXmlSecurity) {
            try {
                f.setFeature("http://xml.org/sax/features/external-general-entities", Boolean.FALSE);
            } catch (Exception ex) {
                throw new RuntimeException("Security features for the SAX parser could not be enabled",  ex);
            }

            try {
                f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
            } catch (Exception ex) {
                LOGGER.log(Level.WARNING, 
                        "JAXP feature XMLConstants.FEATURE_SECURE_PROCESSING cannot be set on a SAXParserFactory. " +
                        "External general entity processing is disbaled but other potential securty related" +
                        " features will not be enabled.", 
                        ex);
            }
        }

        return f;
    }

This would normally be the end of it if it was not for bug 12543845, where the invalid features is incorrectly stored prevent the future creation of any parsers.

Luckily there is a workaround in Jersey, you can simply set this using a Servlet init param as follows:

<servlet>
    <servlet-name>jersey</servlet-name>
    <servlet-class>com.sun.jersey.
spi.container.servlet.ServletContainer</servlet-class>
   <init-param>

<param-name>com.sun.jersey.config.feature.DisableXmlSecurity</param-name>
      <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet> 

Be careful not to apply this property when you are not using the XDK parser otherwise you might open yourself up to a range of attacks which is not going to be a good thing.

Updated 30th March 2012: You might also need a similar workaround for the Jersey client as shown here. (I have raised this Jersey issue to see if this can be improved)

DefaultClientConfig cc = new DefaultClientConfig();
  cc.getFeatures().put(
    FeaturesAndProperties.FEATURE_DISABLE_XML_SECURITY, true);
  Client c = Client.create(cc);

Updated 15th August 2014: Slightly different for JAX-RS 2.0 client under Jersey, set this property on a configurable such as your client instance:

   configurable.property(MessageProperties.XML_SECURITY_DISABLE, Boolean.TRUE);


6 comments:

Harish said...

Thanks for the Anwser. The blog was useful.

Mohamad Hosafy said...

Thank you vey much.

If you don't mind can please clarify on what exactly the work around is other than the servlet parameter.

Where can I add the override of the
SAXParserFactory getInstance() ?

Gerard Davison said...

M,

That should be all that is required.

Gerard

Anuj said...

Hi Gerard,

I am facing same problem. I am using Jdev 12.1.3 and deploying my ADF application on weblogic 12.1.3. Are these issues still open? Ane idea?

Thanks,
Anuj

Gerard Davison said...

Anuj,

No this should be resolved by now, raise a bug with your support rep if this is still an issue.

Gerard Davison said...

Anuj,

No this should be resolved by now, raise a bug with your support rep if this is still an issue.