This is an automated email from the ASF dual-hosted git repository.
tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new 17812252de Update serialization docs (#2924)
17812252de is described below
commit 17812252de89f232abb50c8c3d4e1fe3b92d22c5
Author: Tim Allison <[email protected]>
AuthorDate: Thu Jul 2 16:53:46 2026 -0400
Update serialization docs (#2924)
---
.../ROOT/pages/developers/serialization.adoc | 56 ++++++++++++++++++++++
.../pages/migration-to-4x/design-notes-4x.adoc | 18 ++++---
.../pages/migration-to-4x/serialization-4x.adoc | 24 ++++++++--
.../tika/serialization/ComponentNameResolver.java | 11 +++--
4 files changed, 93 insertions(+), 16 deletions(-)
diff --git a/docs/modules/ROOT/pages/developers/serialization.adoc
b/docs/modules/ROOT/pages/developers/serialization.adoc
index 238adf1552..84037c6a78 100644
--- a/docs/modules/ROOT/pages/developers/serialization.adoc
+++ b/docs/modules/ROOT/pages/developers/serialization.adoc
@@ -251,6 +251,62 @@ for instantiation.
}
----
+=== Untrusted (Wire) Input: Restricted Mode
+
+Configuration files loaded at startup via `TikaLoader` are treated as trusted.
+Per-request configuration arriving over the wire — tika-server request bodies
+and pipes `FetchEmitTuple`s — is deserialized in *restricted mode*
+(`ParseContextDeserializer.readParseContext(node, true)`), which adds a second,
+fail-closed gate on top of the registry:
+
+* Only context-key types confined to shaping this request's metadata or output
+ may be instantiated from the wire: `MetadataFilter`, `ContentHandlerFactory`,
+ `ContentHandlerDecoratorFactory`, `DigesterFactory`,
+ `MetadataWriteLimiterFactory`, `UnpackSelector`
+* Types with exec/IO/network capability or control over which components run
+ are blocked: `Parser`, `Detector`, `EncodingDetector`, `Renderer`,
+ `Translator`, `EmbeddedDocumentExtractorFactory`
+* The check is fail-closed: a newly added context-key interface is blocked
until
+ it is consciously allow-listed
+* The whole tree is scanned *before* any component is constructed
+
+The allowlist/blocklist lives in `ComponentNameResolver`
+(`WIRE_INSTANTIABLE_CONTEXT_KEYS` / `WIRE_BLOCKED_CONTEXT_KEYS`); an
+exhaustiveness test asserts every context-key interface is classified as
+exactly one of the two. Plain config DTOs (non-component keys) are never
+blocked.
+
+== Framework Directives
+
+Some JSON keys are consumed by the loading framework itself rather than by the
+component whose config object they appear in. When such a directive shares a
+JSON object with a component's own properties, it carries a leading underscore
+to avoid namespace collisions with legitimate component config keys:
+
+[source,json]
+----
+{
+ "parsers": [
+ {
+ "pdf-parser": {
+ "_mime-include": ["application/pdf"],
+ "_mime-exclude": ["application/pdf+fdf"],
+ "extractInlineImages": true
+ }
+ }
+ ]
+}
+----
+
+`_mime-include`/`_mime-exclude` are stripped before the component sees its
+config and are applied by the framework as a MIME-filtering decorator around
+the parser. New framework directives must follow the underscore convention.
+
+Marker entries that have no component-config namespace of their own are the
+exception: `"exclude"` on `default-parser`/`default-detector`/
+`default-encoding-detector` needs no prefix because those markers carry only
+framework keys.
+
== Creating a Custom Component
Complete example of a custom metadata filter:
diff --git a/docs/modules/ROOT/pages/migration-to-4x/design-notes-4x.adoc
b/docs/modules/ROOT/pages/migration-to-4x/design-notes-4x.adoc
index d8e027d496..7913fafefb 100644
--- a/docs/modules/ROOT/pages/migration-to-4x/design-notes-4x.adoc
+++ b/docs/modules/ROOT/pages/migration-to-4x/design-notes-4x.adoc
@@ -61,16 +61,22 @@ IMPORTANT: We tried to have as few Tika dependencies in the
plugins as possible.
=== Security Model
-Configuration files at initialization are treated as trusted sources. Runtime
-serialization/deserialization uses an allowlist of permitted packages via
-`PolymorphicObjectMapperFactory`.
-
-Custom components can add patterns to
`META-INF/tika-serialization-allowlist.txt`.
+Configuration files at initialization are treated as trusted sources. Component
+instantiation from JSON is restricted to classes registered at compile time by
+the `@TikaComponent` annotation processor (`META-INF/tika/*.idx` files);
unknown
+class names are rejected, and there is no Jackson default typing.
+
+Untrusted per-request configuration (tika-server requests, pipes
+`FetchEmitTuple`s) is deserialized in a restricted mode that additionally
applies
+a fail-closed allowlist of context-key types: only metadata/output-shaping
+components (e.g. `MetadataFilter`, `ContentHandlerFactory`, `DigesterFactory`)
+may be bound from the wire; `Parser`, `Detector`, `Renderer`, and similar are
+blocked before anything is constructed. See
+xref:developers/serialization.adoc[Serialization and Configuration].
=== Implementation Challenges
* Converted code to true Java beans with matching getters/setters
-* Used `ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE` for polymorphic
typing
* Replaced generic collections (`List`, `Set`) with concrete types
(`ArrayList`, `HashSet`)
* Converted `Path` fields to `String` due to Jackson constraints
* Avoided Java records to enable `readerForUpdating` functionality
diff --git a/docs/modules/ROOT/pages/migration-to-4x/serialization-4x.adoc
b/docs/modules/ROOT/pages/migration-to-4x/serialization-4x.adoc
index 8afafbe55e..4981f706bc 100644
--- a/docs/modules/ROOT/pages/migration-to-4x/serialization-4x.adoc
+++ b/docs/modules/ROOT/pages/migration-to-4x/serialization-4x.adoc
@@ -75,10 +75,18 @@ indented). Use the `--list-*-names` variants when you want
a machine-readable ma
=== Custom Class Support
-The design permits users to add custom classes through Jackson's polymorphic
handling:
+Custom classes are supported through the `@TikaComponent` annotation rather
than
+Jackson polymorphic typing:
-* `org.apache.tika` patterns are allowed by default
-* Users can define additional inclusion patterns for security
+* Annotate the class with `@TikaComponent`; the annotation processor generates
a
+ `META-INF/tika/*.idx` registry entry at compile time
+* Any class whose `.idx` entry is on the classpath can be referenced by its
+ friendly name in JSON configuration
+* Class names or packages that are not registered cannot be instantiated from
+ JSON — there is no package-pattern allowlist and no `Class.forName` fallback
+
+See xref:developers/serialization.adoc[Serialization and Configuration] for the
+full mechanism.
=== Configuration Consistency
@@ -137,7 +145,13 @@ dependencies on components like `PDFParser`.
== Security Considerations
* Configuration files at initialization are treated as trusted sources
-* Runtime serialization/deserialization uses an allowlist of permitted packages
-* Custom components can register patterns in
`META-INF/tika-serialization-allowlist.txt`
+* Only classes registered via `@TikaComponent` (compile-time-generated
+ `META-INF/tika/*.idx` files) can be instantiated from JSON; unregistered
class
+ names are rejected and there is no Jackson default typing
+* Untrusted per-request configuration (tika-server requests, pipes
+ `FetchEmitTuple`s) is deserialized in restricted mode: a fail-closed
allowlist
+ permits only metadata/output-shaping context keys (e.g. `MetadataFilter`,
+ `ContentHandlerFactory`, `DigesterFactory`) and blocks `Parser`, `Detector`,
+ `Renderer`, and similar before anything is constructed
See link:design-notes-4x.html[Design Notes for 4.x] for additional
architectural context.
diff --git
a/tika-serialization/src/main/java/org/apache/tika/serialization/ComponentNameResolver.java
b/tika-serialization/src/main/java/org/apache/tika/serialization/ComponentNameResolver.java
index 977dd895a4..7b3db573c3 100644
---
a/tika-serialization/src/main/java/org/apache/tika/serialization/ComponentNameResolver.java
+++
b/tika-serialization/src/main/java/org/apache/tika/serialization/ComponentNameResolver.java
@@ -128,13 +128,14 @@ public final class ComponentNameResolver {
}
/**
- * Resolves a friendly name or FQCN to a Class.
- * Searches all registered component registries, falling back to
Class.forName.
+ * Resolves a friendly name (or registered FQCN) to a Class by searching
the
+ * registered component registries only. There is deliberately no
+ * Class.forName fallback: unregistered names are rejected for security.
*
- * @param name friendly name or fully qualified class name
- * @param classLoader the class loader to use for FQCN fallback
+ * @param name friendly name or registered fully qualified class name
+ * @param classLoader unused for resolution; retained for API stability
* @return the resolved class
- * @throws ClassNotFoundException if not found in any registry and not a
valid FQCN
+ * @throws ClassNotFoundException if the name is not in any registry
*/
public static Class<?> resolveClass(String name, ClassLoader classLoader)
throws ClassNotFoundException {