Skip to content

Commit 1781225

Browse files
authored
Update serialization docs (#2924)
1 parent aca20dc commit 1781225

4 files changed

Lines changed: 93 additions & 16 deletions

File tree

docs/modules/ROOT/pages/developers/serialization.adoc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,62 @@ for instantiation.
251251
}
252252
----
253253

254+
=== Untrusted (Wire) Input: Restricted Mode
255+
256+
Configuration files loaded at startup via `TikaLoader` are treated as trusted.
257+
Per-request configuration arriving over the wire — tika-server request bodies
258+
and pipes `FetchEmitTuple`s — is deserialized in *restricted mode*
259+
(`ParseContextDeserializer.readParseContext(node, true)`), which adds a second,
260+
fail-closed gate on top of the registry:
261+
262+
* Only context-key types confined to shaping this request's metadata or output
263+
may be instantiated from the wire: `MetadataFilter`, `ContentHandlerFactory`,
264+
`ContentHandlerDecoratorFactory`, `DigesterFactory`,
265+
`MetadataWriteLimiterFactory`, `UnpackSelector`
266+
* Types with exec/IO/network capability or control over which components run
267+
are blocked: `Parser`, `Detector`, `EncodingDetector`, `Renderer`,
268+
`Translator`, `EmbeddedDocumentExtractorFactory`
269+
* The check is fail-closed: a newly added context-key interface is blocked until
270+
it is consciously allow-listed
271+
* The whole tree is scanned *before* any component is constructed
272+
273+
The allowlist/blocklist lives in `ComponentNameResolver`
274+
(`WIRE_INSTANTIABLE_CONTEXT_KEYS` / `WIRE_BLOCKED_CONTEXT_KEYS`); an
275+
exhaustiveness test asserts every context-key interface is classified as
276+
exactly one of the two. Plain config DTOs (non-component keys) are never
277+
blocked.
278+
279+
== Framework Directives
280+
281+
Some JSON keys are consumed by the loading framework itself rather than by the
282+
component whose config object they appear in. When such a directive shares a
283+
JSON object with a component's own properties, it carries a leading underscore
284+
to avoid namespace collisions with legitimate component config keys:
285+
286+
[source,json]
287+
----
288+
{
289+
"parsers": [
290+
{
291+
"pdf-parser": {
292+
"_mime-include": ["application/pdf"],
293+
"_mime-exclude": ["application/pdf+fdf"],
294+
"extractInlineImages": true
295+
}
296+
}
297+
]
298+
}
299+
----
300+
301+
`_mime-include`/`_mime-exclude` are stripped before the component sees its
302+
config and are applied by the framework as a MIME-filtering decorator around
303+
the parser. New framework directives must follow the underscore convention.
304+
305+
Marker entries that have no component-config namespace of their own are the
306+
exception: `"exclude"` on `default-parser`/`default-detector`/
307+
`default-encoding-detector` needs no prefix because those markers carry only
308+
framework keys.
309+
254310
== Creating a Custom Component
255311

256312
Complete example of a custom metadata filter:

docs/modules/ROOT/pages/migration-to-4x/design-notes-4x.adoc

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,22 @@ IMPORTANT: We tried to have as few Tika dependencies in the plugins as possible.
6161

6262
=== Security Model
6363

64-
Configuration files at initialization are treated as trusted sources. Runtime
65-
serialization/deserialization uses an allowlist of permitted packages via
66-
`PolymorphicObjectMapperFactory`.
67-
68-
Custom components can add patterns to `META-INF/tika-serialization-allowlist.txt`.
64+
Configuration files at initialization are treated as trusted sources. Component
65+
instantiation from JSON is restricted to classes registered at compile time by
66+
the `@TikaComponent` annotation processor (`META-INF/tika/*.idx` files); unknown
67+
class names are rejected, and there is no Jackson default typing.
68+
69+
Untrusted per-request configuration (tika-server requests, pipes
70+
`FetchEmitTuple`s) is deserialized in a restricted mode that additionally applies
71+
a fail-closed allowlist of context-key types: only metadata/output-shaping
72+
components (e.g. `MetadataFilter`, `ContentHandlerFactory`, `DigesterFactory`)
73+
may be bound from the wire; `Parser`, `Detector`, `Renderer`, and similar are
74+
blocked before anything is constructed. See
75+
xref:developers/serialization.adoc[Serialization and Configuration].
6976

7077
=== Implementation Challenges
7178

7279
* Converted code to true Java beans with matching getters/setters
73-
* Used `ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE` for polymorphic typing
7480
* Replaced generic collections (`List`, `Set`) with concrete types (`ArrayList`, `HashSet`)
7581
* Converted `Path` fields to `String` due to Jackson constraints
7682
* Avoided Java records to enable `readerForUpdating` functionality

docs/modules/ROOT/pages/migration-to-4x/serialization-4x.adoc

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,18 @@ indented). Use the `--list-*-names` variants when you want a machine-readable ma
7575

7676
=== Custom Class Support
7777

78-
The design permits users to add custom classes through Jackson's polymorphic handling:
78+
Custom classes are supported through the `@TikaComponent` annotation rather than
79+
Jackson polymorphic typing:
7980

80-
* `org.apache.tika` patterns are allowed by default
81-
* Users can define additional inclusion patterns for security
81+
* Annotate the class with `@TikaComponent`; the annotation processor generates a
82+
`META-INF/tika/*.idx` registry entry at compile time
83+
* Any class whose `.idx` entry is on the classpath can be referenced by its
84+
friendly name in JSON configuration
85+
* Class names or packages that are not registered cannot be instantiated from
86+
JSON — there is no package-pattern allowlist and no `Class.forName` fallback
87+
88+
See xref:developers/serialization.adoc[Serialization and Configuration] for the
89+
full mechanism.
8290

8391
=== Configuration Consistency
8492

@@ -137,7 +145,13 @@ dependencies on components like `PDFParser`.
137145
== Security Considerations
138146

139147
* Configuration files at initialization are treated as trusted sources
140-
* Runtime serialization/deserialization uses an allowlist of permitted packages
141-
* Custom components can register patterns in `META-INF/tika-serialization-allowlist.txt`
148+
* Only classes registered via `@TikaComponent` (compile-time-generated
149+
`META-INF/tika/*.idx` files) can be instantiated from JSON; unregistered class
150+
names are rejected and there is no Jackson default typing
151+
* Untrusted per-request configuration (tika-server requests, pipes
152+
`FetchEmitTuple`s) is deserialized in restricted mode: a fail-closed allowlist
153+
permits only metadata/output-shaping context keys (e.g. `MetadataFilter`,
154+
`ContentHandlerFactory`, `DigesterFactory`) and blocks `Parser`, `Detector`,
155+
`Renderer`, and similar before anything is constructed
142156

143157
See link:design-notes-4x.html[Design Notes for 4.x] for additional architectural context.

tika-serialization/src/main/java/org/apache/tika/serialization/ComponentNameResolver.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,14 @@ public static void registerRegistry(String indexName, ComponentRegistry registry
128128
}
129129

130130
/**
131-
* Resolves a friendly name or FQCN to a Class.
132-
* Searches all registered component registries, falling back to Class.forName.
131+
* Resolves a friendly name (or registered FQCN) to a Class by searching the
132+
* registered component registries only. There is deliberately no
133+
* Class.forName fallback: unregistered names are rejected for security.
133134
*
134-
* @param name friendly name or fully qualified class name
135-
* @param classLoader the class loader to use for FQCN fallback
135+
* @param name friendly name or registered fully qualified class name
136+
* @param classLoader unused for resolution; retained for API stability
136137
* @return the resolved class
137-
* @throws ClassNotFoundException if not found in any registry and not a valid FQCN
138+
* @throws ClassNotFoundException if the name is not in any registry
138139
*/
139140
public static Class<?> resolveClass(String name, ClassLoader classLoader)
140141
throws ClassNotFoundException {

0 commit comments

Comments
 (0)