This is an automated email from the ASF dual-hosted git repository.
oscerd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 6daeefed7220 CAMEL-24292: camel-sql, camel-sql-stored - gate the
query/template override headers behind an opt-in (#26268)
6daeefed7220 is described below
commit 6daeefed722014fd3e429479c4e480228fe54b8a
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Sep 15 11:18:47 2026 +0200
CAMEL-24292: camel-sql, camel-sql-stored - gate the query/template override
headers behind an opt-in (#26268)
camel-sql (CamelSqlQuery) and camel-sql-stored (CamelSqlStoredTemplate) no
longer let an inbound header
override the endpoint-configured query/template by default. New
allowQueryFromHeader / allowTemplateFromHeader
options (on both the endpoint and the component, default false, marked
security="insecure:dev") restore the
old behaviour when explicitly opted in. A header- or message-body-supplied
stored-procedure template is now
resolved with property placeholders only, never dereferenced as a
file:/http:/classpath: resource
(SSRF / local file read). Documented in the 4.23 upgrade guide.
Co-authored-by: Claude Opus 4.8 <[email protected]>
---
.../camel/catalog/components/sql-stored.json | 8 +-
.../org/apache/camel/catalog/components/sql.json | 8 +-
.../component/sql/SqlComponentConfigurer.java | 6 ++
.../camel/component/sql/SqlEndpointConfigurer.java | 6 ++
.../camel/component/sql/SqlEndpointUriFactory.java | 3 +-
.../sql/stored/SqlStoredComponentConfigurer.java | 6 ++
.../sql/stored/SqlStoredEndpointConfigurer.java | 6 ++
.../sql/stored/SqlStoredEndpointUriFactory.java | 3 +-
.../org/apache/camel/component/sql/sql.json | 8 +-
.../camel/component/sql/stored/sql-stored.json | 8 +-
.../camel/component/sql/DefaultSqlEndpoint.java | 17 ++++
.../apache/camel/component/sql/SqlComponent.java | 19 ++++
.../apache/camel/component/sql/SqlConstants.java | 8 +-
.../apache/camel/component/sql/SqlProducer.java | 3 +-
.../component/sql/stored/SqlStoredComponent.java | 20 ++++
.../component/sql/stored/SqlStoredConstants.java | 6 +-
.../component/sql/stored/SqlStoredEndpoint.java | 17 ++++
.../component/sql/stored/SqlStoredProducer.java | 20 +++-
.../apache/camel/component/sql/SqlRouteTest.java | 21 +++-
.../component/sql/SqlTransactedRouteTest.java | 2 +-
.../SqlStoredAllowTemplateFromHeaderTest.java | 107 +++++++++++++++++++++
...toredUseMessageBodyForTemplateResourceTest.java | 103 ++++++++++++++++++++
.../test/resources/sql/bodyTemplateResource.sql | 21 ++++
.../java/org/apache/camel/util/SecurityUtils.java | 2 +
.../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 24 +++++
.../component/dsl/SqlComponentBuilderFactory.java | 22 +++++
.../dsl/SqlStoredComponentBuilderFactory.java | 22 +++++
.../endpoint/dsl/SqlEndpointBuilderFactory.java | 44 ++++++++-
.../dsl/SqlStoredEndpointBuilderFactory.java | 40 +++++++-
29 files changed, 552 insertions(+), 28 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql-stored.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql-stored.json
index 36831533494b..cf3f69b6ce36 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql-stored.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql-stored.json
@@ -27,10 +27,11 @@
"dataSource": { "index": 0, "kind": "property", "displayName": "Data
Source", "group": "producer", "label": "", "required": false, "type": "object",
"javaType": "javax.sql.DataSource", "deprecated": false, "autowired": true,
"secret": false, "description": "Sets the DataSource to use to communicate with
the database." },
"lazyStartProducer": { "index": 1, "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 [...]
"autowiredEnabled": { "index": 2, "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 t [...]
- "serviceLocationEnabled": { "index": 3, "kind": "property", "displayName":
"Service Location Enabled", "group": "advanced", "label": "advanced",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether to detect the network address location of the database
on startup. This information is gathered via reflection on the DataSource, and
is vendor specific. This option can be used [...]
+ "serviceLocationEnabled": { "index": 3, "kind": "property", "displayName":
"Service Location Enabled", "group": "advanced", "label": "advanced",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether to detect the network address location of the database
on startup. This information is gathered via reflection on the DataSource, and
is vendor specific. This option can be used [...]
+ "allowTemplateFromHeader": { "index": 4, "kind": "property",
"displayName": "Allow Template From Header", "group": "security", "label":
"producer,security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"security": "insecure:dev", "insecureValue": "true", "defaultValue": false,
"description": "Whether to allow overriding the endpoint-configured
stored-procedure template with the CamelSqlStoredTemplate header. Di [...]
},
"headers": {
- "CamelSqlStoredTemplate": { "index": 0, "kind": "header", "displayName":
"", "group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The template", "constantName":
"org.apache.camel.component.sql.stored.SqlStoredConstants#SQL_STORED_TEMPLATE"
},
+ "CamelSqlStoredTemplate": { "index": 0, "kind": "header", "displayName":
"", "group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The stored-procedure template to execute. This
header is ignored unless the endpoint enables allowTemplateFromHeader=true
(disabled by default); when enabled it overrides the endpoint-configured
template.", "constantName": "org.apa [...]
"CamelSqlStoredParameters": { "index": 1, "kind": "header", "displayName":
"", "group": "producer", "label": "producer", "required": false, "javaType":
"Iterator", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The parameters", "constantName":
"org.apache.camel.component.sql.stored.SqlStoredConstants#SQL_STORED_PARAMETERS"
},
"CamelSqlStoredUpdateCount": { "index": 2, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "important": true, "description": "The update count",
"constantName":
"org.apache.camel.component.sql.stored.SqlStoredConstants#SQL_STORED_UPDATE_COUNT"
}
},
@@ -43,6 +44,7 @@
"outputHeader": { "index": 5, "kind": "parameter", "displayName": "Output
Header", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "Store the template result in a header instead
of the message body. By default, outputHeader == null and the template result
is stored in the message body, any existing content in the message body is
discarded. If outputHeader is [...]
"useMessageBodyForTemplate": { "index": 6, "kind": "parameter",
"displayName": "Use Message Body For Template", "group": "producer", "label":
"", "required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": false,
"description": "Whether to use the message body as the stored procedure
template and then headers for parameters. If this option is enabled then the
template in the uri is not used." },
"lazyStartProducer": { "index": 7, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "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 produc [...]
- "templateOptions": { "index": 8, "kind": "parameter", "displayName":
"Template Options", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType": "java.util.Map<java.lang.String,
java.lang.Object>", "prefix": "template.", "multiValue": true, "deprecated":
false, "autowired": false, "secret": false, "description": "Configures the
Spring JdbcTemplate with the key\/values from the Map. This is a multi-value
option with prefix: template." }
+ "templateOptions": { "index": 8, "kind": "parameter", "displayName":
"Template Options", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType": "java.util.Map<java.lang.String,
java.lang.Object>", "prefix": "template.", "multiValue": true, "deprecated":
false, "autowired": false, "secret": false, "description": "Configures the
Spring JdbcTemplate with the key\/values from the Map. This is a multi-value
option with prefix: template." },
+ "allowTemplateFromHeader": { "index": 9, "kind": "parameter",
"displayName": "Allow Template From Header", "group": "security", "label":
"security", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "security":
"insecure:dev", "insecureValue": "true", "defaultValue": false, "description":
"Whether to allow overriding the endpoint-configured stored-procedure template
with the CamelSqlStoredTemplate header. Disabled b [...]
}
}
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql.json
index 188c7d45c4ae..fca8d9d34bd1 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql.json
@@ -34,10 +34,11 @@
"serviceLocationEnabled": { "index": 7, "kind": "property", "displayName":
"Service Location Enabled", "group": "advanced", "label": "advanced",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether to detect the network address location of the Database
on startup. This information is gathered via reflection on the DataSource, and
is vendor specific. This option can be used [...]
"usePlaceholder": { "index": 8, "kind": "property", "displayName": "Use
Placeholder", "group": "advanced", "label": "advanced", "required": false,
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": true, "description": "Sets whether to
use placeholder and replace all placeholder characters with sign in the SQL
queries. This option is default true" },
"healthCheckConsumerEnabled": { "index": 9, "kind": "property",
"displayName": "Health Check Consumer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all consumer based health checks
from this component" },
- "healthCheckProducerEnabled": { "index": 10, "kind": "property",
"displayName": "Health Check Producer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all producer based health checks
from this component. Notice: Camel has by default disabled all producer based
health-checks. You can turn on produce [...]
+ "healthCheckProducerEnabled": { "index": 10, "kind": "property",
"displayName": "Health Check Producer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all producer based health checks
from this component. Notice: Camel has by default disabled all producer based
health-checks. You can turn on produce [...]
+ "allowQueryFromHeader": { "index": 11, "kind": "property", "displayName":
"Allow Query From Header", "group": "security", "label": "producer,security",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "security": "insecure:dev",
"insecureValue": "true", "defaultValue": false, "description": "Whether to
allow overriding the endpoint-configured SQL query with the CamelSqlQuery
header. Disabled by default; enable it o [...]
},
"headers": {
- "CamelSqlQuery": { "index": 0, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "Query to execute. This query takes precedence
over the query specified in the endpoint URI. Note that query parameters in the
header are represented by a instead of a pass:# symbol", "constantName":
"org.apache.camel.component.sql.SqlConsta [...]
+ "CamelSqlQuery": { "index": 0, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "Query to execute. This header is ignored
unless the endpoint enables allowQueryFromHeader=true (disabled by default);
when enabled it takes precedence over the query specified in the endpoint URI.
Note that query parameters in the header ar [...]
"CamelSqlUpdateCount": { "index": 1, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"Integer", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "important": true, "description": "The number of rows updated
for update operations, returned as an Integer object. This header is not
provided when using outputType=StreamList.", "constantName":
"org.apache.camel.component.sql.SqlConstants#SQL_UPDA [...]
"CamelSqlRowCount": { "index": 2, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"Integer", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "important": true, "description": "The number of rows returned
for select operations, returned as an Integer object. This header is not
provided when using outputType=StreamList.", "constantName":
"org.apache.camel.component.sql.SqlConstants#SQL_ROW_COUNT" },
"CamelSqlRetrieveGeneratedKeys": { "index": 3, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "defaultValue": "false", "description": "Set its value
to true to retrieve generated keys", "constantName":
"org.apache.camel.component.sql.SqlConstants#SQL_RETRIEVE_GENERATED_KEYS" },
@@ -96,6 +97,7 @@
"schedulerProperties": { "index": 45, "kind": "parameter", "displayName":
"Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "object", "javaType":
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": "scheduler.",
"multiValue": true, "deprecated": false, "autowired": false, "secret": false,
"description": "To configure additional properties when using a custom
scheduler or any of the Quartz, Spring based scheduler. This i [...]
"startScheduler": { "index": 46, "kind": "parameter", "displayName":
"Start Scheduler", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether the scheduler should be auto started." },
"timeUnit": { "index": 47, "kind": "parameter", "displayName": "Time
Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [
"NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS",
"DAYS" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and
delay options." },
- "useFixedDelay": { "index": 48, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." }
+ "useFixedDelay": { "index": 48, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." },
+ "allowQueryFromHeader": { "index": 49, "kind": "parameter", "displayName":
"Allow Query From Header", "group": "security", "label": "producer,security",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "security": "insecure:dev",
"insecureValue": "true", "defaultValue": false, "description": "Whether to
allow overriding the endpoint-configured SQL query with the CamelSqlQuery
header. Disabled by default; enable it [...]
}
}
diff --git
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlComponentConfigurer.java
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlComponentConfigurer.java
index f04aba0caa6f..7e8624c89f81 100644
---
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlComponentConfigurer.java
+++
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlComponentConfigurer.java
@@ -23,6 +23,8 @@ public class SqlComponentConfigurer extends
PropertyConfigurerSupport implements
public boolean configure(CamelContext camelContext, Object obj, String
name, Object value, boolean ignoreCase) {
SqlComponent target = (SqlComponent) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowqueryfromheader":
+ case "allowQueryFromHeader":
target.setAllowQueryFromHeader(property(camelContext, boolean.class, value));
return true;
case "autowiredenabled":
case "autowiredEnabled":
target.setAutowiredEnabled(property(camelContext, boolean.class, value));
return true;
case "batchautocommitdisabled":
@@ -57,6 +59,8 @@ public class SqlComponentConfigurer extends
PropertyConfigurerSupport implements
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowqueryfromheader":
+ case "allowQueryFromHeader": return boolean.class;
case "autowiredenabled":
case "autowiredEnabled": return boolean.class;
case "batchautocommitdisabled":
@@ -87,6 +91,8 @@ public class SqlComponentConfigurer extends
PropertyConfigurerSupport implements
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
SqlComponent target = (SqlComponent) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowqueryfromheader":
+ case "allowQueryFromHeader": return target.isAllowQueryFromHeader();
case "autowiredenabled":
case "autowiredEnabled": return target.isAutowiredEnabled();
case "batchautocommitdisabled":
diff --git
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlEndpointConfigurer.java
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlEndpointConfigurer.java
index 6805419d4f95..f70796e4c3a1 100644
---
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlEndpointConfigurer.java
+++
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlEndpointConfigurer.java
@@ -25,6 +25,8 @@ public class SqlEndpointConfigurer extends
PropertyConfigurerSupport implements
switch (ignoreCase ? name.toLowerCase() : name) {
case "allownamedparameters":
case "allowNamedParameters":
target.setAllowNamedParameters(property(camelContext, boolean.class, value));
return true;
+ case "allowqueryfromheader":
+ case "allowQueryFromHeader":
target.setAllowQueryFromHeader(property(camelContext, boolean.class, value));
return true;
case "alwayspopulatestatement":
case "alwaysPopulateStatement":
target.setAlwaysPopulateStatement(property(camelContext, boolean.class,
value)); return true;
case "backofferrorthreshold":
@@ -125,6 +127,8 @@ public class SqlEndpointConfigurer extends
PropertyConfigurerSupport implements
switch (ignoreCase ? name.toLowerCase() : name) {
case "allownamedparameters":
case "allowNamedParameters": return boolean.class;
+ case "allowqueryfromheader":
+ case "allowQueryFromHeader": return boolean.class;
case "alwayspopulatestatement":
case "alwaysPopulateStatement": return boolean.class;
case "backofferrorthreshold":
@@ -221,6 +225,8 @@ public class SqlEndpointConfigurer extends
PropertyConfigurerSupport implements
switch (ignoreCase ? name.toLowerCase() : name) {
case "allownamedparameters":
case "allowNamedParameters": return target.isAllowNamedParameters();
+ case "allowqueryfromheader":
+ case "allowQueryFromHeader": return target.isAllowQueryFromHeader();
case "alwayspopulatestatement":
case "alwaysPopulateStatement": return
target.isAlwaysPopulateStatement();
case "backofferrorthreshold":
diff --git
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlEndpointUriFactory.java
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlEndpointUriFactory.java
index 214292296ec1..f1aa85d600df 100644
---
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlEndpointUriFactory.java
+++
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/SqlEndpointUriFactory.java
@@ -24,8 +24,9 @@ public class SqlEndpointUriFactory extends
org.apache.camel.support.component.En
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(49);
+ Set<String> props = new HashSet<>(50);
props.add("allowNamedParameters");
+ props.add("allowQueryFromHeader");
props.add("alwaysPopulateStatement");
props.add("backoffErrorThreshold");
props.add("backoffIdleThreshold");
diff --git
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredComponentConfigurer.java
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredComponentConfigurer.java
index 5e853b26b96c..c3044e2fe765 100644
---
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredComponentConfigurer.java
+++
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredComponentConfigurer.java
@@ -23,6 +23,8 @@ public class SqlStoredComponentConfigurer extends
PropertyConfigurerSupport impl
public boolean configure(CamelContext camelContext, Object obj, String
name, Object value, boolean ignoreCase) {
SqlStoredComponent target = (SqlStoredComponent) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowtemplatefromheader":
+ case "allowTemplateFromHeader":
target.setAllowTemplateFromHeader(property(camelContext, boolean.class,
value)); return true;
case "autowiredenabled":
case "autowiredEnabled":
target.setAutowiredEnabled(property(camelContext, boolean.class, value));
return true;
case "datasource":
@@ -43,6 +45,8 @@ public class SqlStoredComponentConfigurer extends
PropertyConfigurerSupport impl
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowtemplatefromheader":
+ case "allowTemplateFromHeader": return boolean.class;
case "autowiredenabled":
case "autowiredEnabled": return boolean.class;
case "datasource":
@@ -59,6 +63,8 @@ public class SqlStoredComponentConfigurer extends
PropertyConfigurerSupport impl
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
SqlStoredComponent target = (SqlStoredComponent) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowtemplatefromheader":
+ case "allowTemplateFromHeader": return
target.isAllowTemplateFromHeader();
case "autowiredenabled":
case "autowiredEnabled": return target.isAutowiredEnabled();
case "datasource":
diff --git
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredEndpointConfigurer.java
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredEndpointConfigurer.java
index b1406c759b23..c456df47959c 100644
---
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredEndpointConfigurer.java
+++
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredEndpointConfigurer.java
@@ -23,6 +23,8 @@ public class SqlStoredEndpointConfigurer extends
PropertyConfigurerSupport imple
public boolean configure(CamelContext camelContext, Object obj, String
name, Object value, boolean ignoreCase) {
SqlStoredEndpoint target = (SqlStoredEndpoint) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowtemplatefromheader":
+ case "allowTemplateFromHeader":
target.setAllowTemplateFromHeader(property(camelContext, boolean.class,
value)); return true;
case "batch": target.setBatch(property(camelContext, boolean.class,
value)); return true;
case "datasource":
case "dataSource": target.setDataSource(property(camelContext,
javax.sql.DataSource.class, value)); return true;
@@ -43,6 +45,8 @@ public class SqlStoredEndpointConfigurer extends
PropertyConfigurerSupport imple
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowtemplatefromheader":
+ case "allowTemplateFromHeader": return boolean.class;
case "batch": return boolean.class;
case "datasource":
case "dataSource": return javax.sql.DataSource.class;
@@ -64,6 +68,8 @@ public class SqlStoredEndpointConfigurer extends
PropertyConfigurerSupport imple
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
SqlStoredEndpoint target = (SqlStoredEndpoint) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowtemplatefromheader":
+ case "allowTemplateFromHeader": return
target.isAllowTemplateFromHeader();
case "batch": return target.isBatch();
case "datasource":
case "dataSource": return target.getDataSource();
diff --git
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredEndpointUriFactory.java
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredEndpointUriFactory.java
index 31e823eb55f2..d67a23984bdf 100644
---
a/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredEndpointUriFactory.java
+++
b/components/camel-sql/src/generated/java/org/apache/camel/component/sql/stored/SqlStoredEndpointUriFactory.java
@@ -24,7 +24,8 @@ public class SqlStoredEndpointUriFactory extends
org.apache.camel.support.compon
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(9);
+ Set<String> props = new HashSet<>(10);
+ props.add("allowTemplateFromHeader");
props.add("batch");
props.add("dataSource");
props.add("function");
diff --git
a/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/sql.json
b/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/sql.json
index 188c7d45c4ae..fca8d9d34bd1 100644
---
a/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/sql.json
+++
b/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/sql.json
@@ -34,10 +34,11 @@
"serviceLocationEnabled": { "index": 7, "kind": "property", "displayName":
"Service Location Enabled", "group": "advanced", "label": "advanced",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether to detect the network address location of the Database
on startup. This information is gathered via reflection on the DataSource, and
is vendor specific. This option can be used [...]
"usePlaceholder": { "index": 8, "kind": "property", "displayName": "Use
Placeholder", "group": "advanced", "label": "advanced", "required": false,
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": true, "description": "Sets whether to
use placeholder and replace all placeholder characters with sign in the SQL
queries. This option is default true" },
"healthCheckConsumerEnabled": { "index": 9, "kind": "property",
"displayName": "Health Check Consumer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all consumer based health checks
from this component" },
- "healthCheckProducerEnabled": { "index": 10, "kind": "property",
"displayName": "Health Check Producer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all producer based health checks
from this component. Notice: Camel has by default disabled all producer based
health-checks. You can turn on produce [...]
+ "healthCheckProducerEnabled": { "index": 10, "kind": "property",
"displayName": "Health Check Producer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all producer based health checks
from this component. Notice: Camel has by default disabled all producer based
health-checks. You can turn on produce [...]
+ "allowQueryFromHeader": { "index": 11, "kind": "property", "displayName":
"Allow Query From Header", "group": "security", "label": "producer,security",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "security": "insecure:dev",
"insecureValue": "true", "defaultValue": false, "description": "Whether to
allow overriding the endpoint-configured SQL query with the CamelSqlQuery
header. Disabled by default; enable it o [...]
},
"headers": {
- "CamelSqlQuery": { "index": 0, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "Query to execute. This query takes precedence
over the query specified in the endpoint URI. Note that query parameters in the
header are represented by a instead of a pass:# symbol", "constantName":
"org.apache.camel.component.sql.SqlConsta [...]
+ "CamelSqlQuery": { "index": 0, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "Query to execute. This header is ignored
unless the endpoint enables allowQueryFromHeader=true (disabled by default);
when enabled it takes precedence over the query specified in the endpoint URI.
Note that query parameters in the header ar [...]
"CamelSqlUpdateCount": { "index": 1, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"Integer", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "important": true, "description": "The number of rows updated
for update operations, returned as an Integer object. This header is not
provided when using outputType=StreamList.", "constantName":
"org.apache.camel.component.sql.SqlConstants#SQL_UPDA [...]
"CamelSqlRowCount": { "index": 2, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"Integer", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "important": true, "description": "The number of rows returned
for select operations, returned as an Integer object. This header is not
provided when using outputType=StreamList.", "constantName":
"org.apache.camel.component.sql.SqlConstants#SQL_ROW_COUNT" },
"CamelSqlRetrieveGeneratedKeys": { "index": 3, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "defaultValue": "false", "description": "Set its value
to true to retrieve generated keys", "constantName":
"org.apache.camel.component.sql.SqlConstants#SQL_RETRIEVE_GENERATED_KEYS" },
@@ -96,6 +97,7 @@
"schedulerProperties": { "index": 45, "kind": "parameter", "displayName":
"Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "object", "javaType":
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": "scheduler.",
"multiValue": true, "deprecated": false, "autowired": false, "secret": false,
"description": "To configure additional properties when using a custom
scheduler or any of the Quartz, Spring based scheduler. This i [...]
"startScheduler": { "index": 46, "kind": "parameter", "displayName":
"Start Scheduler", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether the scheduler should be auto started." },
"timeUnit": { "index": 47, "kind": "parameter", "displayName": "Time
Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [
"NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS",
"DAYS" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and
delay options." },
- "useFixedDelay": { "index": 48, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." }
+ "useFixedDelay": { "index": 48, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." },
+ "allowQueryFromHeader": { "index": 49, "kind": "parameter", "displayName":
"Allow Query From Header", "group": "security", "label": "producer,security",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "security": "insecure:dev",
"insecureValue": "true", "defaultValue": false, "description": "Whether to
allow overriding the endpoint-configured SQL query with the CamelSqlQuery
header. Disabled by default; enable it [...]
}
}
diff --git
a/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/stored/sql-stored.json
b/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/stored/sql-stored.json
index 36831533494b..cf3f69b6ce36 100644
---
a/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/stored/sql-stored.json
+++
b/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/stored/sql-stored.json
@@ -27,10 +27,11 @@
"dataSource": { "index": 0, "kind": "property", "displayName": "Data
Source", "group": "producer", "label": "", "required": false, "type": "object",
"javaType": "javax.sql.DataSource", "deprecated": false, "autowired": true,
"secret": false, "description": "Sets the DataSource to use to communicate with
the database." },
"lazyStartProducer": { "index": 1, "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 [...]
"autowiredEnabled": { "index": 2, "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 t [...]
- "serviceLocationEnabled": { "index": 3, "kind": "property", "displayName":
"Service Location Enabled", "group": "advanced", "label": "advanced",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether to detect the network address location of the database
on startup. This information is gathered via reflection on the DataSource, and
is vendor specific. This option can be used [...]
+ "serviceLocationEnabled": { "index": 3, "kind": "property", "displayName":
"Service Location Enabled", "group": "advanced", "label": "advanced",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether to detect the network address location of the database
on startup. This information is gathered via reflection on the DataSource, and
is vendor specific. This option can be used [...]
+ "allowTemplateFromHeader": { "index": 4, "kind": "property",
"displayName": "Allow Template From Header", "group": "security", "label":
"producer,security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"security": "insecure:dev", "insecureValue": "true", "defaultValue": false,
"description": "Whether to allow overriding the endpoint-configured
stored-procedure template with the CamelSqlStoredTemplate header. Di [...]
},
"headers": {
- "CamelSqlStoredTemplate": { "index": 0, "kind": "header", "displayName":
"", "group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The template", "constantName":
"org.apache.camel.component.sql.stored.SqlStoredConstants#SQL_STORED_TEMPLATE"
},
+ "CamelSqlStoredTemplate": { "index": 0, "kind": "header", "displayName":
"", "group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The stored-procedure template to execute. This
header is ignored unless the endpoint enables allowTemplateFromHeader=true
(disabled by default); when enabled it overrides the endpoint-configured
template.", "constantName": "org.apa [...]
"CamelSqlStoredParameters": { "index": 1, "kind": "header", "displayName":
"", "group": "producer", "label": "producer", "required": false, "javaType":
"Iterator", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The parameters", "constantName":
"org.apache.camel.component.sql.stored.SqlStoredConstants#SQL_STORED_PARAMETERS"
},
"CamelSqlStoredUpdateCount": { "index": 2, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "important": true, "description": "The update count",
"constantName":
"org.apache.camel.component.sql.stored.SqlStoredConstants#SQL_STORED_UPDATE_COUNT"
}
},
@@ -43,6 +44,7 @@
"outputHeader": { "index": 5, "kind": "parameter", "displayName": "Output
Header", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "Store the template result in a header instead
of the message body. By default, outputHeader == null and the template result
is stored in the message body, any existing content in the message body is
discarded. If outputHeader is [...]
"useMessageBodyForTemplate": { "index": 6, "kind": "parameter",
"displayName": "Use Message Body For Template", "group": "producer", "label":
"", "required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": false,
"description": "Whether to use the message body as the stored procedure
template and then headers for parameters. If this option is enabled then the
template in the uri is not used." },
"lazyStartProducer": { "index": 7, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "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 produc [...]
- "templateOptions": { "index": 8, "kind": "parameter", "displayName":
"Template Options", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType": "java.util.Map<java.lang.String,
java.lang.Object>", "prefix": "template.", "multiValue": true, "deprecated":
false, "autowired": false, "secret": false, "description": "Configures the
Spring JdbcTemplate with the key\/values from the Map. This is a multi-value
option with prefix: template." }
+ "templateOptions": { "index": 8, "kind": "parameter", "displayName":
"Template Options", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType": "java.util.Map<java.lang.String,
java.lang.Object>", "prefix": "template.", "multiValue": true, "deprecated":
false, "autowired": false, "secret": false, "description": "Configures the
Spring JdbcTemplate with the key\/values from the Map. This is a multi-value
option with prefix: template." },
+ "allowTemplateFromHeader": { "index": 9, "kind": "parameter",
"displayName": "Allow Template From Header", "group": "security", "label":
"security", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "security":
"insecure:dev", "insecureValue": "true", "defaultValue": false, "description":
"Whether to allow overriding the endpoint-configured stored-procedure template
with the CamelSqlStoredTemplate header. Disabled b [...]
}
}
diff --git
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlEndpoint.java
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlEndpoint.java
index c7f4d5beb616..f808ab51ccef 100644
---
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlEndpoint.java
+++
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlEndpoint.java
@@ -93,6 +93,11 @@ public abstract class DefaultSqlEndpoint extends
DefaultPollingEndpoint implemen
private boolean breakBatchOnConsumeFail;
@UriParam(defaultValue = "true", description = "Whether to allow using
named parameters in the queries.")
private boolean allowNamedParameters = true;
+ @UriParam(defaultValue = "false", label = "producer,security", security =
"insecure:dev", insecureValue = "true",
+ description = "Whether to allow overriding the
endpoint-configured SQL query with the CamelSqlQuery header."
+ + " Disabled by default; enable it only when the
header source is trusted, since it lets a"
+ + " message choose the executed SQL.")
+ private boolean allowQueryFromHeader;
@UriParam(label = "advanced",
description = "If enabled then the populateStatement method from
org.apache.camel.component.sql.SqlPrepareStatementStrategy is always invoked, "
+ "also if there is no expected parameters to be
prepared. When this is false then the populateStatement is only invoked if
there is 1"
@@ -291,6 +296,18 @@ public abstract class DefaultSqlEndpoint extends
DefaultPollingEndpoint implemen
this.allowNamedParameters = allowNamedParameters;
}
+ public boolean isAllowQueryFromHeader() {
+ return allowQueryFromHeader;
+ }
+
+ /**
+ * Whether to allow overriding the endpoint-configured SQL query with the
{@code CamelSqlQuery} header. Disabled by
+ * default.
+ */
+ public void setAllowQueryFromHeader(boolean allowQueryFromHeader) {
+ this.allowQueryFromHeader = allowQueryFromHeader;
+ }
+
public boolean isAlwaysPopulateStatement() {
return alwaysPopulateStatement;
}
diff --git
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlComponent.java
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlComponent.java
index a8495a87aa98..c82957861c29 100644
---
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlComponent.java
+++
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlComponent.java
@@ -56,6 +56,12 @@ public class SqlComponent extends HealthCheckComponent {
description = "Gives the JDBC driver a hint as to the number of
rows that should be fetched from the database when more rows are needed for
ResultSet objects generated by this Statement. If the value specified is zero,
then the hint is ignored. The default value is zero."
+ " This is important for processing large result
sets: Setting this higher than the default value will increase processing speed
at the cost of memory consumption; setting this lower can avoid transferring
row data that will never be read by the application.")
private int fetchSize;
+ @Metadata(label = "producer,security", defaultValue = "false", security =
"insecure:dev", insecureValue = "true",
+ description = "Whether to allow overriding the
endpoint-configured SQL query with the CamelSqlQuery header."
+ + " Disabled by default; enable it only when the
header source is trusted, since it lets a"
+ + " message choose the executed SQL. This is the
default for all sql endpoints and can be"
+ + " overridden per endpoint.")
+ private boolean allowQueryFromHeader;
public SqlComponent() {
}
@@ -116,6 +122,7 @@ public class SqlComponent extends HealthCheckComponent {
endpoint.setBatchAutoCommitDisabled(isBatchAutoCommitDisabled());
endpoint.setFetchSize(getFetchSize());
endpoint.setServiceLocationEnabled(serviceLocationEnabled);
+ endpoint.setAllowQueryFromHeader(isAllowQueryFromHeader());
endpoint.setQuery(query);
endpoint.setPlaceholder(parameterPlaceholderSubstitute);
endpoint.setUsePlaceholder(isUsePlaceholder());
@@ -207,6 +214,18 @@ public class SqlComponent extends HealthCheckComponent {
return fetchSize;
}
+ public boolean isAllowQueryFromHeader() {
+ return allowQueryFromHeader;
+ }
+
+ /**
+ * Whether to allow overriding the endpoint-configured SQL query with the
{@code CamelSqlQuery} header. Disabled by
+ * default; this is the default for all sql endpoints and can be
overridden per endpoint.
+ */
+ public void setAllowQueryFromHeader(boolean allowQueryFromHeader) {
+ this.allowQueryFromHeader = allowQueryFromHeader;
+ }
+
/**
* Gives the JDBC driver a hint as to the number of rows that should be
fetched from the database when more rows are
* needed for ResultSet objects generated by this Statement. If the value
specified is zero, then the hint is
diff --git
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlConstants.java
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlConstants.java
index 0b1f9ddec8de..2e961586aaa5 100644
---
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlConstants.java
+++
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlConstants.java
@@ -23,9 +23,11 @@ import org.apache.camel.spi.Metadata;
*/
public final class SqlConstants {
- @Metadata(label = "producer", description = "Query to execute. This query
takes precedence over the" +
- " query specified in the
endpoint URI. Note that query parameters in the" +
- " header are represented by a
`?` instead of a `pass:[#]` symbol",
+ @Metadata(label = "producer", description = "Query to execute. This header
is ignored unless the endpoint enables" +
+ " allowQueryFromHeader=true
(disabled by default); when enabled it takes" +
+ " precedence over the query
specified in the endpoint URI. Note that" +
+ " query parameters in the
header are represented by a `?` instead of a" +
+ " `pass:[#]` symbol",
javaType = "String")
public static final String SQL_QUERY = "CamelSqlQuery";
@Metadata(label = "producer", description = "The number of rows updated
for `update` operations, returned as an" +
diff --git
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlProducer.java
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlProducer.java
index a40705181ce6..b2e7b7d143bd 100644
---
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlProducer.java
+++
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlProducer.java
@@ -101,7 +101,8 @@ public class SqlProducer extends DefaultProducer {
if (useMessageBodyForSql) {
sql = exchange.getIn().getBody(String.class);
} else {
- String queryHeader =
exchange.getIn().getHeader(SqlConstants.SQL_QUERY, String.class);
+ String queryHeader = getEndpoint().isAllowQueryFromHeader()
+ ? exchange.getIn().getHeader(SqlConstants.SQL_QUERY,
String.class) : null;
if (queryHeader != null) {
String placeholder = getEndpoint().isUsePlaceholder() ?
getEndpoint().getPlaceholder() : null;
sql = SqlHelper.resolvePlaceholders(queryHeader, placeholder);
diff --git
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredComponent.java
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredComponent.java
index 1acb34c4e0e8..ef7f38d2a559 100644
---
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredComponent.java
+++
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredComponent.java
@@ -39,11 +39,18 @@ public class SqlStoredComponent extends DefaultComponent {
+ " This option can be used to turn this off.",
defaultValue = "true")
private boolean serviceLocationEnabled = true;
+ @Metadata(label = "producer,security", defaultValue = "false", security =
"insecure:dev", insecureValue = "true",
+ description = "Whether to allow overriding the
endpoint-configured stored-procedure template with the"
+ + " CamelSqlStoredTemplate header. Disabled by
default; a header-supplied template is"
+ + " resolved with placeholders only, never as a
file:/http: resource. This is the default for"
+ + " all sql-stored endpoints and can be overridden
per endpoint.")
+ private boolean allowTemplateFromHeader;
@Override
protected Endpoint createEndpoint(String uri, String template, Map<String,
Object> parameters) throws Exception {
SqlStoredEndpoint endpoint = new SqlStoredEndpoint(uri, this);
endpoint.setServiceLocationEnabled(serviceLocationEnabled);
+ endpoint.setAllowTemplateFromHeader(isAllowTemplateFromHeader());
endpoint.setTemplate(template);
setProperties(endpoint, parameters);
@@ -92,4 +99,17 @@ public class SqlStoredComponent extends DefaultComponent {
this.serviceLocationEnabled = serviceLocationEnabled;
}
+ public boolean isAllowTemplateFromHeader() {
+ return allowTemplateFromHeader;
+ }
+
+ /**
+ * Whether to allow overriding the endpoint-configured stored-procedure
template with the
+ * {@code CamelSqlStoredTemplate} header. Disabled by default; this is the
default for all sql-stored endpoints and
+ * can be overridden per endpoint.
+ */
+ public void setAllowTemplateFromHeader(boolean allowTemplateFromHeader) {
+ this.allowTemplateFromHeader = allowTemplateFromHeader;
+ }
+
}
diff --git
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredConstants.java
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredConstants.java
index 5b54efaa66f8..a8f91ff518da 100644
---
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredConstants.java
+++
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredConstants.java
@@ -19,7 +19,11 @@ package org.apache.camel.component.sql.stored;
import org.apache.camel.spi.Metadata;
public final class SqlStoredConstants {
- @Metadata(label = "producer", description = "The template", javaType =
"String")
+ @Metadata(label = "producer",
+ description = "The stored-procedure template to execute. This
header is ignored unless the endpoint enables"
+ + " allowTemplateFromHeader=true (disabled by
default); when enabled it overrides the"
+ + " endpoint-configured template.",
+ javaType = "String")
public static final String SQL_STORED_TEMPLATE = "CamelSqlStoredTemplate";
@Metadata(label = "producer", description = "The parameters", javaType =
"Iterator")
public static final String SQL_STORED_PARAMETERS =
"CamelSqlStoredParameters";
diff --git
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredEndpoint.java
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredEndpoint.java
index 9d88a6602931..99f81e108bdc 100644
---
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredEndpoint.java
+++
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredEndpoint.java
@@ -62,6 +62,11 @@ public class SqlStoredEndpoint extends DefaultEndpoint
implements EndpointServic
private boolean batch;
@UriParam(description = "Whether to use the message body as the stored
procedure template and then headers for parameters. If this option is enabled
then the template in the uri is not used.")
private boolean useMessageBodyForTemplate;
+ @UriParam(defaultValue = "false", label = "security", security =
"insecure:dev", insecureValue = "true",
+ description = "Whether to allow overriding the
endpoint-configured stored-procedure template with the"
+ + " CamelSqlStoredTemplate header. Disabled by
default; a header-supplied template is"
+ + " resolved with placeholders only, never as a
file:/http: resource.")
+ private boolean allowTemplateFromHeader;
@UriParam(description = "If set, will ignore the results of the stored
procedure template and use the existing IN message as the OUT message for the
continuation of processing")
private boolean noop;
@UriParam(description = "Store the template result in a header instead of
the message body. By default, outputHeader == null and the template result is
stored"
@@ -195,6 +200,18 @@ public class SqlStoredEndpoint extends DefaultEndpoint
implements EndpointServic
this.useMessageBodyForTemplate = useMessageBodyForTemplate;
}
+ public boolean isAllowTemplateFromHeader() {
+ return allowTemplateFromHeader;
+ }
+
+ /**
+ * Whether to allow overriding the endpoint-configured stored-procedure
template with the
+ * {@code CamelSqlStoredTemplate} header. Disabled by default.
+ */
+ public void setAllowTemplateFromHeader(boolean allowTemplateFromHeader) {
+ this.allowTemplateFromHeader = allowTemplateFromHeader;
+ }
+
public boolean isNoop() {
return noop;
}
diff --git
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredProducer.java
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredProducer.java
index ed036d9b84a0..67b5404ed352 100644
---
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredProducer.java
+++
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredProducer.java
@@ -106,15 +106,29 @@ public class SqlStoredProducer extends DefaultProducer {
private StatementWrapper createStatement(Exchange exchange) throws
SQLException {
String sql;
+ boolean runtime = false;
if (getEndpoint().isUseMessageBodyForTemplate()) {
sql = exchange.getIn().getBody(String.class);
+ runtime = true;
} else {
- String templateHeader =
exchange.getIn().getHeader(SqlStoredConstants.SQL_STORED_TEMPLATE,
String.class);
- sql = templateHeader != null ? templateHeader : resolvedTemplate;
+ String templateHeader = getEndpoint().isAllowTemplateFromHeader()
+ ?
exchange.getIn().getHeader(SqlStoredConstants.SQL_STORED_TEMPLATE,
String.class) : null;
+ if (templateHeader != null) {
+ sql = templateHeader;
+ runtime = true;
+ } else {
+ sql = resolvedTemplate;
+ }
}
try {
- sql = SqlHelper.resolveQuery(getEndpoint().getCamelContext(), sql,
null);
+ // A template taken at runtime from the message body
(useMessageBodyForTemplate) or from a header
+ // (CamelSqlStoredTemplate) is untrusted input, so it must not be
resolved as a file:/http:/classpath:
+ // resource (SqlHelper.resolveQuery -> ResourceHelper does that) -
resolve placeholders only. Only the
+ // endpoint-configured template is resolved as a resource, and
that already happens in doInit/doStart.
+ sql = runtime
+ ? SqlHelper.resolvePlaceholders(sql, null)
+ : SqlHelper.resolveQuery(getEndpoint().getCamelContext(),
sql, null);
} catch (Exception e) {
throw new SQLException("Error loading template resource: " + sql,
e);
}
diff --git
a/components/camel-sql/src/test/java/org/apache/camel/component/sql/SqlRouteTest.java
b/components/camel-sql/src/test/java/org/apache/camel/component/sql/SqlRouteTest.java
index 638d9da1cce9..a89f6118ac75 100644
---
a/components/camel-sql/src/test/java/org/apache/camel/component/sql/SqlRouteTest.java
+++
b/components/camel-sql/src/test/java/org/apache/camel/component/sql/SqlRouteTest.java
@@ -59,6 +59,22 @@ public class SqlRouteTest extends CamelTestSupport {
assertEquals("Linux", row.get("PROJECT"));
}
+ @Test
+ public void testQueryFromHeaderIsIgnoredByDefault() throws Exception {
+ // allowQueryFromHeader defaults to false, so the CamelSqlQuery header
must not override the endpoint query
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMessageCount(1);
+
+ template.sendBodyAndHeader("direct:gated", "XXX",
SqlConstants.SQL_QUERY,
+ "select * from projects where project = 'Camel' order by id");
+ mock.assertIsSatisfied();
+
+ // the endpoint query (license = 'XXX') ran, not the header-supplied
one
+ List<?> received = assertIsInstanceOf(List.class,
mock.getReceivedExchanges().get(0).getIn().getBody());
+ Map<?, ?> row = assertIsInstanceOf(Map.class, received.get(0));
+ assertEquals("Linux", row.get("PROJECT"));
+ }
+
@Test
public void testQueryAsHeader() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:result");
@@ -292,7 +308,10 @@ public class SqlRouteTest extends CamelTestSupport {
errorHandler(noErrorHandler());
- from("direct:simple").to("sql:select * from projects where
license = # order by id")
+ from("direct:simple").to("sql:select * from projects where
license = # order by id?allowQueryFromHeader=true")
+ .to("mock:result");
+
+ from("direct:gated").to("sql:select * from projects where
license = # order by id")
.to("mock:result");
from("direct:list")
diff --git
a/components/camel-sql/src/test/java/org/apache/camel/component/sql/SqlTransactedRouteTest.java
b/components/camel-sql/src/test/java/org/apache/camel/component/sql/SqlTransactedRouteTest.java
index 35f3f4f9c443..d0d4fd2c84af 100644
---
a/components/camel-sql/src/test/java/org/apache/camel/component/sql/SqlTransactedRouteTest.java
+++
b/components/camel-sql/src/test/java/org/apache/camel/component/sql/SqlTransactedRouteTest.java
@@ -41,7 +41,7 @@ public class SqlTransactedRouteTest extends CamelTestSupport {
private JdbcTemplate jdbc;
private String startEndpoint = "direct:start";
- private String sqlEndpoint =
"sql:overriddenByTheHeader?dataSource=#testdb";
+ private String sqlEndpoint =
"sql:overriddenByTheHeader?dataSource=#testdb&allowQueryFromHeader=true";
@Override
public void doPostSetup() {
diff --git
a/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/SqlStoredAllowTemplateFromHeaderTest.java
b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/SqlStoredAllowTemplateFromHeaderTest.java
new file mode 100644
index 000000000000..25c1610d51ca
--- /dev/null
+++
b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/SqlStoredAllowTemplateFromHeaderTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.component.sql.stored;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+/**
+ * Verifies the {@code allowTemplateFromHeader} gate on {@code sql-stored}.
+ * <p>
+ * Both templates call the same {@code SUBNUMBERS} procedure but declare a
different OUT-parameter alias, so the key
+ * present in the result map tells us unambiguously which template text was
executed. The endpoint template aliases the
+ * OUT parameter {@code resultfromendpoint}; the {@code
CamelSqlStoredTemplate} header aliases it
+ * {@code resultfromheader}. This makes both assertions mutation-resistant:
with the gate off the header alias must be
+ * absent, and with the gate on the endpoint alias must be absent.
+ */
+public class SqlStoredAllowTemplateFromHeaderTest extends CamelTestSupport {
+
+ private static final String HEADER_TEMPLATE
+ = "SUBNUMBERS(INTEGER ${headers.num1},INTEGER ${headers.num2},OUT
INTEGER resultfromheader)";
+
+ private EmbeddedDatabase db;
+
+ @Override
+ public void doPreSetup() throws Exception {
+ db = new EmbeddedDatabaseBuilder()
+ .setName(getClass().getSimpleName())
+ .setType(EmbeddedDatabaseType.HSQL)
+ .addScript("sql/storedProcedureTest.sql").build();
+ }
+
+ @Override
+ public void doPostTearDown() throws Exception {
+ if (db != null) {
+ db.shutdown();
+ }
+ }
+
+ @Test
+ public void headerTemplateIgnoredByDefault() {
+ // allowTemplateFromHeader defaults to false: the
CamelSqlStoredTemplate header must be ignored and the
+ // endpoint-configured template executed instead.
+ Map<String, Object> result = execute("direct:gated");
+
+ assertEquals(Integer.valueOf(2), result.get("resultfromendpoint"));
+ assertFalse(result.containsKey("resultfromheader"), "the
header-supplied template must not have been executed");
+ }
+
+ @Test
+ public void headerTemplateHonouredWhenAllowed() {
+ // With allowTemplateFromHeader=true the CamelSqlStoredTemplate header
overrides the endpoint template.
+ Map<String, Object> result = execute("direct:allowed");
+
+ assertEquals(Integer.valueOf(2), result.get("resultfromheader"));
+ assertFalse(result.containsKey("resultfromendpoint"), "the
endpoint-configured template must not have been executed");
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map<String, Object> execute(String uri) {
+ Map<String, Object> headers = new HashMap<>();
+ headers.put("num1", 3);
+ headers.put("num2", 1);
+ headers.put(SqlStoredConstants.SQL_STORED_TEMPLATE, HEADER_TEMPLATE);
+ return template.requestBodyAndHeaders(uri, null, headers, Map.class);
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ getContext().getComponent("sql-stored",
SqlStoredComponent.class).setDataSource(db);
+
+ String endpointTemplate
+ = "SUBNUMBERS(INTEGER ${headers.num1},INTEGER
${headers.num2},OUT INTEGER resultfromendpoint)";
+
+ from("direct:gated").to("sql-stored:" +
endpointTemplate).to("mock:result");
+ from("direct:allowed").to("sql-stored:" + endpointTemplate +
"?allowTemplateFromHeader=true")
+ .to("mock:result");
+ }
+ };
+ }
+}
diff --git
a/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/SqlStoredUseMessageBodyForTemplateResourceTest.java
b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/SqlStoredUseMessageBodyForTemplateResourceTest.java
new file mode 100644
index 000000000000..54a7643bf149
--- /dev/null
+++
b/components/camel-sql/src/test/java/org/apache/camel/component/sql/stored/SqlStoredUseMessageBodyForTemplateResourceTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.component.sql.stored;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * When {@code useMessageBodyForTemplate=true} the message body is the
stored-procedure template text. Because the body
+ * is untrusted per-exchange input, it must be used verbatim and never
dereferenced as a {@code file:} / {@code http:} /
+ * {@code classpath:} resource - only the endpoint-configured template is
resolved as a resource (at route start).
+ */
+public class SqlStoredUseMessageBodyForTemplateResourceTest extends
CamelTestSupport {
+
+ private static final String INLINE_TEMPLATE = "SUBNUMBERS(INTEGER
:#num1,INTEGER :#num2,OUT INTEGER resultofsum)";
+
+ // Points at a real classpath resource holding a valid template. Before
the fix this body would have been loaded
+ // and executed; after the fix it is treated as literal (invalid) template
text.
+ private static final String RESOURCE_BODY =
"classpath:sql/bodyTemplateResource.sql";
+
+ private EmbeddedDatabase db;
+
+ @Override
+ public void doPreSetup() throws Exception {
+ db = new EmbeddedDatabaseBuilder()
+ .setName(getClass().getSimpleName())
+ .setType(EmbeddedDatabaseType.HSQL)
+ .addScript("sql/storedProcedureTest.sql").build();
+ }
+
+ @Override
+ public void doPostTearDown() throws Exception {
+ if (db != null) {
+ db.shutdown();
+ }
+ }
+
+ @Test
+ public void inlineBodyTemplateStillWorks() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:query");
+ mock.expectedMessageCount(1);
+
+ Map<String, Object> params = new HashMap<>();
+ params.put("num1", 3);
+ params.put("num2", 1);
+
+ template.requestBodyAndHeader("direct:query", INLINE_TEMPLATE,
SqlStoredConstants.SQL_STORED_PARAMETERS, params);
+
+ MockEndpoint.assertIsSatisfied(context);
+ assertEquals(Integer.valueOf(2),
mock.getExchanges().get(0).getIn().getBody(Map.class).get("resultofsum"));
+ }
+
+ @Test
+ public void schemePrefixedBodyIsNotResolvedAsResource() {
+ Map<String, Object> params = new HashMap<>();
+ params.put("num1", 3);
+ params.put("num2", 1);
+
+ // The body is a classpath: URI pointing at a valid template. It must
NOT be fetched and executed; instead the
+ // literal string is used as the template and fails to parse - which
is what proves the resource was not loaded.
+ assertThrows(CamelExecutionException.class,
+ () -> template.requestBodyAndHeader("direct:query",
RESOURCE_BODY, SqlStoredConstants.SQL_STORED_PARAMETERS,
+ params));
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ getContext().getComponent("sql-stored",
SqlStoredComponent.class).setDataSource(db);
+
+
from("direct:query").to("sql-stored:query?useMessageBodyForTemplate=true").to("mock:query");
+ }
+ };
+ }
+}
diff --git
a/components/camel-sql/src/test/resources/sql/bodyTemplateResource.sql
b/components/camel-sql/src/test/resources/sql/bodyTemplateResource.sql
new file mode 100644
index 000000000000..174e3bb0253e
--- /dev/null
+++ b/components/camel-sql/src/test/resources/sql/bodyTemplateResource.sql
@@ -0,0 +1,21 @@
+--
+-- 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.
+--
+
+-- A valid stored-procedure template. Referenced only so that, before the fix,
a message body of
+-- "classpath:sql/bodyTemplateResource.sql" would have been dereferenced,
loaded and executed. After the fix the
+-- body is used verbatim as the template text and never resolved as a resource.
+SUBNUMBERS(INTEGER :#num1,INTEGER :#num2,OUT INTEGER resultofsum)
diff --git
a/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
b/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
index 0e7e42151dba..8cdcd2972e95 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
@@ -65,7 +65,9 @@ public final class SecurityUtils {
map.put("allowlocalwebhookurls", new SecurityOption(INSECURE_DEV,
"true"));
map.put("allowoperationheader", new SecurityOption(INSECURE_DEV,
"true"));
map.put("allowpredicatefrommessage", new SecurityOption(INSECURE_DEV,
"true"));
+ map.put("allowqueryfromheader", new SecurityOption(INSECURE_DEV,
"true"));
map.put("allowserializedheaders", new
SecurityOption(INSECURE_SERIALIZATION, "true"));
+ map.put("allowtemplatefromheader", new SecurityOption(INSECURE_DEV,
"true"));
map.put("allowurlbody", new SecurityOption(INSECURE_DEV, "true"));
map.put("allowurlsource", new SecurityOption(INSECURE_DEV, "true"));
map.put("devconsoleenabled", new SecurityOption(INSECURE_DEV, "true"));
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index de812b6cca9d..9027544015e8 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -1990,6 +1990,30 @@ The accessors changed accordingly:
The fluent builder `ParamDefinition.required(Boolean)` is unchanged, and a
`required(String)` overload
was added for placeholders. Routes written in XML, YAML or the Java DSL do not
need any change.
+=== camel-sql, camel-sql-stored - the query/template override headers are gated
+
+A message header could override the endpoint-configured SQL by default,
letting an incoming message choose the
+executed statement:
+
+* `camel-sql`: the `CamelSqlQuery` header replaced the endpoint query.
+* `camel-sql-stored`: the `CamelSqlStoredTemplate` header replaced the
endpoint template, and its value was
+ resolved through `SqlHelper.resolveQuery`, which resolves `file:` / `http:`
/ `classpath:` resources.
+
+Both overrides are now disabled by default and must be opted into, matching
the `allowTemplateFromHeader`
+convention already used by the template components (camel-freemarker,
camel-velocity, camel-xslt, ...):
+
+* `camel-sql`: set `allowQueryFromHeader=true` to honour the `CamelSqlQuery`
header again.
+* `camel-sql-stored`: set `allowTemplateFromHeader=true` to honour the
`CamelSqlStoredTemplate` header again; a
+ header-supplied template is now resolved with property placeholders only,
never as a `file:` / `http:` resource.
+
+A route that relied on either header must set the corresponding option on the
endpoint.
+
+Additionally, `camel-sql-stored` with `useMessageBodyForTemplate=true` now
uses the message body verbatim as the
+stored-procedure template text and no longer resolves it through
`SqlHelper.resolveQuery`. A body beginning with
+`file:`, `http:`, `https:` or `classpath:` is therefore treated as literal
template text instead of being fetched
+as a resource, consistent with how `camel-sql` already treats the body under
`useMessageBodyForSql=true`. A route
+that relied on the body being a resource location must resolve it to the
template text before the `sql-stored`
+endpoint.
=== camel-core - the inheritErrorHandler attribute on circuitBreaker and
failoverLoadBalancer is now a String
`CircuitBreakerDefinition.inheritErrorHandler` and
`FailoverLoadBalancerDefinition.inheritErrorHandler` are now
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SqlComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SqlComponentBuilderFactory.java
index 195bff6f22ed..1d47af535c29 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SqlComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SqlComponentBuilderFactory.java
@@ -272,6 +272,27 @@ public interface SqlComponentBuilderFactory {
doSetProperty("healthCheckProducerEnabled",
healthCheckProducerEnabled);
return this;
}
+
+
+ /**
+ * Whether to allow overriding the endpoint-configured SQL query with
+ * the CamelSqlQuery header. Disabled by default; enable it only when
+ * the header source is trusted, since it lets a message choose the
+ * executed SQL. This is the default for all sql endpoints and can be
+ * overridden per endpoint.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: security
+ *
+ * @param allowQueryFromHeader the value to set
+ * @return the dsl builder
+ */
+ default SqlComponentBuilder allowQueryFromHeader(boolean
allowQueryFromHeader) {
+ doSetProperty("allowQueryFromHeader", allowQueryFromHeader);
+ return this;
+ }
}
class SqlComponentBuilderImpl
@@ -298,6 +319,7 @@ public interface SqlComponentBuilderFactory {
case "usePlaceholder": ((SqlComponent)
component).setUsePlaceholder((boolean) value); return true;
case "healthCheckConsumerEnabled": ((SqlComponent)
component).setHealthCheckConsumerEnabled((boolean) value); return true;
case "healthCheckProducerEnabled": ((SqlComponent)
component).setHealthCheckProducerEnabled((boolean) value); return true;
+ case "allowQueryFromHeader": ((SqlComponent)
component).setAllowQueryFromHeader((boolean) value); return true;
default: return false;
}
}
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SqlStoredComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SqlStoredComponentBuilderFactory.java
index c7de52231409..519d97457b9a 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SqlStoredComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SqlStoredComponentBuilderFactory.java
@@ -131,6 +131,27 @@ public interface SqlStoredComponentBuilderFactory {
doSetProperty("serviceLocationEnabled", serviceLocationEnabled);
return this;
}
+
+
+ /**
+ * Whether to allow overriding the endpoint-configured stored-procedure
+ * template with the CamelSqlStoredTemplate header. Disabled by
default;
+ * a header-supplied template is resolved with placeholders only, never
+ * as a file:/http: resource. This is the default for all sql-stored
+ * endpoints and can be overridden per endpoint.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: security
+ *
+ * @param allowTemplateFromHeader the value to set
+ * @return the dsl builder
+ */
+ default SqlStoredComponentBuilder allowTemplateFromHeader(boolean
allowTemplateFromHeader) {
+ doSetProperty("allowTemplateFromHeader", allowTemplateFromHeader);
+ return this;
+ }
}
class SqlStoredComponentBuilderImpl
@@ -150,6 +171,7 @@ public interface SqlStoredComponentBuilderFactory {
case "lazyStartProducer": ((SqlStoredComponent)
component).setLazyStartProducer((boolean) value); return true;
case "autowiredEnabled": ((SqlStoredComponent)
component).setAutowiredEnabled((boolean) value); return true;
case "serviceLocationEnabled": ((SqlStoredComponent)
component).setServiceLocationEnabled((boolean) value); return true;
+ case "allowTemplateFromHeader": ((SqlStoredComponent)
component).setAllowTemplateFromHeader((boolean) value); return true;
default: return false;
}
}
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlEndpointBuilderFactory.java
index faf0a326350a..29c523e3706d 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlEndpointBuilderFactory.java
@@ -1749,6 +1749,42 @@ public interface SqlEndpointBuilderFactory {
doSetProperty("useMessageBodyForSql", useMessageBodyForSql);
return this;
}
+ /**
+ * Whether to allow overriding the endpoint-configured SQL query with
+ * the CamelSqlQuery header. Disabled by default; enable it only when
+ * the header source is trusted, since it lets a message choose the
+ * executed SQL.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: security
+ *
+ * @param allowQueryFromHeader the value to set
+ * @return the dsl builder
+ */
+ default SqlEndpointProducerBuilder allowQueryFromHeader(boolean
allowQueryFromHeader) {
+ doSetProperty("allowQueryFromHeader", allowQueryFromHeader);
+ return this;
+ }
+ /**
+ * Whether to allow overriding the endpoint-configured SQL query with
+ * the CamelSqlQuery header. Disabled by default; enable it only when
+ * the header source is trusted, since it lets a message choose the
+ * executed SQL.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: security
+ *
+ * @param allowQueryFromHeader the value to set
+ * @return the dsl builder
+ */
+ default SqlEndpointProducerBuilder allowQueryFromHeader(String
allowQueryFromHeader) {
+ doSetProperty("allowQueryFromHeader", allowQueryFromHeader);
+ return this;
+ }
}
/**
@@ -2628,9 +2664,11 @@ public interface SqlEndpointBuilderFactory {
public static final SqlHeaderNameBuilder INSTANCE = new
SqlHeaderNameBuilder();
/**
- * Query to execute. This query takes precedence over the query
- * specified in the endpoint URI. Note that query parameters in the
- * header are represented by a instead of a pass:# symbol.
+ * Query to execute. This header is ignored unless the endpoint enables
+ * allowQueryFromHeader=true (disabled by default); when enabled it
+ * takes precedence over the query specified in the endpoint URI. Note
+ * that query parameters in the header are represented by a instead of
a
+ * pass:# symbol.
*
* The option is a: {@code String} type.
*
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlStoredEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlStoredEndpointBuilderFactory.java
index 51c7beff81d3..1dc31b485fb4 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlStoredEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlStoredEndpointBuilderFactory.java
@@ -220,6 +220,42 @@ public interface SqlStoredEndpointBuilderFactory {
doSetProperty("useMessageBodyForTemplate",
useMessageBodyForTemplate);
return this;
}
+ /**
+ * Whether to allow overriding the endpoint-configured stored-procedure
+ * template with the CamelSqlStoredTemplate header. Disabled by
default;
+ * a header-supplied template is resolved with placeholders only, never
+ * as a file:/http: resource.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: security
+ *
+ * @param allowTemplateFromHeader the value to set
+ * @return the dsl builder
+ */
+ default SqlStoredEndpointBuilder allowTemplateFromHeader(boolean
allowTemplateFromHeader) {
+ doSetProperty("allowTemplateFromHeader", allowTemplateFromHeader);
+ return this;
+ }
+ /**
+ * Whether to allow overriding the endpoint-configured stored-procedure
+ * template with the CamelSqlStoredTemplate header. Disabled by
default;
+ * a header-supplied template is resolved with placeholders only, never
+ * as a file:/http: resource.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: security
+ *
+ * @param allowTemplateFromHeader the value to set
+ * @return the dsl builder
+ */
+ default SqlStoredEndpointBuilder allowTemplateFromHeader(String
allowTemplateFromHeader) {
+ doSetProperty("allowTemplateFromHeader", allowTemplateFromHeader);
+ return this;
+ }
}
/**
@@ -394,7 +430,9 @@ public interface SqlStoredEndpointBuilderFactory {
public static final SqlStoredHeaderNameBuilder INSTANCE = new
SqlStoredHeaderNameBuilder();
/**
- * The template.
+ * The stored-procedure template to execute. This header is ignored
+ * unless the endpoint enables allowTemplateFromHeader=true (disabled
by
+ * default); when enabled it overrides the endpoint-configured
template.
*
* The option is a: {@code String} type.
*