Skip to content

Commit 20e2622

Browse files
committed
CAMEL-10575: snakeyaml: add an option to filter classes the yaml parser can construct
1 parent 9e9a86b commit 20e2622

File tree

22 files changed

+1120
-125
lines changed

22 files changed

+1120
-125
lines changed

camel-core/src/main/java/org/apache/camel/model/dataformat/YAMLDataFormat.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
*/
1717
package org.apache.camel.model.dataformat;
1818

19+
import java.util.ArrayList;
20+
import java.util.List;
1921
import javax.xml.bind.annotation.XmlAccessType;
2022
import javax.xml.bind.annotation.XmlAccessorType;
2123
import javax.xml.bind.annotation.XmlAttribute;
24+
import javax.xml.bind.annotation.XmlElement;
2225
import javax.xml.bind.annotation.XmlRootElement;
2326
import javax.xml.bind.annotation.XmlTransient;
2427

@@ -58,6 +61,10 @@ public class YAMLDataFormat extends DataFormatDefinition {
5861
private Boolean useApplicationContextClassLoader = true;
5962
@XmlAttribute @Metadata(defaultValue = "false")
6063
private Boolean prettyFlow = false;
64+
@XmlAttribute @Metadata(defaultValue = "false")
65+
private Boolean allowAnyType = false;
66+
@XmlElement(name = "typeFilter")
67+
private List<YAMLTypeFilterDefinition> typeFilters;
6168

6269
public YAMLDataFormat() {
6370
this(YAMLLibrary.SnakeYAML);
@@ -188,6 +195,28 @@ public void setPrettyFlow(boolean prettyFlow) {
188195
this.prettyFlow = prettyFlow;
189196
}
190197

198+
public boolean isAllowAnyType() {
199+
return allowAnyType;
200+
}
201+
202+
/**
203+
* Allow any class to be un-marshaled
204+
*/
205+
public void setAllowAnyType(boolean allowAnyType) {
206+
this.allowAnyType = allowAnyType;
207+
}
208+
209+
public List<YAMLTypeFilterDefinition> getTypeFilters() {
210+
return typeFilters;
211+
}
212+
213+
/**
214+
* Set the types SnakeYAML is allowed to un-marshall
215+
*/
216+
public void setTypeFilters(List<YAMLTypeFilterDefinition> typeFilters) {
217+
this.typeFilters = typeFilters;
218+
}
219+
191220
@Override
192221
protected DataFormat createDataFormat(RouteContext routeContext) {
193222
if (library == YAMLLibrary.SnakeYAML) {
@@ -218,6 +247,27 @@ protected void configureSnakeDataFormat(DataFormat dataFormat, CamelContext came
218247
setProperty(dataFormat, camelContext, "classLoader", classLoader);
219248
setProperty(dataFormat, camelContext, "useApplicationContextClassLoader", useApplicationContextClassLoader);
220249
setProperty(dataFormat, camelContext, "prettyFlow", prettyFlow);
250+
setProperty(dataFormat, camelContext, "allowAnyType", allowAnyType);
251+
252+
if (typeFilters != null && !typeFilters.isEmpty()) {
253+
List<String> typeFilterDefinitions = new ArrayList<>(typeFilters.size());
254+
for (YAMLTypeFilterDefinition definition : typeFilters) {
255+
String value = definition.getValue();
256+
257+
if (!value.startsWith("type") && !value.startsWith("regexp")) {
258+
YAMLTypeFilterType type = definition.getType();
259+
if (type == null) {
260+
type = YAMLTypeFilterType.type;
261+
}
262+
263+
value = type.name() + ":" + value;
264+
}
265+
266+
typeFilterDefinitions.add(value);
267+
}
268+
269+
setProperty(dataFormat, camelContext, "typeFilterDefinitions", typeFilterDefinitions);
270+
}
221271

222272
setPropertyRef(dataFormat, camelContext, "constructor", constructor);
223273
setPropertyRef(dataFormat, camelContext, "representer", representer);
@@ -238,4 +288,5 @@ protected void setPropertyRef(DataFormat dataFormat, CamelContext camelContext,
238288
setProperty(camelContext, dataFormat, propertyName, ref);
239289
}
240290
}
291+
241292
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.camel.model.dataformat;
18+
19+
import javax.xml.bind.annotation.XmlAccessType;
20+
import javax.xml.bind.annotation.XmlAccessorType;
21+
import javax.xml.bind.annotation.XmlAttribute;
22+
import javax.xml.bind.annotation.XmlRootElement;
23+
24+
@XmlRootElement(name = "typeFilter")
25+
@XmlAccessorType(XmlAccessType.FIELD)
26+
public final class YAMLTypeFilterDefinition {
27+
@XmlAttribute
28+
private String value;
29+
@XmlAttribute
30+
private YAMLTypeFilterType type;
31+
32+
public String getValue() {
33+
return value;
34+
}
35+
36+
public void setValue(String value) {
37+
this.value = value;
38+
}
39+
40+
public YAMLTypeFilterType getType() {
41+
return type;
42+
}
43+
44+
public void setType(YAMLTypeFilterType type) {
45+
this.type = type;
46+
}
47+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.camel.model.dataformat;
19+
20+
import javax.xml.bind.annotation.XmlEnum;
21+
22+
@XmlEnum
23+
public enum YAMLTypeFilterType {
24+
type,
25+
regexp
26+
}

components/camel-snakeyaml/pom.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,17 @@
4545
<artifactId>snakeyaml</artifactId>
4646
<version>${snakeyaml-version}</version>
4747
</dependency>
48-
4948
<!-- testing -->
5049
<dependency>
5150
<groupId>org.apache.camel</groupId>
5251
<artifactId>camel-test-spring</artifactId>
5352
<scope>test</scope>
5453
</dependency>
54+
<dependency>
55+
<groupId>org.apache.camel</groupId>
56+
<artifactId>camel-test-blueprint</artifactId>
57+
<scope>test</scope>
58+
</dependency>
5559
<dependency>
5660
<groupId>org.apache.logging.log4j</groupId>
5761
<artifactId>log4j-api</artifactId>

components/camel-snakeyaml/src/main/docs/yaml-snakeyaml-dataformat.adoc

Lines changed: 77 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,12 @@ Every library requires adding the special camel component (see
1414
"Dependency..." paragraphs further down). By default Camel uses the
1515
SnakeYAML library.
1616

17-
[[YAMLDataFormat-UsingYAMLdataformatwiththeSnakeYAMLlibrary]]
18-
Using YAML data format with the SnakeYAML library
19-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
20-
21-
[source,java]
22-
------------------------------------------------------------
23-
// lets turn Object messages into yaml then send to MQSeries
24-
from("activemq:My.Queue")
25-
.marshal().yaml()
26-
.to("mqseries:Another.Queue");
27-
------------------------------------------------------------
28-
29-
[source,java]
30-
------------------------------------------------------------
31-
// lets turn Object messages into yaml then send to MQSeries
32-
from("activemq:My.Queue")
33-
.marshal().yaml(YAMLLibrary.SnakeYAML)
34-
.to("mqseries:Another.Queue");
35-
------------------------------------------------------------
36-
3717
[[YAML-Options]]
3818
YAML Options
3919
^^^^^^^^^^^^
4020

41-
42-
4321
// dataformat options: START
44-
The YAML SnakeYAML dataformat supports 8 options which are listed below.
22+
The YAML SnakeYAML dataformat supports 10 options which are listed below.
4523

4624

4725

@@ -57,11 +35,48 @@ The YAML SnakeYAML dataformat supports 8 options which are listed below.
5735
| resolver | | String | Resolver to detect implicit type
5836
| useApplicationContextClassLoader | true | Boolean | Use ApplicationContextClassLoader as custom ClassLoader
5937
| prettyFlow | false | Boolean | Force the emitter to produce a pretty YAML document when using the flow style.
38+
| allowAnyType | false | Boolean | Allow any class to be un-marshaled
39+
| typeFilter | | List | Set the types SnakeYAML is allowed to un-marshall
6040
|=======================================================================
6141
{% endraw %}
6242
// dataformat options: END
6343

44+
WARNING: SnakeYAML can load any class from YAML definition which may lead to security breach so by default, SnakeYAML DataForma restrict the object it can load to standard Java objects like List or Long. If you want to load custom POJOs you need to add theirs type to SnakeYAML DataFormat type filter list. If your source is trusted, you can set the property allowAnyType to true so SnakeYAML DataForma won't perform any filter on the types.
6445

46+
[[YAMLDataFormat-UsingYAMLdataformatwiththeSnakeYAMLlibrary]]
47+
Using YAML data format with the SnakeYAML library
48+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49+
50+
- Turn Object messages into yaml then send to MQSeries
51+
+
52+
[source,java]
53+
------------------------------------------------------------
54+
from("activemq:My.Queue")
55+
.marshal().yaml()
56+
.to("mqseries:Another.Queue");
57+
------------------------------------------------------------
58+
+
59+
[source,java]
60+
------------------------------------------------------------
61+
from("activemq:My.Queue")
62+
.marshal().yaml(YAMLLibrary.SnakeYAML)
63+
.to("mqseries:Another.Queue");
64+
------------------------------------------------------------
65+
66+
- Restrict classes to be loaded from YAML
67+
+
68+
[source,java]
69+
------------------------------------------------------------
70+
// Creat a SnakeYAMLDataFormat instance
71+
SnakeYAMLDataFormat yaml = new SnakeYAMLDataFormat();
72+
73+
// Restrict classes to be loaded from YAML
74+
yaml.addTypeFilters(TypeFilters.types(MyPojo.class, MyOtherPojo.class));
75+
76+
from("activemq:My.Queue")
77+
.unmarshal(yaml)
78+
.to("mqseries:Another.Queue");
79+
------------------------------------------------------------
6580

6681
[[YAMLDataFormat-UsingYAMLinSpringDSL]]
6782
Using YAML in Spring DSL
@@ -72,56 +87,50 @@ declare the data formats first. This is done in the *DataFormats* XML
7287
tag.
7388

7489
[source,xml]
75-
----------------------------------------------------------------------------------------------------------------------------------
76-
<dataFormats>
77-
<!-- here we define a YAML data format with the id snak and that it should use the TestPojo as the class type when
78-
doing unmarshal. The unmarshalTypeName is optional, if not provided Camel will use a Object.class as the type -->
79-
<yaml id="snake" library="SnakeYAML" unmarshalTypeName="org.apache.camel.component.yaml.model.TestPojo"/>
80-
</dataFormats>
81-
----------------------------------------------------------------------------------------------------------------------------------
82-
83-
And then you can refer to this id in the route:
90+
--------------------------------------------------------------------------------
91+
<dataFormats>
92+
<!--
93+
here we define a YAML data format with the id snake and that it should use
94+
the TestPojo as the class type when doing unmarshal. The unmarshalTypeName
95+
is optional
96+
-->
97+
<yaml
98+
id="snake"
99+
library="SnakeYAML"
100+
unmarshalTypeName="org.apache.camel.component.yaml.model.TestPojo"/>
101+
102+
<!--
103+
here we define a YAML data format with the id snake-safe which restricts the
104+
classes to be loaded from YAML to TestPojo and those belonging to package
105+
com.mycompany
106+
-->
107+
<yaml id="snake-safe">
108+
<typeFilter value="org.apache.camel.component.yaml.model.TestPojo"/>
109+
<typeFilter value="com.mycompany\..*" type="regexp"/>
110+
</yaml>
111+
</dataFormats>
112+
--------------------------------------------------------------------------------
113+
114+
And then you can refer to those ids in the route:
84115

85116
[source,xml]
86117
-------------------------------------
87-
<route>
88-
<from uri="direct:back"/>
89-
<unmarshal ref="snake"/>
90-
<to uri="mock:reverse"/>
91-
</route>
118+
<route>
119+
<from uri="direct:unmarshal"/>
120+
<unmarshal>
121+
<custom ref="snake"/>
122+
</unmarshal>
123+
<to uri="mock:unmarshal"/>
124+
</route>
125+
<route>
126+
<from uri="direct:unmarshal-safe"/>
127+
<unmarshal>
128+
<custom ref="snake-safe"/>
129+
</unmarshal>
130+
<to uri="mock:unmarshal-safe"/>
131+
</route>
92132
-------------------------------------
93133

94-
 
95-
96-
[[YAMLDataFormat-OptionsforSnakeYAMLDataFormat]]
97-
Options for SnakeYAML Data Format
98-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
99-
100-
[width="100%",cols="<25%,<25%,<25%,<25%",options="header",]
101-
|=======================================================================
102-
|Name |Type |Default |Description
103-
|unmarshalType |`Class` |`Object.class` |Class of the object to be created
104-
105-
|classLoader |ClassLoader |null |The classloader to use to
106-
instantiate objects
107-
108-
|constructor |String |null |A reference to an
109-
org.yaml.snakeyaml.constructor.BaseConstructor instance in the registry
110-
111-
|representer |String |null |A reference to an
112-
org.yaml.snakeyaml.representer.Representer instance in the registry
113-
114-
|dumperOptions |String |null |A reference to an
115-
org.yaml.snakeyaml.DumperOptions instance in the registry
116-
117-
|resolver |String |null |A reference to an
118-
org.yaml.snakeyaml.resolver.Resolver instance in the registry
119-
120-
|useApplicationContextClassLoader | Boolean |true  |To use CamelContext's ApplicationContextClassLoader if no custom class loader is set and
121-
ApplicationContextClassLoader is provided
122-
123-
|prettyFlow | Boolean |false  |Force the emitter to produce a pretty YAML document when using the flow style
124-
|=======================================================================
125134

126135
[[YAMLDataFormat-DependenciesforSnakeYAML]]
127136
Dependencies for SnakeYAML

0 commit comments

Comments
 (0)