Skip to content

Commit bdff8f3

Browse files
committed
CAMEL-11929: camel-castor - Add more configuration
1 parent cd41c2f commit bdff8f3

File tree

9 files changed

+307
-7
lines changed

9 files changed

+307
-7
lines changed

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@
3838
public class CastorDataFormat extends DataFormatDefinition {
3939
@XmlAttribute
4040
private String mappingFile;
41+
@XmlAttribute
42+
@Metadata(defaultValue = "true")
43+
private Boolean whitelistEnabled = true;
44+
@XmlAttribute
45+
private String allowedUnmarshallObjects;
46+
@XmlAttribute
47+
private String deniedUnmarshallObjects;
4148
@XmlAttribute @Metadata(defaultValue = "true")
4249
private Boolean validation;
4350
@XmlAttribute @Metadata(defaultValue = "UTF-8")
@@ -110,6 +117,45 @@ public void setEncoding(String encoding) {
110117
this.encoding = encoding;
111118
}
112119

120+
/**
121+
* Define if Whitelist feature is enabled or not
122+
*/
123+
public void setWhitelistEnabled(Boolean whitelistEnabled) {
124+
this.whitelistEnabled = whitelistEnabled;
125+
}
126+
127+
public String getAllowedUnmarshallObjects() {
128+
return allowedUnmarshallObjects;
129+
}
130+
131+
/**
132+
* Define the allowed objects to be unmarshalled.
133+
*
134+
* You can specify the FQN class name of allowed objects, and you can use comma to separate multiple entries.
135+
* It is also possible to use wildcards and regular expression which is based on the pattern
136+
* defined by {@link org.apache.camel.util.EndpointHelper#matchPattern(String, String)}.
137+
* Denied objects takes precedence over allowed objects.
138+
*/
139+
public void setAllowedUnmarshallObjects(String allowedUnmarshallObjects) {
140+
this.allowedUnmarshallObjects = allowedUnmarshallObjects;
141+
}
142+
143+
public String getDeniedUnmarshallObjects() {
144+
return deniedUnmarshallObjects;
145+
}
146+
147+
/**
148+
* Define the denied objects to be unmarshalled.
149+
*
150+
* You can specify the FQN class name of deined objects, and you can use comma to separate multiple entries.
151+
* It is also possible to use wildcards and regular expression which is based on the pattern
152+
* defined by {@link org.apache.camel.util.EndpointHelper#matchPattern(String, String)}.
153+
* Denied objects takes precedence over allowed objects.
154+
*/
155+
public void setDeniedUnmarshallObjects(String deniedUnmarshallObjects) {
156+
this.deniedUnmarshallObjects = deniedUnmarshallObjects;
157+
}
158+
113159
@Override
114160
protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) {
115161
if (mappingFile != null) {
@@ -128,6 +174,15 @@ protected void configureDataFormat(DataFormat dataFormat, CamelContext camelCont
128174
if (classes != null) {
129175
setProperty(camelContext, dataFormat, "classes", classes);
130176
}
177+
if (whitelistEnabled != null) {
178+
setProperty(camelContext, dataFormat, "whitelistEnabled", whitelistEnabled);
179+
}
180+
if (allowedUnmarshallObjects != null) {
181+
setProperty(camelContext, dataFormat, "allowedUnmarshallObjects", allowedUnmarshallObjects);
182+
}
183+
if (deniedUnmarshallObjects != null) {
184+
setProperty(camelContext, dataFormat, "deniedUnmarshallObjects", deniedUnmarshallObjects);
185+
}
131186
}
132187

133188
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,8 @@ public class HessianDataFormat extends DataFormatDefinition {
3535
@XmlAttribute
3636
@Metadata(defaultValue = "true")
3737
private Boolean whitelistEnabled = true;
38-
3938
@XmlAttribute
4039
private String allowedUnmarshallObjects;
41-
4240
@XmlAttribute
4341
private String deniedUnmarshallObjects;
4442

components/camel-castor/src/main/docs/castor-dataformat.adoc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,17 @@ on multiple routes. You have to set the <castor> element directly in
105105
### Options
106106

107107
// dataformat options: START
108-
The Castor dataformat supports 6 options which are listed below.
108+
The Castor dataformat supports 9 options which are listed below.
109109

110110

111111

112112
[width="100%",cols="2s,1m,1m,6",options="header"]
113113
|===
114114
| Name | Default | Java Type | Description
115115
| mappingFile | | String | Path to a Castor mapping file to load from the classpath.
116+
| whitelistEnabled | true | Boolean | Define if Whitelist feature is enabled or not
117+
| allowedUnmarshallObjects | | String | Define the allowed objects to be unmarshalled. You can specify the FQN class name of allowed objects and you can use comma to separate multiple entries. It is also possible to use wildcards and regular expression which is based on the pattern defined by link org.apache.camel.util.EndpointHelpermatchPattern(String String). Denied objects takes precedence over allowed objects.
118+
| deniedUnmarshallObjects | | String | Define the denied objects to be unmarshalled. You can specify the FQN class name of deined objects and you can use comma to separate multiple entries. It is also possible to use wildcards and regular expression which is based on the pattern defined by link org.apache.camel.util.EndpointHelpermatchPattern(String String). Denied objects takes precedence over allowed objects.
116119
| validation | true | Boolean | Whether validation is turned on or off. Is by default true.
117120
| encoding | UTF-8 | String | Encoding to use when marshalling an Object to XML. Is by default UTF-8
118121
| packages | | String[] | Add additional packages to Castor XmlContext
@@ -137,4 +140,4 @@ link:download.html[the download page for the latest versions]).
137140
<artifactId>camel-castor</artifactId>
138141
<version>x.x.x</version>
139142
</dependency>
140-
---------------------------------------
143+
---------------------------------------

components/camel-castor/src/main/java/org/apache/camel/dataformat/castor/AbstractCastorDataFormat.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.apache.camel.spi.DataFormat;
3131
import org.apache.camel.spi.DataFormatName;
3232
import org.apache.camel.support.ServiceSupport;
33+
import org.apache.camel.util.CollectionStringBuffer;
3334
import org.apache.camel.util.ObjectHelper;
3435
import org.exolab.castor.mapping.Mapping;
3536
import org.exolab.castor.xml.Marshaller;
@@ -57,6 +58,9 @@ public abstract class AbstractCastorDataFormat extends ServiceSupport implements
5758
private boolean validation;
5859
private volatile XMLContext xmlContext;
5960
private boolean contentTypeHeader = true;
61+
private boolean whitlistEnabled = true;
62+
private String allowedUnmarshallObjects;
63+
private String deniedUnmarshallObjects;
6064

6165
public AbstractCastorDataFormat() {
6266
}
@@ -129,6 +133,12 @@ public Unmarshaller createUnmarshaller(Exchange exchange) throws Exception {
129133
// need to create new marshaller as we may have concurrent processing
130134
Unmarshaller answer = xmlContext.createUnmarshaller();
131135
answer.setValidation(isValidation());
136+
if (whitlistEnabled) {
137+
WhitelistObjectFactory factory = new WhitelistObjectFactory();
138+
factory.setAllowClasses(allowedUnmarshallObjects);
139+
factory.setDenyClasses(deniedUnmarshallObjects);
140+
answer.setObjectFactory(factory);
141+
}
132142
return answer;
133143
}
134144

@@ -183,7 +193,6 @@ public void setValidation(boolean validation) {
183193
this.validation = validation;
184194
}
185195

186-
187196
public boolean isContentTypeHeader() {
188197
return contentTypeHeader;
189198
}
@@ -195,6 +204,38 @@ public void setContentTypeHeader(boolean contentTypeHeader) {
195204
this.contentTypeHeader = contentTypeHeader;
196205
}
197206

207+
public boolean isWhitlistEnabled() {
208+
return whitlistEnabled;
209+
}
210+
211+
public void setWhitlistEnabled(boolean whitlistEnabled) {
212+
this.whitlistEnabled = whitlistEnabled;
213+
}
214+
215+
public String getAllowedUnmarshallObjects() {
216+
return allowedUnmarshallObjects;
217+
}
218+
219+
public void setAllowedUnmarshallObjects(String allowedUnmarshallObjects) {
220+
this.allowedUnmarshallObjects = allowedUnmarshallObjects;
221+
}
222+
223+
public void setAllowClasses(Class... allowClasses) {
224+
CollectionStringBuffer csb = new CollectionStringBuffer(",");
225+
for (Class clazz : allowClasses) {
226+
csb.append(clazz.getName());
227+
}
228+
this.allowedUnmarshallObjects = csb.toString();
229+
}
230+
231+
public String getDeniedUnmarshallObjects() {
232+
return deniedUnmarshallObjects;
233+
}
234+
235+
public void setDeniedUnmarshallObjects(String deniedUnmarshallObjects) {
236+
this.deniedUnmarshallObjects = deniedUnmarshallObjects;
237+
}
238+
198239
@Override
199240
protected void doStart() throws Exception {
200241
if (xmlContext == null) {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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.dataformat.castor;
18+
19+
import org.apache.camel.util.EndpointHelper;
20+
import org.exolab.castor.util.DefaultObjectFactory;
21+
22+
public class WhitelistObjectFactory extends DefaultObjectFactory {
23+
24+
private String allowClasses;
25+
private String denyClasses;
26+
27+
public String getAllowClasses() {
28+
return allowClasses;
29+
}
30+
31+
public void setAllowClasses(String allowClasses) {
32+
this.allowClasses = allowClasses;
33+
}
34+
35+
public String getDenyClasses() {
36+
return denyClasses;
37+
}
38+
39+
public void setDenyClasses(String denyClasses) {
40+
this.denyClasses = denyClasses;
41+
}
42+
43+
@Override
44+
public Object createInstance(Class type) throws IllegalAccessException, InstantiationException {
45+
if (allowCreate(type)) {
46+
return super.createInstance(type);
47+
} else {
48+
throw new IllegalAccessException("Not allowed to create class of type: " + type);
49+
}
50+
}
51+
52+
@Override
53+
public Object createInstance(Class type, Object[] args) throws IllegalAccessException, InstantiationException {
54+
if (allowCreate(type)) {
55+
return super.createInstance(type, args);
56+
} else {
57+
throw new IllegalAccessException("Not allowed to create class of type: " + type);
58+
}
59+
}
60+
61+
@Override
62+
public Object createInstance(Class type, Class[] argTypes, Object[] args) throws IllegalAccessException, InstantiationException {
63+
if (allowCreate(type)) {
64+
return super.createInstance(type, argTypes, args);
65+
} else {
66+
throw new IllegalAccessException("Not allowed to create class of type: " + type);
67+
}
68+
}
69+
70+
private boolean allowCreate(Class type) {
71+
String name = type.getName();
72+
73+
// deny takes precedence
74+
if (denyClasses != null) {
75+
String[] arr = denyClasses.split(",");
76+
for (String key : arr) {
77+
if (EndpointHelper.matchPattern(name, key)) {
78+
return false;
79+
}
80+
}
81+
}
82+
83+
// deny takes precedence
84+
if (allowClasses != null) {
85+
String[] arr = allowClasses.split(",");
86+
for (String key : arr) {
87+
if (EndpointHelper.matchPattern(name, key)) {
88+
return true;
89+
}
90+
}
91+
}
92+
93+
// deny by default
94+
return false;
95+
}
96+
}

components/camel-castor/src/test/java/org/apache/camel/dataformat/castor/MarshalWithMappingDomainObjectTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ public void configure() throws Exception {
7373

7474
CastorDataFormat myformat = new CastorDataFormat();
7575
myformat.setMappingFile("map.xml");
76-
7776
myformat.setValidation(true);
77+
myformat.setAllowClasses(Student.class);
78+
7879
from("direct:marshal").marshal(myformat).to("mock:marshal");
7980
from("direct:unmarshal").unmarshal(myformat).to("mock:unmarshal");
8081

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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.dataformat.castor;
18+
19+
import org.apache.camel.RoutesBuilder;
20+
import org.apache.camel.builder.RouteBuilder;
21+
import org.apache.camel.test.junit4.CamelTestSupport;
22+
import org.junit.Test;
23+
24+
public class WhitelistTest extends CamelTestSupport {
25+
26+
@Test
27+
public void testDeny() throws Exception {
28+
final String stuff = "<x xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:java=\"http://java.sun.com\""
29+
+ " xsi:type=\"java:org.springframework.beans.factory.config.PropertyPathFactoryBean\">"
30+
+ "<target-bean-name>ldap://localhost:1389/obj</target-bean-name><property-path>foo</property-path>"
31+
+ "<bean-factory xsi:type=\"java:org.springframework.jndi.support.SimpleJndiBeanFactory\">"
32+
+ "<shareable-resource>ldap://localhost:1389/obj</shareable-resource></bean-factory></x>";
33+
34+
try {
35+
template.sendBody("direct:unmarshal", stuff);
36+
fail("Should throw an error");
37+
} catch (Exception e) {
38+
IllegalAccessException iae = assertIsInstanceOf(IllegalAccessException.class, e.getCause().getCause());
39+
assertNotNull(iae);
40+
assertTrue(iae.getMessage().startsWith("Not allowed to create class of type: class org.springframework.beans.factory.config.PropertyPathFactoryBean"));
41+
}
42+
}
43+
44+
@Override
45+
protected RoutesBuilder createRouteBuilder() throws Exception {
46+
CastorDataFormat castor = new CastorDataFormat();
47+
// note that whitelist is enabled by default
48+
// castor.setWhitlistEnabled(true);
49+
// and that everything is denied by default
50+
// so you would need to configure allow to enable safe classes to be loaded
51+
// castor.setDeniedUnmarshallObjects("org.spring.*");
52+
53+
return new RouteBuilder() {
54+
@Override
55+
public void configure() throws Exception {
56+
from("direct:unmarshal").unmarshal(castor).to("mock:unmarshal");
57+
}
58+
};
59+
}
60+
}

components/camel-castor/src/test/resources/org/apache/camel/dataformat/castor/SpringMarshalDomainObjectTest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
2828

2929
<dataFormats>
30-
<castor id="castor" mappingFile="map.xml"/>
30+
<castor id="castor" mappingFile="map.xml" allowedUnmarshallObjects="org.apache.camel.dataformat.castor.Student"/>
3131
</dataFormats>
3232

3333
<route>

0 commit comments

Comments
 (0)