Skip to content

Harden JDBCJobStore deserialization: centralize getObjectFromBlob and support a JEP-290 ObjectInputFilter - #1494

Open
Nexory wants to merge 2 commits into
quartz-scheduler:mainfrom
Nexory:harden/jdbcjobstore-deserialization-filter
Open

Harden JDBCJobStore deserialization: centralize getObjectFromBlob and support a JEP-290 ObjectInputFilter#1494
Nexory wants to merge 2 commits into
quartz-scheduler:mainfrom
Nexory:harden/jdbcjobstore-deserialization-filter

Conversation

@Nexory

@Nexory Nexory commented Jul 10, 2026

Copy link
Copy Markdown

Summary

This centralizes the JDBCJobStore BLOB deserialization behind a single helper and adds support for a configurable JEP-290 ObjectInputFilter, so the job-data-map / trigger / calendar deserialization can be constrained in one place instead of being an unfiltered new ObjectInputStream(...).readObject() duplicated across the base delegate and every dialect delegate (CWE-502 hardening).

Discussion / design question (default policy): see the linked issue. Opening as a draft: the default is left as opt-in (no behavior change) pending the team's preference on the default filter policy.

Changes

  • Add StdJDBCDelegate.readObjectFromBinaryStream(InputStream), the single choke point that constructs the ObjectInputStream, applies the configured ObjectInputFilter (if any), and reads the object.
  • Route the base getObjectFromBlob() and all ten dialect overrides (PostgreSQLDelegate, MSSQLDelegate, OracleDelegate, HSQLDBDelegate, SybaseDelegate, WebLogicDelegate, PointbaseDelegate, CUBRIDDelegate, CacheDelegate, GaussDBDelegate) through it. Each delegate keeps its own dialect-specific stream fetching; only the deserialization step is shared.
  • Add an optional objectInputFilter field, configurable via the delegate init-string setting objectInputFilter=<JEP-290 pattern> (parsed with ObjectInputFilter.Config.createFilter). The init-string split is changed to split("=", 2) so filter patterns (which contain =) survive parsing.
  • No new dependencies (java.io.ObjectInputFilter is JDK 9+, this project targets Java 11).

Behavior

  • Default is unchanged. With no objectInputFilter configured, the field is null and deserialization behaves exactly as before.
  • When configured (e.g. org.quartz.jobStore.driverDelegateInitString = objectInputFilter=maxdepth=20;java.**;org.quartz.**;!*), the filter is applied at the single choke point for every BLOB the store reads back.

Testing

  • ./gradlew :quartz:compileJava succeeds on the Java 11 toolchain.
  • ./gradlew :quartz:test --tests StdJDBCDelegateTest: 7 passed, 0 failed. Two tests were added:
    • testReadObjectFromBinaryStreamWithoutFilterIsBehaviorPreserving: legitimate map round-trips unchanged with no filter.
    • testReadObjectFromBinaryStreamAppliesConfiguredFilter: a legitimate map still deserializes, while a class outside the configured allow-list is rejected (InvalidClassException).

Notes

Commits are DCO signed-off. This is a draft pending the default-policy discussion in the linked issue; happy to adjust the default (opt-in vs. a non-breaking resource-limit default vs. a reject-list) before finalizing.

Route the base StdJDBCDelegate.getObjectFromBlob() and the ten dialect
delegate overrides through a shared readObjectFromBinaryStream(InputStream)
helper, and add an optional, configurable ObjectInputFilter (JEP 290) that is
applied at that single point. The filter is set via the delegate init-string
setting objectInputFilter=<pattern>; when unset, deserialization behavior is
unchanged. No new dependencies (ObjectInputFilter is JDK 9+, this project
targets Java 11).

Adds StdJDBCDelegateTest coverage for the unfiltered (behavior-preserving)
and filtered (rejects a non-allow-listed class) paths.

Signed-off-by: Nexory <St4yl3r30@hotmail.de>
@Nexory
Nexory force-pushed the harden/jdbcjobstore-deserialization-filter branch from 898e0da to 2322cd9 Compare August 1, 2026 23:43
@Nexory
Nexory marked this pull request as ready for review August 2, 2026 00:08
@Nexory

Nexory commented Aug 2, 2026

Copy link
Copy Markdown
Author

Marking this ready for review. There has been no feedback on the default-policy question in #1495, so I have kept the non-breaking opt-in default (option a): the filter defaults to null, i.e. zero behavior change, and is fully overridable via the objectInputFilter=<pattern> delegate setting. CI is green across Java 11/17/21 and StdJDBCDelegateTest passes (7/7).

Happy to switch the default to the conservative resource-limit variant (b) or a documented reject-list (c) if the team prefers; either is a small follow-up on top of this change. Whatever default you choose, the central choke point stays the same.

@melloware

Copy link
Copy Markdown
Contributor

LGTM but i guess this needs the opinion of the maintainers.

@Nexory

Nexory commented Aug 6, 2026

Copy link
Copy Markdown
Author

@jhouserizer when you have a moment I'd appreciate a review. The only open item is the default
filter policy (#1495); I've kept it as a zero-behavior-change opt-in (defaults to null, fully
overridable via the objectInputFilter delegate setting), so it is safe to merge as-is. If you'd
prefer a conservative resource-limit default instead, that's a small follow-up and I'm happy to
adjust to whatever you pick. Thanks!

@jhouserizer

jhouserizer commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

@Nexory - This looks good - I'm remote next few days (just on my phone )- I think how you've defaulted it is fine - would you mind adding a bit of update to doc/examples about how to use it? Even just incorporating the example into an existing one, or something? e.g. https://github.com/quartz-scheduler/quartz/tree/main/examples , https://github.com/quartz-scheduler/quartz-scheduler.org-site/tree/master/documentation/quartz-2.5.x/configuration

@Nexory

Nexory commented Aug 6, 2026

Copy link
Copy Markdown
Author

Thanks! Added a commented, off-by-default example of the objectInputFilter setting to the JDBC/clustering example (example13), showing the ObjectInputFilter pattern syntax on driverDelegateInitString. It stays disabled by default, so the example runs unchanged.

Adds a commented, off-by-default example of the objectInputFilter delegate
setting to the JDBC/clustering example (example13), showing the
java.io.ObjectInputFilter pattern syntax on driverDelegateInitString. The
line stays disabled by default, so the example runs unchanged.

Signed-off-by: Nexory <St4yl3r30@hotmail.de>
@Nexory
Nexory force-pushed the harden/jdbcjobstore-deserialization-filter branch from 9bf2631 to 248febf Compare August 6, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

is:enhancement Enhancement to an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Harden JDBCJobStore deserialization: centralize getObjectFromBlob and support a JEP-290 ObjectInputFilter

3 participants