Abhishek Singh
Abhishek Singh

Reputation: 625

org.xml.sax.SAXNotRecognizedException: Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized

I want to prevent a XXE attack in my project. It's old api project which runs on java 7 (no maven) and jboss-as-7 server. But during the execution i get the error: org.xml.sax.SAXNotRecognizedException: Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.

 org.xml.sax.SAXNotRecognizedException: Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.

15:19:02,845 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at org.apache.xerces.jaxp.validation.ValidatorImpl.setProperty(ValidatorImpl.java:218)

15:19:02,846 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at com.uid.kua.web.KUARestController.authenticateAtAUA(KUARestController.java:118)

15:19:02,847 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

15:19:02,847 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

15:19:02,848 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

15:19:02,849 ERROR [stderr] (http-localhost-127.0.0.1-8080-3)   at java.lang.reflect.Method.invoke(Method.java:606)

I have searched about it and every forum has some different meaning to it saying it's a bug. I have not found any relevant solution for this exception. Please help. Thanks in advance.

Upvotes: 17

Views: 46400

Answers (8)

times29
times29

Reputation: 3373

In my case I added the following dependency for Pact tests and suddenly other tests failed due to the following exception: org.xml.sax.SAXNotRecognizedException: Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.. The dependency I added was this:

<dependency>
    <groupId>au.com.dius.pact.provider</groupId>
    <artifactId>junit5</artifactId>
    <scope>test</scope>
</dependency>

To make it work I excluded xerces as follows:

<dependency>
    <groupId>au.com.dius.pact.provider</groupId>
    <artifactId>junit5</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
        </exclusion>
    </exclusions>
</dependency>

After that everything worked as before.

Upvotes: 1

Ed Gomoliako
Ed Gomoliako

Reputation: 1038

I tend to agree with the opinion of the author (@searchengine27) of the first comment on the accepted answer. Patching container configuration doesn't look like a robust and maintainable solution.

For instance, with the JBoss Wildfly installation, I got only one place where the mentioned module was defined, but with the JBoss EAP 7.4 patched to work under Java 17 there were two places, thus having the container updated just ruined the working program.

It's also worth mentioning that JBoss is provided with the particular implementation of javax.api on purpose (tested security, etc.) and one should think twice before deciding to turn it off.

I encountered the same problem with a third-party library instantiating Schemafactory and setting the accessExternalDTD property to it.

Everything worked well when the application was running in a Docker container under OpenJDK17 and got into trouble running inside the JBoss container.

The solution I propose is to provide with your program an implementation of SchemaFactory that leverages either org.apache.xerces implementation, or the default one from the JDK (OpenJDK17 in my case).

I've chosen the latter because I found it newer and supports the next version of the JAXP standard.

Here is the code of the Jdk17DefaultSchemaFactoryWrapper class:

package my.package.utils.jaxp;

import lombok.experimental.Delegate;

import javax.xml.validation.SchemaFactory;

public class Jdk17DefaultSchemaFactoryWrapper extends SchemaFactory {
  @Delegate
  SchemaFactory factory = SchemaFactory.newDefaultInstance();
}

Instead SchemaFactory.newDefaultInstance() probably SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI, "com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory", ClassLoader.getSystemClassLoader()) could be used to make sure that the SchemaFactory from the JDK gets used.

And the Jdk17DefaultSchemaFactoryWrapper class has to be registered as javax.xml.validation.SchemaFactory. I've done it via creating a file META-INF/services/javax.xml.validation.SchemaFactory and putting the full quilified name of the Jdk17DefaultSchemaFactoryWrapper class as its contents.

As Mr. @Appernicus provided in his answer to this question, other ways could be approached to get done the same.

Alternative Solution

An alternative solution would be to use the implementation provided by the container.

To do that, one would need to add the org.apache.xerces dependency with the scope: provided to their POM and the following XMLSchemaFactoryWrapper implementation:

package com.temenos.multifonds.integration.integrationBroker.utils.jaxp;

import lombok.experimental.Delegate;
import org.apache.xerces.jaxp.validation.XMLSchemaFactory;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;

import javax.xml.XMLConstants;
import javax.xml.validation.SchemaFactory;

public class XMLSchemaFactoryWrapper extends SchemaFactory {
  @Delegate(excludes = DelegateExclude.class)
  SchemaFactory factory = new XMLSchemaFactory();

  @Override
  public void setProperty(String name, Object object) throws SAXNotRecognizedException, SAXNotSupportedException {
    if (XMLConstants.ACCESS_EXTERNAL_DTD.equals(name))
      return;

    super.setProperty(name, object);
  }

  private interface DelegateExclude {
    void setProperty(String name, Object value);
  }
}

As you might notice, the problem with this solution is that the accessExternalDTD property actually gets ignored.

In my case, it wasn't a problem because XML schemas didn't use external schemas and the property was set by the third party to cover some future cases.

Though, knowing pros and cons and limitations of the provided solutions it should be possible to find the one that suits your particular case.

Upvotes: -1

Appernicus
Appernicus

Reputation: 464

javax.xml loads the implementation of certain Factory interfaces by going through a couple of options. First option is to configure a default implementation through a system property. For example:

javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema = com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory
javax.xml.parsers.DocumentBuilderFactory = com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

The second option is to use the jaxb.properties file which you have to include in your jre or jdk how you can do do that is described here: https://docs.oracle.com/javase/tutorial/jaxp/properties/usingProps.html

The third option is to add a file in META-INF/services of which the name should be the Factory interface that you want to define the implementation for and the file should contain the full package name + class name of the implementation. For example, you can add a file called javax.xml.parsers.DocumentBuilderFactory containing com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

The fourth option is to select the default implementation. In the case of Wildfly/Jboss they have included an org.apache.xerces implementation which only support JAXP 1.4. This means that it will select this implementation and that's why you get the error.

To find out which implementation is used for your specific function you can add a system property

jaxp.debug = 1

This property will enable debug mode for jaxp and you will see the following output:

JAXP: using thread context class loader (ModuleClassLoader for Module "deployment.css-private-build-1.0-SNAPSHOT.ear.css-private.war" from Service Module Loader) for search
JAXP: Looking up system property 'javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema'
JAXP: The value is 'com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory'
JAXP: createInstance(com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory)
JAXP: loaded com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory from (no code source)
JAXP: factory 'com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory' was found for http://www.w3.org/2001/XMLSchema

So before your error you will see the JAXP debug logging and then you should know which factory you have to provide an implementation for to get it to work.

Upvotes: 4

snukone
snukone

Reputation: 332

Thanks for Hint regarding xerces.

My Error-Message when running Java tests during a Maven Build (mvn verify) look like this:

Property 'http://javax.xml.XMLConstants/property/accessExternalDTD' is not recognized.

I solved it this way:

mvn dependency:tree

Finding the Dependency which is inheriting xerces:

[INFO] +- au.com.dius.pact:consumer:jar:4.2.9:test
[INFO] |  +- au.com.dius.pact.core:model:jar:4.2.9:test
[INFO] |  |  +- org.apache.commons:commons-collections4:jar:4.1:test
[INFO] |  |  +- com.github.mifmif:generex:jar:1.0.2:test
[INFO] |  |  +- javax.mail:mail:jar:1.5.0-b01:test
[INFO] |  |  +- org.apache.tika:tika-core:jar:1.27:test
[INFO] |  |  \- io.ktor:ktor-http-jvm:jar:1.3.1:test
[INFO] |  |     +- org.jetbrains.kotlinx:atomicfu:jar:0.14.1:test
[INFO] |  |     +- org.jetbrains.kotlinx:kotlinx-coroutines-core:jar:1.3.3:test
[INFO] |  |     +- org.jetbrains.kotlinx:kotlinx-coroutines-core-common:jar:1.3.3:test
[INFO] |  |     \- io.ktor:ktor-utils-jvm:jar:1.3.1:test
[INFO] |  |        \- io.ktor:ktor-io-jvm:jar:1.3.1:test
[INFO] |  +- au.com.dius.pact.core:matchers:jar:4.2.9:test
[INFO] |  |  +- xerces:xercesImpl:jar:2.12.0:test

And excluded xerces in the corresponding Dependency in the Maven Pom.xml:

       <dependency>
            <groupId>au.com.dius.pact</groupId>
            <artifactId>consumer</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <artifactId>aws-java-sdk-s3</artifactId>
                    <groupId>com.amazonaws</groupId>
                </exclusion>                
                <exclusion>
                    <groupId>xerces</groupId>
                    <artifactId>xercesImpl</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

Upvotes: 1

Matheus Pinheiro
Matheus Pinheiro

Reputation: 21

In my case, I had a similar issue, but related to the SAXParser, when setting the props: XMLConstants.ACCESS_EXTERNAL_DTD and XMLConstants.ACCESS_EXTERNAL_SCHEMA.

The solution following Michael's suggestion was to specify the classname to be used by the SAXParserFactory (I am using JDK 8)

final SAXParserFactory factory = SAXParserFactory.newInstance("com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl", ClassLoader.getSystemClassLoader());

Upvotes: 2

Leonid Balikhin
Leonid Balikhin

Reputation: 11

good answer - https://stackoverflow.com/a/62404699 It's just example of a code (work with java 11 and jboss 7.3):

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
 DocumentBuilder builder = dbf.newDocumentBuilder();

 ByteArrayInputStream input = new ByteArrayInputStream(xmlDocument.getBytes(encoding));
 org.w3c.dom.Document doc = builder.parse(input);
 DOMBuilder domBuilder = new DOMBuilder();

 Document docJdom = domBuilder.build(doc);

Upvotes: 0

Michael
Michael

Reputation: 161

It seems that the attributes accessExternalDTD and accessExternalSchema were introduced in JAXP 1.5. However, Java EE 6 (and even still Java EE 8) only comes with JAXP 1.4.

In my case (running on WildFly 19 and AdoptOpenJDK 11) I was able to obtain the JDK's default instances of DocumentBuilderFactory and SchemaFactory by using their static newDefaultInstance() method which was introduced in Java 9. In Java 8 both classes also have a newInstance method where you can specify the class name, i.e. com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl and com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.

This solution avoids changing the JBoss modules.

Upvotes: 14

Abhishek Singh
Abhishek Singh

Reputation: 625

Finally i resolved it. I am posting the answer in case this helps anyone. After going through online solutions i was unable to detect the main issue which was causing the above error. For xxe prevention we need some defined properties like: XMLConstants.ACCESS_EXTERNAL_DTD XMLConstants.ACCESS_EXTERNAL_SCHEMA

We need xerces and jaxp-api jars to pasrse xml and prevent xxe provided by the api's to resolve the xml by setting some above properties. Prior to JDK 7 these are already included in JDK 7 and above. So we don't need to import above jars in our project classpath.

In my case i was using jboss-as-7.1.1.Final as application server which also has it's own xerces jar (org.apache.xerces.). But java also comes with it's own xerces and jaxp implementation (com.sun.xerces.). So while deploying the war we get the above error as both these jars conflicts with each other where jboss loads it's own xerces jars.

Solution: We need to exclude the jboss xerces implementation by making changes in jboss/org/apache/xerces/main/modules.xml file. Comment out the lines as shown below:

> <module xmlns="urn:jboss:module:1.1" name="org.apache.xerces">    
> <!--
>     <resources>
>         <resource-root path="xercesImpl-2.9.1-jbossas-1.jar"/>
>         Insert resources here
>     </resources>
> -->
>     <dependencies>
>         <module name="javax.api"/>
>     </dependencies>
> 
> </module>

Now deploy and run your application. Happy coding.

Upvotes: 22

Related Questions