atiaomar1978-hub commented on code in PR #26026:
URL: https://github.com/apache/camel/pull/26026#discussion_r3911187879
##########
components/camel-avro/src/main/java/org/apache/camel/dataformat/avro/AvroDataFormat.java:
##########
@@ -135,6 +158,9 @@ protected Schema loadSchema(String className) throws
CamelException, ClassNotFou
@Override
public void marshal(Exchange exchange, Object graph, OutputStream
outputStream) throws Exception {
+ if (actualSchema == null) {
Review Comment:
**Fixed in e7f7c32:** Trust graph class only when `actualSchema == null`
(dynamic schema inference). Preconfigured schema/instance paths trust at init
only.
_AI-generated on behalf of @atiaomar1978-hub_
##########
components/camel-avro/src/main/java/org/apache/camel/avro/support/AvroClassSecuritySupport.java:
##########
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.avro.support;
+
+import java.util.Arrays;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.avro.util.ClassSecurityValidator;
+import org.apache.avro.util.ClassSecurityValidator.ClassSecurityPredicate;
+
+/**
+ * Configures Apache Avro {@link ClassSecurityValidator} with Camel trusted
packages.
+ * <p>
+ * Avro 1.12+ validates classes resolved from schemas. Camel automatically
trusts packages derived from configured
+ * protocol or schema classes. Additional packages can be configured through
the {@code serializablePackages} endpoint
+ * option.
+ * <p>
+ * Trusted packages are stored in a JVM-wide registry shared by all Camel
contexts in the process. Trust is cumulative
+ * and cannot be revoked in production.
+ */
+public final class AvroClassSecuritySupport {
+
+ private static final Set<String> TRUSTED_PACKAGES =
ConcurrentHashMap.newKeySet();
+
+ private static final Set<String> TRUSTED_CLASSES =
ConcurrentHashMap.newKeySet();
+
+ private static final Object LOCK = new Object();
+
+ private static final ClassSecurityPredicate CAMEL_TRUSTED =
AvroClassSecuritySupport::isCamelTrusted;
+
+ private static volatile ClassSecurityPredicate baseValidator =
ClassSecurityValidator.DEFAULT;
+
+ private static volatile ClassSecurityPredicate installedGlobal;
+
+ private static volatile NavigableSet<String> normalizedPackagePrefixes =
new TreeSet<>();
+
+ private AvroClassSecuritySupport() {
+ }
+
+ /**
+ * Trusts Avro IPC classes required for camel-avro-rpc handshake.
+ */
+ public static void ensureAvroIpcPackagesTrusted() {
+ trustPackages("org.apache.avro.ipc");
+ }
+
+ /**
+ * Trusts the exact class name and its package for schema resolution.
+ */
+ public static void trustClassName(String className) {
+ if (className == null || className.isBlank()) {
+ return;
+ }
+ synchronized (LOCK) {
+ TRUSTED_CLASSES.add(className);
+ int lastDot = className.lastIndexOf('.');
+ if (lastDot > 0) {
+ TRUSTED_PACKAGES.add(normalizePackage(className.substring(0,
lastDot)));
+ }
+ rebuildNormalizedPackagePrefixes();
+ refreshGlobal();
+ }
+ }
+
+ /**
+ * Trusts the comma-separated list of packages.
+ */
+ public static void trustPackages(String packages) {
+ if (packages == null || packages.isBlank()) {
+ return;
+ }
+ trustPackages(parsePackages(packages).toArray(String[]::new));
+ }
+
+ /**
+ * Trusts the given packages.
+ */
+ public static void trustPackages(String... packages) {
+ if (packages == null || packages.length == 0) {
+ return;
+ }
+ synchronized (LOCK) {
+ for (String pkg : packages) {
+ if (pkg != null && !pkg.isBlank()) {
+ TRUSTED_PACKAGES.add(normalizePackage(pkg));
+ }
+ }
+ rebuildNormalizedPackagePrefixes();
+ refreshGlobal();
+ }
+ }
+
+ /**
+ * Clears Camel-managed trusted classes and packages. Intended for tests.
+ */
+ public static void resetForTesting() {
+ synchronized (LOCK) {
+ TRUSTED_PACKAGES.clear();
+ TRUSTED_CLASSES.clear();
+ normalizedPackagePrefixes = new TreeSet<>();
+ baseValidator = ClassSecurityValidator.DEFAULT;
+ installedGlobal = null;
+ ClassSecurityValidator.setGlobal(ClassSecurityValidator.DEFAULT);
+ }
+ }
+
+ private static void refreshGlobal() {
+ if (installedGlobal == null) {
Review Comment:
**Fixed in e7f7c32:** First trust call captures existing
`ClassSecurityValidator.getGlobal()` as base and composes Camel predicate on
top.
_AI-generated on behalf of @atiaomar1978-hub_
##########
components/camel-avro/src/main/java/org/apache/camel/avro/support/AvroClassSecuritySupport.java:
##########
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.avro.support;
+
+import java.util.Arrays;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.avro.util.ClassSecurityValidator;
+import org.apache.avro.util.ClassSecurityValidator.ClassSecurityPredicate;
+
+/**
+ * Configures Apache Avro {@link ClassSecurityValidator} with Camel trusted
packages.
+ * <p>
+ * Avro 1.12+ validates classes resolved from schemas. Camel automatically
trusts packages derived from configured
+ * protocol or schema classes. Additional packages can be configured through
the {@code serializablePackages} endpoint
+ * option.
+ * <p>
+ * Trusted packages are stored in a JVM-wide registry shared by all Camel
contexts in the process. Trust is cumulative
+ * and cannot be revoked in production.
+ */
+public final class AvroClassSecuritySupport {
+
+ private static final Set<String> TRUSTED_PACKAGES =
ConcurrentHashMap.newKeySet();
+
+ private static final Set<String> TRUSTED_CLASSES =
ConcurrentHashMap.newKeySet();
+
+ private static final Object LOCK = new Object();
+
+ private static final ClassSecurityPredicate CAMEL_TRUSTED =
AvroClassSecuritySupport::isCamelTrusted;
+
+ private static volatile ClassSecurityPredicate baseValidator =
ClassSecurityValidator.DEFAULT;
+
+ private static volatile ClassSecurityPredicate installedGlobal;
+
+ private static volatile NavigableSet<String> normalizedPackagePrefixes =
new TreeSet<>();
+
+ private AvroClassSecuritySupport() {
+ }
+
+ /**
+ * Trusts Avro IPC classes required for camel-avro-rpc handshake.
+ */
+ public static void ensureAvroIpcPackagesTrusted() {
+ trustPackages("org.apache.avro.ipc");
+ }
+
+ /**
+ * Trusts the exact class name and its package for schema resolution.
+ */
+ public static void trustClassName(String className) {
+ if (className == null || className.isBlank()) {
+ return;
+ }
+ synchronized (LOCK) {
+ TRUSTED_CLASSES.add(className);
+ int lastDot = className.lastIndexOf('.');
+ if (lastDot > 0) {
+ TRUSTED_PACKAGES.add(normalizePackage(className.substring(0,
lastDot)));
+ }
+ rebuildNormalizedPackagePrefixes();
+ refreshGlobal();
+ }
+ }
+
+ /**
+ * Trusts the comma-separated list of packages.
+ */
+ public static void trustPackages(String packages) {
+ if (packages == null || packages.isBlank()) {
+ return;
+ }
+ trustPackages(parsePackages(packages).toArray(String[]::new));
+ }
+
+ /**
+ * Trusts the given packages.
+ */
+ public static void trustPackages(String... packages) {
+ if (packages == null || packages.length == 0) {
+ return;
+ }
+ synchronized (LOCK) {
+ for (String pkg : packages) {
+ if (pkg != null && !pkg.isBlank()) {
+ TRUSTED_PACKAGES.add(normalizePackage(pkg));
+ }
+ }
+ rebuildNormalizedPackagePrefixes();
+ refreshGlobal();
+ }
+ }
+
+ /**
+ * Clears Camel-managed trusted classes and packages. Intended for tests.
+ */
+ public static void resetForTesting() {
+ synchronized (LOCK) {
+ TRUSTED_PACKAGES.clear();
+ TRUSTED_CLASSES.clear();
+ normalizedPackagePrefixes = new TreeSet<>();
+ baseValidator = ClassSecurityValidator.DEFAULT;
+ installedGlobal = null;
+ ClassSecurityValidator.setGlobal(ClassSecurityValidator.DEFAULT);
+ }
+ }
+
+ private static void refreshGlobal() {
+ if (installedGlobal == null) {
+ ClassSecurityPredicate current =
ClassSecurityValidator.getGlobal();
+ if (current != null && current != ClassSecurityValidator.DEFAULT) {
+ baseValidator = current;
+ }
+ }
+ installedGlobal = ClassSecurityValidator.composite(baseValidator,
CAMEL_TRUSTED);
+ ClassSecurityValidator.setGlobal(installedGlobal);
+ }
+
+ private static boolean isCamelTrusted(Class<?> clazz) {
+ String className = clazz.getName();
+ if (TRUSTED_CLASSES.contains(className)) {
+ return true;
+ }
+ NavigableSet<String> packages = normalizedPackagePrefixes;
+ String lower = packages.lower(className);
+ return lower != null && className.startsWith(lower);
+ }
+
+ private static void rebuildNormalizedPackagePrefixes() {
+ NavigableSet<String> normalized = new TreeSet<>();
Review Comment:
**Fixed in e7f7c32:** Normalized package prefixes cached in
`normalizedPackagePrefixes`, rebuilt only when allowlist mutates.
_AI-generated on behalf of @atiaomar1978-hub_
##########
core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/AvroDataFormat.java:
##########
@@ -120,6 +120,10 @@ public class AvroDataFormat extends DataFormatDefinition
implements ContentTypeH
@Metadata(label = "advanced", javaType = "java.lang.Boolean", defaultValue
= "true",
description = "When not disabled, the SchemaResolver will be
looked up into the registry.")
private String autoDiscoverSchemaResolver;
+ @XmlAttribute
Review Comment:
**Fixed in e7f7c32:** Added `serializablePackages` to core model with full
regen (catalog, YAML, XML schema, reifier). Usable from XML/YAML/fluent DSL.
_AI-generated on behalf of @atiaomar1978-hub_
##########
catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/avro.json:
##########
@@ -33,7 +33,8 @@
"bridgeErrorHandler": { "index": 6, "kind": "property", "displayName":
"Bridge Error Handler", "group": "consumer", "label": "consumer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Allows for bridging the consumer to the Camel routing Error Handler, which
mean any exceptions (if possible) occurred while the Camel consumer is trying
to pickup incoming messages, or the likes, will now be processed as a message
and handled by the routing Error Handler. Important: This is only possible if
the 3rd party component allows Camel to be alerted if an exception was thrown.
Some components handle this internally only, and therefore bridgeErrorHandler
is not possible. In other situations we may improve the Camel component to hook
into the 3rd party component and make this possible for future releases. By
default the consumer will use the org.apache.camel.spi.ExceptionHandler to d
eal with exceptions, that will be logged at WARN or ERROR level and ignored."
},
"lazyStartProducer": { "index": 7, "kind": "property", "displayName":
"Lazy Start Producer", "group": "producer", "label": "producer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether the producer should be started lazy (on the first message). By
starting lazy you can use this to allow CamelContext and routes to startup in
situations where a producer may otherwise fail during starting and cause the
route to fail being started. By deferring this startup to be lazy then the
startup failure can be handled during routing messages via Camel's routing
error handlers. Beware that when the first message is processed then creating
and starting the producer may take a little time and prolong the total
processing time of the processing." },
"autowiredEnabled": { "index": 8, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching type, which then gets configured on
the component. This can be used for automatic configuring JDBC data sources,
JMS connection factories, AWS Clients, etc." },
- "configuration": { "index": 9, "kind": "property", "displayName":
"Configuration", "group": "advanced", "label": "advanced", "required": false,
"type": "object", "javaType":
"org.apache.camel.component.avro.AvroConfiguration", "deprecated": false,
"autowired": false, "secret": false, "description": "To use a shared
AvroConfiguration to configure options once" }
+ "configuration": { "index": 9, "kind": "property", "displayName":
"Configuration", "group": "advanced", "label": "advanced", "required": false,
"type": "object", "javaType":
"org.apache.camel.component.avro.AvroConfiguration", "deprecated": false,
"autowired": false, "secret": false, "description": "To use a shared
AvroConfiguration to configure options once" },
+ "serializablePackages": { "index": 10, "kind": "property", "displayName":
"Serializable Packages", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:serialization",
"configurationClass": "org.apache.camel.component.avro.AvroConfiguration",
"configurationField": "configuration", "description": "Comma-separated list of
additional packages that contain trusted Avro model classes. Avro 1.12
validates classes resolved from schemas; Camel automatically trusts
org.apache.avro for IPC and packages derived from the configured protocol. Use
this option for any additional model packages not inferred from the protocol." }
Review Comment:
**Fixed in e7f7c32:** Regenerated catalog + endpoint/component DSL —
`serializablePackages` now present for RPC component.
_AI-generated on behalf of @atiaomar1978-hub_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]