Skip to content

Commit

Permalink
CAMEL-11929: camel-castor - Add more configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
davsclaus committed Oct 20, 2017
1 parent 69a88dc commit 573ebd3
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@
public class CastorDataFormat extends DataFormatDefinition {
@XmlAttribute
private String mappingFile;
@XmlAttribute
@Metadata(defaultValue = "true")
private Boolean whitelistEnabled = true;
@XmlAttribute
private String allowedUnmarshallObjects;
@XmlAttribute
private String deniedUnmarshallObjects;
@XmlAttribute @Metadata(defaultValue = "true")
private Boolean validation;
@XmlAttribute @Metadata(defaultValue = "UTF-8")
Expand Down Expand Up @@ -110,6 +117,45 @@ public void setEncoding(String encoding) {
this.encoding = encoding;
}

/**
* Define if Whitelist feature is enabled or not
*/
public void setWhitelistEnabled(Boolean whitelistEnabled) {
this.whitelistEnabled = whitelistEnabled;
}

public String getAllowedUnmarshallObjects() {
return allowedUnmarshallObjects;
}

/**
* 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.EndpointHelper#matchPattern(String, String)}.
* Denied objects takes precedence over allowed objects.
*/
public void setAllowedUnmarshallObjects(String allowedUnmarshallObjects) {
this.allowedUnmarshallObjects = allowedUnmarshallObjects;
}

public String getDeniedUnmarshallObjects() {
return deniedUnmarshallObjects;
}

/**
* 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.EndpointHelper#matchPattern(String, String)}.
* Denied objects takes precedence over allowed objects.
*/
public void setDeniedUnmarshallObjects(String deniedUnmarshallObjects) {
this.deniedUnmarshallObjects = deniedUnmarshallObjects;
}

@Override
protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) {
if (mappingFile != null) {
Expand All @@ -128,6 +174,15 @@ protected void configureDataFormat(DataFormat dataFormat, CamelContext camelCont
if (classes != null) {
setProperty(camelContext, dataFormat, "classes", classes);
}
if (whitelistEnabled != null) {
setProperty(camelContext, dataFormat, "whitelistEnabled", whitelistEnabled);
}
if (allowedUnmarshallObjects != null) {
setProperty(camelContext, dataFormat, "allowedUnmarshallObjects", allowedUnmarshallObjects);
}
if (deniedUnmarshallObjects != null) {
setProperty(camelContext, dataFormat, "deniedUnmarshallObjects", deniedUnmarshallObjects);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ public class HessianDataFormat extends DataFormatDefinition {
@XmlAttribute
@Metadata(defaultValue = "true")
private Boolean whitelistEnabled = true;

@XmlAttribute
private String allowedUnmarshallObjects;

@XmlAttribute
private String deniedUnmarshallObjects;

Expand Down
7 changes: 5 additions & 2 deletions components/camel-castor/src/main/docs/castor-dataformat.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,17 @@ on multiple routes. You have to set the <castor> element directly in
### Options

// dataformat options: START
The Castor dataformat supports 6 options which are listed below.
The Castor dataformat supports 9 options which are listed below.



[width="100%",cols="2s,1m,1m,6",options="header"]
|===
| Name | Default | Java Type | Description
| mappingFile | | String | Path to a Castor mapping file to load from the classpath.
| whitelistEnabled | true | Boolean | Define if Whitelist feature is enabled or not
| 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.
| 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.
| validation | true | Boolean | Whether validation is turned on or off. Is by default true.
| encoding | UTF-8 | String | Encoding to use when marshalling an Object to XML. Is by default UTF-8
| packages | | String[] | Add additional packages to Castor XmlContext
Expand All @@ -137,4 +140,4 @@ link:download.html[the download page for the latest versions]).
<artifactId>camel-castor</artifactId>
<version>x.x.x</version>
</dependency>
---------------------------------------
---------------------------------------
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.apache.camel.spi.DataFormat;
import org.apache.camel.spi.DataFormatName;
import org.apache.camel.support.ServiceSupport;
import org.apache.camel.util.CollectionStringBuffer;
import org.apache.camel.util.ObjectHelper;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.xml.Marshaller;
Expand Down Expand Up @@ -57,6 +58,9 @@ public abstract class AbstractCastorDataFormat extends ServiceSupport implements
private boolean validation;
private volatile XMLContext xmlContext;
private boolean contentTypeHeader = true;
private boolean whitlistEnabled = true;
private String allowedUnmarshallObjects;
private String deniedUnmarshallObjects;

public AbstractCastorDataFormat() {
}
Expand Down Expand Up @@ -129,6 +133,12 @@ public Unmarshaller createUnmarshaller(Exchange exchange) throws Exception {
// need to create new marshaller as we may have concurrent processing
Unmarshaller answer = xmlContext.createUnmarshaller();
answer.setValidation(isValidation());
if (whitlistEnabled) {
WhitelistObjectFactory factory = new WhitelistObjectFactory();
factory.setAllowClasses(allowedUnmarshallObjects);
factory.setDenyClasses(deniedUnmarshallObjects);
answer.setObjectFactory(factory);
}
return answer;
}

Expand Down Expand Up @@ -183,7 +193,6 @@ public void setValidation(boolean validation) {
this.validation = validation;
}


public boolean isContentTypeHeader() {
return contentTypeHeader;
}
Expand All @@ -195,6 +204,38 @@ public void setContentTypeHeader(boolean contentTypeHeader) {
this.contentTypeHeader = contentTypeHeader;
}

public boolean isWhitlistEnabled() {
return whitlistEnabled;
}

public void setWhitlistEnabled(boolean whitlistEnabled) {
this.whitlistEnabled = whitlistEnabled;
}

public String getAllowedUnmarshallObjects() {
return allowedUnmarshallObjects;
}

public void setAllowedUnmarshallObjects(String allowedUnmarshallObjects) {
this.allowedUnmarshallObjects = allowedUnmarshallObjects;
}

public void setAllowClasses(Class... allowClasses) {
CollectionStringBuffer csb = new CollectionStringBuffer(",");
for (Class clazz : allowClasses) {
csb.append(clazz.getName());
}
this.allowedUnmarshallObjects = csb.toString();
}

public String getDeniedUnmarshallObjects() {
return deniedUnmarshallObjects;
}

public void setDeniedUnmarshallObjects(String deniedUnmarshallObjects) {
this.deniedUnmarshallObjects = deniedUnmarshallObjects;
}

@Override
protected void doStart() throws Exception {
if (xmlContext == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* 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.dataformat.castor;

import org.apache.camel.util.EndpointHelper;
import org.exolab.castor.util.DefaultObjectFactory;

public class WhitelistObjectFactory extends DefaultObjectFactory {

private String allowClasses;
private String denyClasses;

public String getAllowClasses() {
return allowClasses;
}

public void setAllowClasses(String allowClasses) {
this.allowClasses = allowClasses;
}

public String getDenyClasses() {
return denyClasses;
}

public void setDenyClasses(String denyClasses) {
this.denyClasses = denyClasses;
}

@Override
public Object createInstance(Class type) throws IllegalAccessException, InstantiationException {
if (allowCreate(type)) {
return super.createInstance(type);
} else {
throw new IllegalAccessException("Not allowed to create class of type: " + type);
}
}

@Override
public Object createInstance(Class type, Object[] args) throws IllegalAccessException, InstantiationException {
if (allowCreate(type)) {
return super.createInstance(type, args);
} else {
throw new IllegalAccessException("Not allowed to create class of type: " + type);
}
}

@Override
public Object createInstance(Class type, Class[] argTypes, Object[] args) throws IllegalAccessException, InstantiationException {
if (allowCreate(type)) {
return super.createInstance(type, argTypes, args);
} else {
throw new IllegalAccessException("Not allowed to create class of type: " + type);
}
}

private boolean allowCreate(Class type) {
String name = type.getName();

// deny takes precedence
if (denyClasses != null) {
String[] arr = denyClasses.split(",");
for (String key : arr) {
if (EndpointHelper.matchPattern(name, key)) {
return false;
}
}
}

// deny takes precedence
if (allowClasses != null) {
String[] arr = allowClasses.split(",");
for (String key : arr) {
if (EndpointHelper.matchPattern(name, key)) {
return true;
}
}
}

// deny by default
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ public void configure() throws Exception {

CastorDataFormat myformat = new CastorDataFormat();
myformat.setMappingFile("map.xml");

myformat.setValidation(true);
myformat.setAllowClasses(Student.class);

from("direct:marshal").marshal(myformat).to("mock:marshal");
from("direct:unmarshal").unmarshal(myformat).to("mock:unmarshal");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* 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.dataformat.castor;

import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;

public class WhitelistTest extends CamelTestSupport {

@Test
public void testDeny() throws Exception {
final String stuff = "<x xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:java=\"http://java.sun.com\""
+ " xsi:type=\"java:org.springframework.beans.factory.config.PropertyPathFactoryBean\">"
+ "<target-bean-name>ldap://localhost:1389/obj</target-bean-name><property-path>foo</property-path>"
+ "<bean-factory xsi:type=\"java:org.springframework.jndi.support.SimpleJndiBeanFactory\">"
+ "<shareable-resource>ldap://localhost:1389/obj</shareable-resource></bean-factory></x>";

try {
template.sendBody("direct:unmarshal", stuff);
fail("Should throw an error");
} catch (Exception e) {
IllegalAccessException iae = assertIsInstanceOf(IllegalAccessException.class, e.getCause().getCause());
assertNotNull(iae);
assertTrue(iae.getMessage().startsWith("Not allowed to create class of type: class org.springframework.beans.factory.config.PropertyPathFactoryBean"));
}
}

@Override
protected RoutesBuilder createRouteBuilder() throws Exception {
CastorDataFormat castor = new CastorDataFormat();
// note that whitelist is enabled by default
// castor.setWhitlistEnabled(true);
// and that everything is denied by default
// so you would need to configure allow to enable safe classes to be loaded
// castor.setDeniedUnmarshallObjects("org.spring.*");

return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:unmarshal").unmarshal(castor).to("mock:unmarshal");
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">

<dataFormats>
<castor id="castor" mappingFile="map.xml"/>
<castor id="castor" mappingFile="map.xml" allowedUnmarshallObjects="org.apache.camel.dataformat.castor.Student"/>
</dataFormats>

<route>
Expand Down
Loading

0 comments on commit 573ebd3

Please sign in to comment.