Restlet client on Java 1.7 xml parse error “FEATUR

2019-09-16 16:24发布

问题:

EDIT : 31/OCT/2014 The fix for this is now available in both Restlet 2.2 and master (future 2.3) branches

Our Netbeans Platform Restlet client app runs okay on Java 1.6 but with 1.7.0_11, I get security runtime errors.

Is there a easy way to prevent this?

WARN org.restlet.log():241 - Unable to unmarshal the XML representation
javax.xml.bind.JAXBException: Unable to create customized SAX source
 - with linked exception:
[javax.xml.parsers.ParserConfigurationException: FEATURE_SECURE_PROCESSING: Cannot set the feature to false when security manager is present.]
            at org.restlet.ext.jaxb.internal.Unmarshaller.unmarshal(Unmarshaller.java:201)
            at org.restlet.ext.jaxb.JaxbRepresentation.getObject(JaxbRepresentation.java:417)
            at org.restlet.ext.jaxb.JaxbConverter.toObject(JaxbConverter.java:172)
            at org.restlet.service.ConverterService.toObject(ConverterService.java:167)
            at org.restlet.resource.Resource.toObject(Resource.java:828)
            at org.restlet.engine.resource.ClientInvocationHandler.invoke(ClientInvocationHandler.java:240)
            <SNIP>
Caused by: javax.xml.parsers.ParserConfigurationException: FEATURE_SECURE_PROCESSING: Cannot set the feature to false when security manager is present.
            at com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl.setFeature(SAXParserFactoryImpl.java:122)
            at org.restlet.ext.jaxb.internal.Unmarshaller.unmarshal(Unmarshaller.java:190)
            ... 23 more

In both java runtimes, my System.getSecurityManager() is a instance of org.netbeans.TopSecurityManager

EDIT 1

After a bit more research into Restlet source as mentioned in answer from Simon Lehmann I see JaxbConverter.java invokes

new JaxbRepresentation<T>(Representation source, Class<T> target).getObject();

Then ...

public JaxbRepresentation(Representation xmlRepresentation, Class<T> type) { ...}

Then ...

public JaxbRepresentation(Representation xmlRepresentation, String contextPath, ValidationEventHandler validationHandler, ClassLoader classLoader) {
    super((xmlRepresentation == null) ? null : xmlRepresentation
            .getMediaType());
    this.classLoader = classLoader;
    this.contextPath = contextPath;
    this.object = null;
    this.validationEventHandler = validationHandler;
    this.xmlRepresentation = xmlRepresentation;
}

In this particular constructor, this.secureProcessing always remains false so later we get errors with Java 7 secure processing feature of the XML parser if there is any security manager present.

Not sure if this is a bug in restlet or if I am doing something wrong ?

EDIT 2 (Simple Java 7 app vs one in full app)

I wrote small restlet client test program on 1.7.0_11 which works ok with our server. I am guessing in my full client app that there is something 'bad' in the classpath ?

In both the small app and the full app I print the factories and it is same in both :

 [exec] DocumentBuilderFactory implementation: com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl loaded from: Java Runtime
 [exec] XPathFactory implementation: com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl loaded from: Java Runtime
 [exec] TransformerFactory implementation: com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl loaded from: Java Runtime
 [exec] SAXParserFactory implementation: com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl loaded from: Java Runtime

I switch on extra JAXP logging via System.setProperty("jaxp.debug", "true"); and see it is different in each :


Small working app

[junit] JAXP: find factoryId =javax.xml.datatype.DatatypeFactory
[junit] JAXP: loaded from fallback value: com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl
[junit] JAXP: created new instance of class com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl using ClassLoader: null

[junit] JAXP: find factoryId =javax.xml.datatype.DatatypeFactory
[junit] JAXP: loaded from fallback value: com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl
[junit] JAXP: created new instance of class com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl using ClassLoader: null
[junit] JAXP: using thread context class loader (sun.misc.Launcher$AppClassLoader@6c5bdfae) for search
[junit] JAXP: Looking up system property 'javax.xml.xpath.XPathFactory:http://java.sun.com/jaxp/xpath/dom'
[junit] JAXP: The property is undefined.
[junit] JAXP: found null in $java.home/jaxp.properties
[junit] JAXP: no META-INF/services/javax.xml.xpath.XPathFactory file was found
[junit] JAXP: attempting to use the platform default W3C DOM XPath lib
[junit] JAXP: createInstance(com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl)
[junit] JAXP: loaded com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl from jar:file:/Library/Java/JavaVirtualMachines/jdk1.7.0_11.jdk/Contents/Home/jre/lib/rt.jar!/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.class
[junit] JAXP: factory 'com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl' was found for http://java.sun.com/jaxp/xpath/dom

[junit] JAXP: find factoryId =javax.xml.transform.TransformerFactory
[junit] JAXP: loaded from fallback value: com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
[junit] JAXP: created new instance of class com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl using ClassLoader: null

Full Netbeans app (failing)

 [exec] JAXP: using thread context class loader (SystemClassLoader[420 modules]) for search
 [exec] JAXP: Looking up system property 'javax.xml.xpath.XPathFactory:http://java.sun.com/jaxp/xpath/dom'
 [exec] JAXP: The property is undefined.
 [exec] JAXP: found null in $java.home/jaxp.properties
 [exec] JAXP: no META-INF/services/javax.xml.xpath.XPathFactory file was found
 [exec] JAXP: attempting to use the platform default W3C DOM XPath lib
 [exec] JAXP: createInstance(com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl)
 [exec] JAXP: loaded com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl from jar:file:/Library/Java/JavaVirtualMachines/jdk1.7.0_11.jdk/Contents/Home/jre/lib/rt.jar!/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.class
 [exec] JAXP: factory 'com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl' was found for http://java.sun.com/jaxp/xpath/dom
 [exec] JAXP: find factoryId =javax.xml.transform.TransformerFactory
 [exec] JAXP: found jar resource=META-INF/services/javax.xml.transform.TransformerFactory using ClassLoader: SystemClassLoader[420 modules]
 [exec] JAXP: loaded from fallback value: com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
 [exec] JAXP: created new instance of class com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl using ClassLoader: null

回答1:

I encountered the same problem - exactly - when I upgraded from restlet 2.2m1 running on Java 6 to restlet 2.2m5 running on Java 7.

The solution I resorted to was to initialize the secureProcessor flag in the JaxbRepresentation constructor you mentioned to true (and rebuild the restlet code). That resolved the problem for me. It is not clear if the lack of initialization of the secureProcessing flag in that constructor is intentional or is an oversight.

I filed a bug about it: https://github.com/restlet/restlet-framework-java/issues/785



回答2:

As it seems, JDK 7 (Oracle as well as OpenJDK/IcedTea) has added a check to prevent disabling the so called secure processing feature of the XML parser if there is any security manager present. This feature is meant to prevent denial of service attacks, for example by providing a SOAP message with deeply nested entity definitions. Unfortunately, they have opted to disable control over this feature in general when a security manager is found instead of allowing you to configure it via security permissions.

However, the restlet code which tries to set this feature to false is actually using the secureProcessing property of the JaxbRepresentation, which should be set to true by default and thus, should not cause any exception.

So the only adivce I could give you is to try updating the restlet library, as maybe the default settings or something else related to this has changed.