Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent Quartz XSD from being fetched from the Internet [SPR-13706] #18281

Closed
spring-issuemaster opened this issue Nov 19, 2015 · 3 comments
Closed

Comments

@spring-issuemaster
Copy link
Collaborator

@spring-issuemaster spring-issuemaster commented Nov 19, 2015

Mathieu Lachance opened SPR-13706 and commented

Quartz offer classloading spi through the org.quartz.spi.ClassLoadHelper interface.

Spring implements ClassLoadHelper in the ResourceLoaderClassLoadHelper which is use as the default Quartz value for 'org.quartz.scheduler.classLoadHelper.class'.

When I'm deploying my application inside JBoss EAP 6.1 and/or Wildfly 8.2.1.Final, the "job_scheduling_data_2_0.xsd" is getting hit from the Internet because it failed to fetch it properly from the classpath.

XMLSchedulingDataProcessorPlugin::processFile(JobFile) -> XMLSchedulingDataProcessor(classLoadHelper) -> resolveSchemaSource()

try {
    is = classLoadHelper.getResourceAsStream(QUARTZ_XSD_PATH_IN_JAR);
}  finally {
    if (is != null) {
        inputSource = new InputSource(is);
        inputSource.setSystemId(QUARTZ_SCHEMA_WEB_URL);
        log.debug("Utilizing schema packaged in local quartz distribution jar.");
    }
    else {
        log.info("Unable to load local schema packaged in quartz distribution jar. Utilizing schema online at " + QUARTZ_SCHEMA_WEB_URL);
        return QUARTZ_SCHEMA_WEB_URL;
    }
        }

by enabling the org.quartz.xml.XMLSchedulingDataProcessor logger you'll see that inside a container the "Unable to load local schema packaged in quartz distribution jar" trace will appear.
This is especially problematic in production environment where generally machines do not have access to the Internet and/or a very limitated access for security reasons.

Here's our temporary workaround which involve of prefixing "classpath:" to any XSD resource:

public class ResourceLoaderHelper extends ResourceLoaderClassLoadHelper {

    private static final String XSD_FILE_EXTENSION = ".xsd";

    @Override
    public URL getResource(String name) {
        if (name != null && name.endsWith(XSD_FILE_EXTENSION) && !name.startsWith(CLASSPATH_URL_PREFIX)) {
            return super.getResource(CLASSPATH_URL_PREFIX.concat(name));
        } else {
            return super.getResource(name);
        }
    }

    @Override
    public InputStream getResourceAsStream(String name) {
        if (name != null && name.endsWith(XSD_FILE_EXTENSION) && !name.startsWith(CLASSPATH_URL_PREFIX)) {
            return super.getResourceAsStream(CLASSPATH_URL_PREFIX.concat(name));
        } else {
            return super.getResourceAsStream(name);
        }
    }
}

This workaround always retreive the XSD resource properly from the classpath. This work, though, this is definitely ugly.

I would suggest instead of our ugly workaround to simply change the Spring implementation to:

  1. check if the resource is found using the original location
  2. if not, prefix "classpath:" to the original location, and check again
  3. if it is yet not found, just return null and fail with the current behavior.

Let me know if I've miss something.

Thanks,


Affects: 3.2.16, 4.2.2

Referenced from: commits 51f356f, 7c998a7, 6db6f23

Backported to: 3.2.17

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Jan 19, 2016

Stéphane Nicoll commented

That's not what I experience with a vanilla setup. We have an integration test with no special configuration and a lookup for org/quartz/xml/job_scheduling_data_2_0.xsd ends up in org.springframework.core.io.DefaultResourceLoader that returns a resource from the classpath. The resource is therefore properly resolved. Where is quartz.jar located in your environment?

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Apr 5, 2016

Sven-Erik Petermann commented

I can confirm the issue for Spring 4.2.4, Quartz 2.2.2.
For completeness: location == "org/quartz/xml/job_scheduling_data_2_0.xsd".
org.springframework.core.io.DefaultResourceLoader.getResource(String location) throws java.net.MalformedURLException after deciding that:

  • location does not start with "/";
  • location does not start with CLASSPATH_URL_PREFIX;
  • location is not a valid URL.

This is the top of the stack trace:

AnnotationConfigWebApplicationContext(DefaultResourceLoader).getResource(String) line: 105	
ResourceLoaderClassLoadHelper.getResourceAsStream(String) line: 103	
XMLSchedulingDataProcessor.resolveSchemaSource() line: 222	
XMLSchedulingDataProcessor.initDocumentParser() line: 175	
XMLSchedulingDataProcessor.<init>(ClassLoadHelper) line: 159	
XMLSchedulingDataProcessorPlugin.processFile(XMLSchedulingDataProcessorPlugin$JobFile) line: 313	
XMLSchedulingDataProcessorPlugin.start(UserTransaction) line: 246	
XMLSchedulingDataProcessorPlugin(SchedulerPluginWithUserTransactionSupport).start() line: 144	
QuartzScheduler.startPlugins() line: 2407	
QuartzScheduler.start() line: 568	
StdScheduler.start() line: 142	
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Apr 5, 2016

Juergen Hoeller commented

Thanks for raising this! Indeed, we should not rely on the getResourceByPath code path there, in particular since that one is not bound to check the classpath at all (e.g. in Servlet environments where such plain resource lookups go through the ServletContext).

Our ResourceLoaderClassLoadHelper explicitly falls back to a classpath lookup now if the ResourceLoader-obtained handle does not exist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.