Skip to content

Commit 9905e2a

Browse files
cshannonjbonofre
authored andcommitted
AMQ-9370 - Openwire marshaller should validate Throwable class type
(cherry picked from commit 3eaf310) (cherry picked from commit d0ccdd3)
1 parent 25b2055 commit 9905e2a

18 files changed

+405
-0
lines changed

activemq-client/pom.xml

+11
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,17 @@
261261
</execution>
262262
</executions>
263263
</plugin>
264+
<!-- generate the attached tests jar -->
265+
<plugin>
266+
<artifactId>maven-jar-plugin</artifactId>
267+
<executions>
268+
<execution>
269+
<goals>
270+
<goal>test-jar</goal>
271+
</goals>
272+
</execution>
273+
</executions>
274+
</plugin>
264275
</plugins>
265276
<pluginManagement>
266277
<plugins>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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.activemq.openwire;
18+
19+
public class OpenWireUtil {
20+
21+
/**
22+
* Verify that the provided class extends {@link Throwable} and throw an
23+
* {@link IllegalArgumentException} if it does not.
24+
*
25+
* @param clazz
26+
*/
27+
public static void validateIsThrowable(Class<?> clazz) {
28+
if (!Throwable.class.isAssignableFrom(clazz)) {
29+
throw new IllegalArgumentException("Class " + clazz + " is not assignable to Throwable");
30+
}
31+
}
32+
}

activemq-client/src/main/java/org/apache/activemq/openwire/v1/BaseDataStreamMarshaller.java

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.activemq.openwire.BooleanStream;
2626
import org.apache.activemq.openwire.DataStreamMarshaller;
2727
import org.apache.activemq.openwire.OpenWireFormat;
28+
import org.apache.activemq.openwire.OpenWireUtil;
2829
import org.apache.activemq.util.ByteSequence;
2930

3031
public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller {
@@ -229,8 +230,11 @@ protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput
229230
private Throwable createThrowable(String className, String message) {
230231
try {
231232
Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
233+
OpenWireUtil.validateIsThrowable(clazz);
232234
Constructor constructor = clazz.getConstructor(new Class[] {String.class});
233235
return (Throwable)constructor.newInstance(new Object[] {message});
236+
} catch (IllegalArgumentException e) {
237+
return e;
234238
} catch (Throwable e) {
235239
return new Throwable(className + ": " + message);
236240
}

activemq-client/src/main/java/org/apache/activemq/openwire/v10/BaseDataStreamMarshaller.java

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.activemq.openwire.BooleanStream;
2525
import org.apache.activemq.openwire.DataStreamMarshaller;
2626
import org.apache.activemq.openwire.OpenWireFormat;
27+
import org.apache.activemq.openwire.OpenWireUtil;
2728
import org.apache.activemq.util.ByteSequence;
2829

2930
public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller {
@@ -228,8 +229,11 @@ protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput
228229
private Throwable createThrowable(String className, String message) {
229230
try {
230231
Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
232+
OpenWireUtil.validateIsThrowable(clazz);
231233
Constructor constructor = clazz.getConstructor(new Class[] {String.class});
232234
return (Throwable)constructor.newInstance(new Object[] {message});
235+
} catch (IllegalArgumentException e) {
236+
return e;
233237
} catch (Throwable e) {
234238
return new Throwable(className + ": " + message);
235239
}

activemq-client/src/main/java/org/apache/activemq/openwire/v11/BaseDataStreamMarshaller.java

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.activemq.openwire.BooleanStream;
2525
import org.apache.activemq.openwire.DataStreamMarshaller;
2626
import org.apache.activemq.openwire.OpenWireFormat;
27+
import org.apache.activemq.openwire.OpenWireUtil;
2728
import org.apache.activemq.util.ByteSequence;
2829

2930
public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller {
@@ -227,8 +228,11 @@ protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput
227228
private Throwable createThrowable(String className, String message) {
228229
try {
229230
Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
231+
OpenWireUtil.validateIsThrowable(clazz);
230232
Constructor constructor = clazz.getConstructor(new Class[] {String.class});
231233
return (Throwable)constructor.newInstance(new Object[] {message});
234+
} catch (IllegalArgumentException e) {
235+
return e;
232236
} catch (Throwable e) {
233237
return new Throwable(className + ": " + message);
234238
}

activemq-client/src/main/java/org/apache/activemq/openwire/v12/BaseDataStreamMarshaller.java

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.activemq.openwire.BooleanStream;
2525
import org.apache.activemq.openwire.DataStreamMarshaller;
2626
import org.apache.activemq.openwire.OpenWireFormat;
27+
import org.apache.activemq.openwire.OpenWireUtil;
2728
import org.apache.activemq.util.ByteSequence;
2829

2930
public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller {
@@ -227,8 +228,11 @@ protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput
227228
private Throwable createThrowable(String className, String message) {
228229
try {
229230
Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
231+
OpenWireUtil.validateIsThrowable(clazz);
230232
Constructor constructor = clazz.getConstructor(new Class[] {String.class});
231233
return (Throwable)constructor.newInstance(new Object[] {message});
234+
} catch (IllegalArgumentException e) {
235+
return e;
232236
} catch (Throwable e) {
233237
return new Throwable(className + ": " + message);
234238
}

activemq-client/src/main/java/org/apache/activemq/openwire/v9/BaseDataStreamMarshaller.java

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.activemq.openwire.BooleanStream;
2525
import org.apache.activemq.openwire.DataStreamMarshaller;
2626
import org.apache.activemq.openwire.OpenWireFormat;
27+
import org.apache.activemq.openwire.OpenWireUtil;
2728
import org.apache.activemq.util.ByteSequence;
2829

2930
public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller {
@@ -227,8 +228,11 @@ protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput
227228
private Throwable createThrowable(String className, String message) {
228229
try {
229230
Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
231+
OpenWireUtil.validateIsThrowable(clazz);
230232
Constructor constructor = clazz.getConstructor(new Class[] {String.class});
231233
return (Throwable)constructor.newInstance(new Object[] {message});
234+
} catch (IllegalArgumentException e) {
235+
return e;
232236
} catch (Throwable e) {
233237
return new Throwable(className + ": " + message);
234238
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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.activemq.openwire;
18+
19+
import static org.junit.Assert.assertTrue;
20+
21+
import java.io.DataOutput;
22+
import java.io.IOException;
23+
import java.lang.reflect.Method;
24+
import java.util.ArrayList;
25+
import java.util.Collection;
26+
import java.util.List;
27+
import org.apache.activemq.command.CommandTypes;
28+
import org.apache.activemq.command.ExceptionResponse;
29+
import org.apache.activemq.util.ByteSequence;
30+
import org.junit.Test;
31+
import org.junit.runner.RunWith;
32+
import org.junit.runners.Parameterized;
33+
import org.junit.runners.Parameterized.Parameters;
34+
35+
/**
36+
* Test that Openwire marshalling will validate Throwable types during
37+
* unmarshalling commands that contain a Throwable
38+
*/
39+
@RunWith(Parameterized.class)
40+
public class OpenWireValidationTest {
41+
42+
protected final int version;
43+
44+
@Parameters(name = "version={0}")
45+
public static Collection<Object[]> data() {
46+
List<Integer> versions = List.of(1, 9, 10, 11, 12);
47+
List<Object[]> versionObjs = new ArrayList<>();
48+
for (int i : versions) {
49+
versionObjs.add(new Object[]{i});
50+
}
51+
52+
// Sanity check to make sure the latest generated version is contained in the list
53+
// This will make sure that we don't forget to update this test to include
54+
// any future versions that are generated
55+
assertTrue("List of Openwire versions does not include latest version",
56+
versions.contains((int)CommandTypes.PROTOCOL_VERSION));
57+
58+
return versionObjs;
59+
}
60+
61+
public OpenWireValidationTest(int version) {
62+
this.version = version;
63+
}
64+
65+
@Test
66+
public void testOpenwireThrowableValidation() throws Exception {
67+
// Create a format which will use loose encoding by default
68+
// The code for handling exception creation is shared between both
69+
// tight/loose encoding so only need to test 1
70+
OpenWireFormat format = new OpenWireFormat();
71+
72+
// Override the marshaller map with a custom impl to purposely marshal a class type that is
73+
// not a Throwable for testing the unmarshaller
74+
Class<?> marshallerFactory = getMarshallerFactory();
75+
Method createMarshallerMap = marshallerFactory.getMethod("createMarshallerMap", OpenWireFormat.class);
76+
DataStreamMarshaller[] map = (DataStreamMarshaller[]) createMarshallerMap.invoke(marshallerFactory, format);
77+
map[ExceptionResponse.DATA_STRUCTURE_TYPE] = getExceptionMarshaller();
78+
// This will trigger updating the marshaller from the marshaller map with the right version
79+
format.setVersion(version);
80+
81+
// Build the response and try to unmarshal which should give an IllegalArgumentExeption on unmarshall
82+
// as the test marshaller should have encoded a class type that is not a Throwable
83+
ExceptionResponse r = new ExceptionResponse();
84+
r.setException(new Exception());
85+
ByteSequence bss = format.marshal(r);
86+
ExceptionResponse response = (ExceptionResponse) format.unmarshal(bss);
87+
88+
assertTrue(response.getException() instanceof IllegalArgumentException);
89+
assertTrue(response.getException().getMessage().contains("is not assignable to Throwable"));
90+
}
91+
92+
static class NotAThrowable {
93+
private String message;
94+
95+
public NotAThrowable(String message) {
96+
this.message = message;
97+
}
98+
99+
public NotAThrowable() {
100+
}
101+
}
102+
103+
private Class<?> getMarshallerFactory() throws ClassNotFoundException {
104+
return Class.forName("org.apache.activemq.openwire.v" + version + ".MarshallerFactory");
105+
}
106+
107+
// Create test marshallers for all non-legacy versions that will encode NotAThrowable
108+
// instead of the exception type for testing purposes
109+
protected DataStreamMarshaller getExceptionMarshaller() {
110+
switch (version) {
111+
case 12:
112+
return new org.apache.activemq.openwire.v12.ExceptionResponseMarshaller() {
113+
@Override
114+
protected void looseMarshalThrowable(OpenWireFormat wireFormat, Throwable o,
115+
DataOutput dataOut) throws IOException {
116+
dataOut.writeBoolean(o != null);
117+
looseMarshalString(NotAThrowable.class.getName(), dataOut);
118+
looseMarshalString(o.getMessage(), dataOut);
119+
}
120+
};
121+
case 11:
122+
return new org.apache.activemq.openwire.v11.ExceptionResponseMarshaller() {
123+
@Override
124+
protected void looseMarshalThrowable(OpenWireFormat wireFormat, Throwable o,
125+
DataOutput dataOut) throws IOException {
126+
dataOut.writeBoolean(o != null);
127+
looseMarshalString(NotAThrowable.class.getName(), dataOut);
128+
looseMarshalString(o.getMessage(), dataOut);
129+
}
130+
};
131+
case 10:
132+
return new org.apache.activemq.openwire.v10.ExceptionResponseMarshaller() {
133+
@Override
134+
protected void looseMarshalThrowable(OpenWireFormat wireFormat, Throwable o,
135+
DataOutput dataOut) throws IOException {
136+
dataOut.writeBoolean(o != null);
137+
looseMarshalString(NotAThrowable.class.getName(), dataOut);
138+
looseMarshalString(o.getMessage(), dataOut);
139+
}
140+
};
141+
case 9:
142+
return new org.apache.activemq.openwire.v9.ExceptionResponseMarshaller() {
143+
@Override
144+
protected void looseMarshalThrowable(OpenWireFormat wireFormat, Throwable o,
145+
DataOutput dataOut) throws IOException {
146+
dataOut.writeBoolean(o != null);
147+
looseMarshalString(NotAThrowable.class.getName(), dataOut);
148+
looseMarshalString(o.getMessage(), dataOut);
149+
}
150+
};
151+
case 1:
152+
return new org.apache.activemq.openwire.v1.ExceptionResponseMarshaller() {
153+
@Override
154+
protected void looseMarshalThrowable(OpenWireFormat wireFormat, Throwable o,
155+
DataOutput dataOut) throws IOException {
156+
dataOut.writeBoolean(o != null);
157+
looseMarshalString(NotAThrowable.class.getName(), dataOut);
158+
looseMarshalString(o.getMessage(), dataOut);
159+
}
160+
};
161+
default:
162+
throw new IllegalArgumentException("Unknown openwire version of " + version);
163+
}
164+
}
165+
166+
}

activemq-openwire-legacy/pom.xml

+12
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@
3535
<groupId>org.apache.activemq</groupId>
3636
<artifactId>activemq-client</artifactId>
3737
</dependency>
38+
39+
<dependency>
40+
<groupId>org.apache.activemq</groupId>
41+
<artifactId>activemq-client</artifactId>
42+
<type>test-jar</type>
43+
<scope>test</scope>
44+
</dependency>
45+
<dependency>
46+
<groupId>junit</groupId>
47+
<artifactId>junit</artifactId>
48+
<scope>test</scope>
49+
</dependency>
3850
</dependencies>
3951

4052
</project>

activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v2/BaseDataStreamMarshaller.java

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.activemq.openwire.BooleanStream;
2626
import org.apache.activemq.openwire.DataStreamMarshaller;
2727
import org.apache.activemq.openwire.OpenWireFormat;
28+
import org.apache.activemq.openwire.OpenWireUtil;
2829
import org.apache.activemq.util.ByteSequence;
2930

3031
public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller {
@@ -228,8 +229,11 @@ protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput
228229
private Throwable createThrowable(String className, String message) {
229230
try {
230231
Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
232+
OpenWireUtil.validateIsThrowable(clazz);
231233
Constructor constructor = clazz.getConstructor(new Class[] {String.class});
232234
return (Throwable)constructor.newInstance(new Object[] {message});
235+
} catch (IllegalArgumentException e) {
236+
return e;
233237
} catch (Throwable e) {
234238
return new Throwable(className + ": " + message);
235239
}

activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v3/BaseDataStreamMarshaller.java

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.activemq.openwire.BooleanStream;
2626
import org.apache.activemq.openwire.DataStreamMarshaller;
2727
import org.apache.activemq.openwire.OpenWireFormat;
28+
import org.apache.activemq.openwire.OpenWireUtil;
2829
import org.apache.activemq.util.ByteSequence;
2930

3031
public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller {
@@ -228,8 +229,11 @@ protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput
228229
private Throwable createThrowable(String className, String message) {
229230
try {
230231
Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
232+
OpenWireUtil.validateIsThrowable(clazz);
231233
Constructor constructor = clazz.getConstructor(new Class[] {String.class});
232234
return (Throwable)constructor.newInstance(new Object[] {message});
235+
} catch (IllegalArgumentException e) {
236+
return e;
233237
} catch (Throwable e) {
234238
return new Throwable(className + ": " + message);
235239
}

activemq-openwire-legacy/src/main/java/org/apache/activemq/openwire/v4/BaseDataStreamMarshaller.java

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.activemq.openwire.BooleanStream;
2626
import org.apache.activemq.openwire.DataStreamMarshaller;
2727
import org.apache.activemq.openwire.OpenWireFormat;
28+
import org.apache.activemq.openwire.OpenWireUtil;
2829
import org.apache.activemq.util.ByteSequence;
2930

3031
public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller {
@@ -228,8 +229,11 @@ protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput
228229
private Throwable createThrowable(String className, String message) {
229230
try {
230231
Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
232+
OpenWireUtil.validateIsThrowable(clazz);
231233
Constructor constructor = clazz.getConstructor(new Class[] {String.class});
232234
return (Throwable)constructor.newInstance(new Object[] {message});
235+
} catch (IllegalArgumentException e) {
236+
return e;
233237
} catch (Throwable e) {
234238
return new Throwable(className + ": " + message);
235239
}

0 commit comments

Comments
 (0)