CVE-2017-5641
Description
Previous versions of Apache Flex BlazeDS (4.7.2 and earlier) did not restrict which types were allowed for AMF(X) object deserialization by default. During the deserialization process code is executed that for several known types has undesired side-effects. Other, unknown types may also exhibit such behaviors. One vector in the Java standard library exists that allows an attacker to trigger possibly further exploitable Java deserialization of untrusted data. Other known vectors in third party libraries can be used to trigger remote code execution.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.flex.blazeds:flex-messaging-coreMaven | < 4.7.3 | 4.7.3 |
org.apache.flex.blazeds:flex-messaging-remotingMaven | < 4.7.3 | 4.7.3 |
Affected products
3- cpe:2.3:a:hp:xp_command_view_advanced_edition:*:*:*:*:*:*:*:*Range: <8.5.3-00
- Apache Software Foundation/Apache Flex Blaze DSv5Range: before 4.7.3
Patches
211b0aa132d9a- Moved the initialization of the ClassDeserializationValidator into the SerializationContext (so it is always initialized).
12 files changed · +626 −964
core/src/main/java/flex/messaging/config/FlexConfigurationManager.java+10 −10 modified@@ -44,11 +44,11 @@ */ public class FlexConfigurationManager implements ConfigurationManager { - static final String DEFAULT_CONFIG_PATH = "/WEB-INF/flex/services-config.xml"; + private static final String DEFAULT_CONFIG_PATH = "/WEB-INF/flex/services-config.xml"; - protected String configurationPath = null; - protected ConfigurationFileResolver configurationResolver = null; - protected ConfigurationParser parser = null; + private String configurationPath = null; + private ConfigurationFileResolver configurationResolver = null; + private ConfigurationParser parser = null; public MessagingConfiguration getMessagingConfiguration(ServletConfig servletConfig) { @@ -88,10 +88,10 @@ public void reportTokens() parser.reportTokens(); } - protected ConfigurationParser getConfigurationParser(ServletConfig servletConfig) + private ConfigurationParser getConfigurationParser(ServletConfig servletConfig) { ConfigurationParser parser = null; - Class parserClass = null; + Class parserClass; String className = null; // Check for Custom Parser Specification @@ -175,7 +175,7 @@ protected ConfigurationParser getConfigurationParser(ServletConfig servletConfig * * @param servletConfig configuration */ - protected void setupConfigurationPathAndResolver(ServletConfig servletConfig) + private void setupConfigurationPathAndResolver(ServletConfig servletConfig) { if (servletConfig != null) { @@ -229,7 +229,7 @@ protected void setupConfigurationPathAndResolver(ServletConfig servletConfig) } - protected void verifyMinimumJavaVersion() throws ConfigurationException + private void verifyMinimumJavaVersion() throws ConfigurationException { try { @@ -262,7 +262,7 @@ else if (second == 4) } else if (third == 2) { - if ((vendor != null) && (vendor.indexOf("Sun") != -1)) + if ((vendor != null) && vendor.contains("Sun")) { // test at least 1.4.2_06 on Sun int fourth = Integer.parseInt(split[3]); @@ -284,7 +284,7 @@ else if (third == 2) { ConfigurationException cx = new ConfigurationException(); - if ((vendor != null) && (vendor.indexOf("Sun") != -1)) + if ((vendor != null) && vendor.contains("Sun")) { // The minimum required Java version was not found. Please install JDK 1.4.2_06 or above. Current version is XX. cx.setMessage(10139, new Object[] { System.getProperty("java.version")});
core/src/main/java/flex/messaging/config/MessagingConfiguration.java+0 −8 modified@@ -591,14 +591,6 @@ private void createValidators(MessageBroker broker) // Only set the DeserializationValidator types for now. if (validator instanceof DeserializationValidator) { - // there can only be one deserialization validator, throw an error if there is more than one. - DeserializationValidator existingValidator = broker.getDeserializationValidator(); - if (existingValidator != null) - { - ConfigurationException cx = new ConfigurationException(); - cx.setMessage(11400, new Object[]{existingValidator.getClass().getCanonicalName(), className}); - throw cx; - } DeserializationValidator deserializationValidator = (DeserializationValidator)validator; deserializationValidator.initialize(null, settings.getProperties()); broker.setDeserializationValidator(deserializationValidator);
core/src/main/java/flex/messaging/config/ServerConfigurationParser.java+0 −14 modified@@ -1867,8 +1867,6 @@ private void validators(Node root) { Node validatorsNode = selectSingleNode(root, VALIDATORS_ELEMENT); if (validatorsNode == null) { - // Default to the ClassDeserializationValidator - defaultValidator(); return; } @@ -1882,21 +1880,9 @@ private void validators(Node root) Node validator = validators.item(i); validator(validator); } - } else { - // Default to the ClassDeserializationValidator - defaultValidator(); } } - /** - * Initialize a efault validator that protects BlazeDS against the most obvious attacks. - */ - private void defaultValidator() { - ValidatorSettings validatorSettings = new ValidatorSettings(); - validatorSettings.setClassName(ClassDeserializationValidator.class.getName()); - ((MessagingConfiguration)config).addValidatorSettings(validatorSettings); - } - private void validator(Node validator) { // Validation
core/src/main/java/flex/messaging/io/SerializationContext.java+38 −59 modified@@ -26,8 +26,7 @@ * A simple context to get settings from an endpoint to a deserializer * or serializer. */ -public class SerializationContext implements Serializable, Cloneable -{ +public class SerializationContext implements Serializable, Cloneable { static final long serialVersionUID = -3020985035377116475L; // Endpoint serialization configuration flags @@ -54,7 +53,7 @@ public class SerializationContext implements Serializable, Cloneable * Provides a way to control whether small messages should be sent even * if the client can support them. If set to false, small messages * will not be sent. - * + * <p> * The default is true. */ public boolean enableSmallMessages = true; @@ -63,10 +62,10 @@ public class SerializationContext implements Serializable, Cloneable * Determines whether type information will be used to instantiate a new instance. * If set to false, types will be deserialized as flex.messaging.io.ASObject instances * with type information retained but not used to create an instance. - * + * <p> * Note that types in the flex.* package (and any subpackage) will always be * instantiated. - * + * <p> * The default is true. */ public boolean instantiateTypes = true; @@ -76,7 +75,7 @@ public class SerializationContext implements Serializable, Cloneable // How deep level of nest object in the object graph that we support public int maxObjectNestLevel = 512; - + // How deep level of nest collection objects in the object graph that we support // Similarly like how many dimensional matrix that we support for serialization. public int maxCollectionNestLevel = 15; @@ -99,17 +98,17 @@ public class SerializationContext implements Serializable, Cloneable /** * The default constructor. */ - public SerializationContext() - { + public SerializationContext() { + // Initialize the default validator. + deserializationValidator = new ClassDeserializationValidator(); } /** * Returns the deserializer class. * * @return The deserializer class. */ - public Class getDeserializerClass() - { + public Class getDeserializerClass() { return deserializer; } @@ -118,8 +117,7 @@ public Class getDeserializerClass() * * @param c The deserializer class. */ - public void setDeserializerClass(Class c) - { + public void setDeserializerClass(Class c) { deserializer = c; } @@ -128,8 +126,7 @@ public void setDeserializerClass(Class c) * * @return The serializer class. */ - public Class getSerializerClass() - { + public Class getSerializerClass() { return serializer; } @@ -138,8 +135,7 @@ public Class getSerializerClass() * * @param c The serializer class. */ - public void setSerializerClass(Class c) - { + public void setSerializerClass(Class c) { serializer = c; } @@ -148,42 +144,35 @@ public void setSerializerClass(Class c) * * @return A new message deserializer instance. */ - public MessageDeserializer newMessageDeserializer() - { + public MessageDeserializer newMessageDeserializer() { Class deserializerClass = getDeserializerClass(); - if (deserializerClass == null) - { + if (deserializerClass == null) { deserializerClass = ClassUtil.createClass("flex.messaging.io.amf.AmfMessageDeserializer"); this.setDeserializerClass(deserializerClass); } - MessageDeserializer deserializer = (MessageDeserializer)ClassUtil.createDefaultInstance(deserializerClass, MessageDeserializer.class); - return deserializer; + return (MessageDeserializer) ClassUtil.createDefaultInstance(deserializerClass, MessageDeserializer.class); } /** * Instantiates a new message serializer. * * @return A new message serializer instance. */ - public MessageSerializer newMessageSerializer() - { + public MessageSerializer newMessageSerializer() { Class serializerClass = getSerializerClass(); - if (serializerClass == null) - { + if (serializerClass == null) { serializerClass = ClassUtil.createClass("flex.messaging.io.amf.AmfMessageSerializer"); this.setSerializerClass(serializerClass); } - MessageSerializer serializer = (MessageSerializer)ClassUtil.createDefaultInstance(serializerClass, MessageSerializer.class); - return serializer; + return (MessageSerializer) ClassUtil.createDefaultInstance(serializerClass, MessageSerializer.class); } /** * Returns the deserialization validator. * * @return The deserialization validator. */ - public DeserializationValidator getDeserializationValidator() - { + public DeserializationValidator getDeserializationValidator() { return deserializationValidator; } @@ -192,20 +181,15 @@ public DeserializationValidator getDeserializationValidator() * * @param deserializationValidator The deserialization validator. */ - public void setDeserializationValidator(DeserializationValidator deserializationValidator) - { + public void setDeserializationValidator(DeserializationValidator deserializationValidator) { this.deserializationValidator = deserializationValidator; } @Override - public Object clone() - { - try - { + public Object clone() { + try { return super.clone(); - } - catch (CloneNotSupportedException e) - { + } catch (CloneNotSupportedException e) { // this should never happen since this class extends object // but just in case revert to manual clone SerializationContext context = new SerializationContext(); @@ -244,57 +228,52 @@ public Object clone() /** * Establishes a SerializationContext for the current thread. * Users are not expected to call this function. + * * @param context The current SerializationContext. */ - public static void setSerializationContext(SerializationContext context) - { - if (context == null) + public static void setSerializationContext(SerializationContext context) { + if (context == null) { contexts.remove(); - else + } else { contexts.set(context); + } } /** * @return The current thread's SerializationContext. */ - public static SerializationContext getSerializationContext() - { + public static SerializationContext getSerializationContext() { SerializationContext sc = contexts.get(); - if (sc == null) - { + if (sc == null) { sc = new SerializationContext(); SerializationContext.setSerializationContext(sc); } return sc; } + /** * Clears out the thread local state after the request completes. */ - public static void clearThreadLocalObjects() - { - if (contexts != null) - { + public static void clearThreadLocalObjects() { + if (contexts != null) { contexts.remove(); } } /** - * * Create thread local storage. */ - public static void createThreadLocalObjects() - { - if (contexts == null) - contexts = new ThreadLocal(); + public static void createThreadLocalObjects() { + if (contexts == null) { + contexts = new ThreadLocal<SerializationContext>(); + } } /** - * * Destroy thread local storage. * Call ONLY on shutdown. */ - public static void releaseThreadLocalObjects() - { + public static void releaseThreadLocalObjects() { clearThreadLocalObjects(); contexts = null;
core/src/main/java/flex/messaging/MessageBroker.java+3 −0 modified@@ -186,6 +186,9 @@ public MessageBroker(boolean enableManagement, String mbid, ClassLoader loader) factories = new HashMap<String, FlexFactory>(); registeredEndpoints = new HashMap<String, String>(); + // Initialize the default validator. + deserializationValidator = new ClassDeserializationValidator(); + // Add the built-in java factory addFactory("java", new JavaFactory());
core/src/main/java/flex/messaging/validators/ClassDeserializationValidator.java+40 −26 modified@@ -40,19 +40,21 @@ public class ClassDeserializationValidator implements DeserializationValidator { public static final String PROPERTY_NAME_ATTR = "name"; private static final String[] DEFAULT_ALLOW_CLASSES = { + "flex.messaging.io.amf.ASObject", "flex.messaging.io.amf.SerializedObject", "flex.messaging.io.ArrayCollection", - "flex.messaging.io.ObjectProxy", - "flex.messaging.io.SerializationProxy", + "flex.messaging.io.ArrayList", + "flex.messaging.messages.AcknowledgeMessage", "flex.messaging.messages.AcknowledgeMessageExt", + "flex.messaging.messages.AsyncMessage", "flex.messaging.messages.AsyncMessageExt", + "flex.messaging.messages.CommandMessage", "flex.messaging.messages.CommandMessageExt", - "flex.data.messages.DataMessageExt", - "flex.data.messages.ManagedRemotingMessageExt", - "flex.data.messages.PagedMessageExt", - "flex.data.messages.SequencedMessageExt", - "flex.data.messages.UpdateCollectionMessageExt", - "flex.data.ChangedItems", + "flex.messaging.messages.ErrorMessage", + "flex.messaging.messages.HTTPMessage", + "flex.messaging.messages.RemotingMessage", + "flex.messaging.messages.SOAPMessage", + "java.io.Externalizable", "java.lang.Boolean", "java.lang.Byte", "java.lang.Character", @@ -63,8 +65,9 @@ public class ClassDeserializationValidator implements DeserializationValidator { "java.lang.Object", "java.lang.Short", "java.lang.String", - "java.io.Externalizable", + "java.util.ArrayList", "java.util.Date", + "java.util.HashMap", "org.w3c.dom.Document", "\\[B", "\\[Ljava.lang.Object;" @@ -94,6 +97,10 @@ public class ClassDeserializationValidator implements DeserializationValidator { private Map<String, Pattern> disallowClassPatterns; public ClassDeserializationValidator() { + // Apply default allow classes + for (String defaultAllowClassPattern : DEFAULT_ALLOW_CLASSES) { + addAllowClassPattern(defaultAllowClassPattern); + } } @@ -110,8 +117,9 @@ public ClassDeserializationValidator() { */ public void addAllowClassPattern(String classNamePattern) { synchronized (lock) { - if (allowClassPatterns == null) + if (allowClassPatterns == null) { allowClassPatterns = new HashMap<String, Pattern>(); + } allowClassPatterns.put(classNamePattern, Pattern.compile(classNamePattern)); @@ -126,8 +134,9 @@ public void addAllowClassPattern(String classNamePattern) { */ public void removeAllowClassPattern(String classNamePattern) { synchronized (lock) { - if (allowClassPatterns != null) + if (allowClassPatterns != null) { allowClassPatterns.remove(classNamePattern); + } clearClassCache(); } @@ -140,8 +149,9 @@ public void removeAllowClassPattern(String classNamePattern) { */ public void addDisallowClassPattern(String classNamePattern) { synchronized (lock) { - if (disallowClassPatterns == null) + if (disallowClassPatterns == null) { disallowClassPatterns = new HashMap<String, Pattern>(); + } disallowClassPatterns.put(classNamePattern, Pattern.compile(classNamePattern)); @@ -156,8 +166,9 @@ public void addDisallowClassPattern(String classNamePattern) { */ public void removeDisallowClassPattern(String classNamePattern) { synchronized (lock) { - if (disallowClassPatterns != null) + if (disallowClassPatterns != null) { disallowClassPatterns.remove(classNamePattern); + } clearClassCache(); } @@ -201,16 +212,19 @@ public boolean validateAssignment(Object instance, String propertyName, Object v */ public boolean validateCreation(Class<?> c) { String className = c == null ? null : c.getName(); - if (className == null) + if (className == null) { return true; + } // First, check against the encountered disallow-classes list. - if (disallowClasses != null && disallowClasses.contains(className)) + if (disallowClasses != null && disallowClasses.contains(className)) { return false; + } // Then, check against the encountered allow-classes list. - if (allowClasses != null && allowClasses.contains(className)) + if (allowClasses != null && allowClasses.contains(className)) { return true; + } // Otherwise, the class was encountered for the first time, need to // go through the disallow and allow class patterns list. @@ -247,13 +261,9 @@ public boolean validateCreation(Class<?> c) { * {@inheritDoc} */ public void initialize(String id, ConfigMap properties) { - // Apply default allow classes - for (String defaultAllowClassPattern : DEFAULT_ALLOW_CLASSES) { - addAllowClassPattern(defaultAllowClassPattern); - } - - if (properties == null || properties.size() == 0) + if (properties == null || properties.size() == 0) { return; + } // Process allow-classes. ConfigMap allowedClassesMap = properties.getPropertyAsMap(PROPERTY_ALLOW_CLASSES, null); @@ -288,21 +298,25 @@ public void initialize(String id, ConfigMap properties) { protected void addAllowClass(String className) { synchronized (lock) { - if (allowClasses == null) + if (allowClasses == null) { allowClasses = new HashSet<String>(); + } - if (!allowClasses.contains(className)) + if (!allowClasses.contains(className)) { allowClasses.add(className); + } } } protected void addDisallowClass(String className) { synchronized (lock) { - if (disallowClasses == null) + if (disallowClasses == null) { disallowClasses = new HashSet<String>(); + } - if (!disallowClasses.contains(className)) + if (!disallowClasses.contains(className)) { disallowClasses.add(className); + } } }
core/src/test/java/flex/messaging/io/amf/validators/AmfDeserializationValidatorTest.java+1 −1 modified@@ -95,7 +95,7 @@ private void deserializateRequest(DeserializationValidator validator) URL resource = ClassLoader.getSystemResource(sample); URI uri = new URI(resource.toString()); File testData = new File(uri.getPath()); - String testDataLocation = testData.getCanonicalPath(); + String testDataLocation = testData.getCanonicalPath(); // Generate sample AMF request from the data file. PipedOutputStream pout = new PipedOutputStream();
core/src/test/java/flex/messaging/io/amfx/AmfxSerializationTest.java+4 −0 modified@@ -16,6 +16,7 @@ */ package flex.messaging.io.amfx; +import flex.messaging.validators.ClassDeserializationValidator; import junit.framework.TestCase; import junit.framework.Test; import junit.framework.TestSuite; @@ -69,7 +70,10 @@ public static Test suite() protected void setUp() throws Exception { super.setUp(); + ClassDeserializationValidator classDeserializationValidator = new ClassDeserializationValidator(); + classDeserializationValidator.addAllowClassPattern("flex.messaging.io.amfx.testtypes.*"); serializationContext = new SerializationContext(); + serializationContext.setDeserializationValidator(classDeserializationValidator); SerializationContext.setSerializationContext(serializationContext); //trace = new AmfTrace(); }
remoting/src/main/java/flex/messaging/services/RemotingService.java+3 −1 modified@@ -164,10 +164,12 @@ public Object serviceMessage(Message msg) { RemotingMessage message = (RemotingMessage)msg; RemotingDestination destination = (RemotingDestination)getDestination(msg); - RemotingDestinationControl destinationControl = (destination.isManaged()) ? (RemotingDestinationControl)destination.getControl() : null; if (destination != null) { + RemotingDestinationControl destinationControl = (destination.isManaged()) ? + (RemotingDestinationControl) destination.getControl() : null; + ServiceAdapter adapter = destination.getAdapter(); long startTime = 0; if (destinationControl != null)
remoting/src/test/java/flex/messaging/io/amf/client/AMFConnectionIT.java+262 −444 modified@@ -17,35 +17,33 @@ package flex.messaging.io.amf.client; -import java.net.HttpURLConnection; -import java.net.InetSocketAddress; -import java.net.Proxy; - -import flex.messaging.util.TestServerWrapper; -import junit.extensions.TestSetup; -import org.junit.Assert; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import remoting.amfclient.ClientCustomType; - import flex.messaging.MessageException; -import flex.messaging.messages.RemotingMessage; +import flex.messaging.io.MessageIOConstants; +import flex.messaging.io.SerializationContext; import flex.messaging.io.amf.ASObject; import flex.messaging.io.amf.AmfTrace; import flex.messaging.io.amf.client.AMFConnection.HttpResponseInfo; import flex.messaging.io.amf.client.exceptions.ClientStatusException; import flex.messaging.io.amf.client.exceptions.ServerStatusException; -import flex.messaging.io.MessageIOConstants; +import flex.messaging.messages.RemotingMessage; +import flex.messaging.util.TestServerWrapper; +import flex.messaging.validators.ClassDeserializationValidator; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import remoting.amfclient.ClientCustomType; + +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.Proxy; /** * JUnit tests for AMFConnection. Note that most of the tests require a running * server with the specified destination. */ -public class AMFConnectionIT extends TestCase -{ +public class AMFConnectionIT { private static final String DEFAULT_DESTINATION_ID = "amfConnectionTestService"; private static final String DEFAULT_METHOD_NAME = "echoString"; private static final String DEFAULT_METHOD_ARG = "echo me"; @@ -57,385 +55,261 @@ public class AMFConnectionIT extends TestCase private static TestServerWrapper serverWrapper; private static int serverPort; + private static SerializationContext serializationContext; - /** - * Given a remote method name, returns the AMF connection call needed using - * the default destination id. - */ - private static String getOperationCall(String method) - { - return DEFAULT_DESTINATION_ID + "." + method; - } + @BeforeClass + public static void setup() { + serverWrapper = new TestServerWrapper(); + serverPort = serverWrapper.startServer("classpath:/WEB-INF/flex/services-config.xml"); + if (serverPort == -1) { + Assert.fail("Couldn't start server process"); + } - protected String getConnectionUrl() { - return String.format(DEFAULT_URL, serverPort); - } + AMFConnection.registerAlias( + "remoting.amfclient.ServerCustomType" /* server type */, + "remoting.amfclient.ClientCustomType" /* client type */); + serializationContext = SerializationContext.getSerializationContext(); + ClassDeserializationValidator deserializationValidator = + (ClassDeserializationValidator) serializationContext.getDeserializationValidator(); + deserializationValidator.addAllowClassPattern("remoting.amfclient.*"); + } - public AMFConnectionIT(String name) - { - super(name); - } - - public static Test suite() - { - //TestSuite suite = new TestSuite(AMFConnectionIT.class); - TestSuite suite = new TestSuite(); - suite.addTest(new AMFConnectionIT("testConnect")); - suite.addTest(new AMFConnectionIT("testConnectAndClose")); - suite.addTest(new AMFConnectionIT("testConnectBadUrl")); - suite.addTest(new AMFConnectionIT("testCallMultipleTimes")); - suite.addTest(new AMFConnectionIT("testCallNoConnect")); - suite.addTest(new AMFConnectionIT("testCallNoConnectStringMsg")); - suite.addTest(new AMFConnectionIT("testCallUnreachableConnectUrl")); - suite.addTest(new AMFConnectionIT("testCallNonexistantMethod")); - suite.addTest(new AMFConnectionIT("testHttpResponseInfoWithNonexistantMethod")); - suite.addTest(new AMFConnectionIT("testCloseNoConnect")); - suite.addTest(new AMFConnectionIT("testSetGetObjectEncoding")); - suite.addTest(new AMFConnectionIT("testSetGetDefaultObjectEncoding")); - suite.addTest(new AMFConnectionIT("testSetGetAMFHeaderProcessor")); - suite.addTest(new AMFConnectionIT("testAddRemoveAMFHeaderTwoParam")); - suite.addTest(new AMFConnectionIT("testAddRemoveAMFHeader")); - suite.addTest(new AMFConnectionIT("testAddRemoveAllAMFHeaders")); - suite.addTest(new AMFConnectionIT("testAddRemoveHTTPRequestHeader")); - suite.addTest(new AMFConnectionIT("testAddRemoveAllHTTPRequestHeaders")); - suite.addTest(new AMFConnectionIT("testRemoveAMFHeader")); - suite.addTest(new AMFConnectionIT("testRemoveAllAMFHeaders")); - suite.addTest(new AMFConnectionIT("testRemoveHTTPRequestHeader")); - suite.addTest(new AMFConnectionIT("testRemoveAllHTTPRequestHeaders")); - suite.addTest(new AMFConnectionIT("testInstantiateTypes")); - suite.addTest(new AMFConnectionIT("testSetGetAMFTrace")); - suite.addTest(new AMFConnectionIT("testHTTPProxy")); - - return new TestSetup(suite) { - protected void setUp() throws Exception { - serverWrapper = new TestServerWrapper(); - serverPort = serverWrapper.startServer("classpath:/WEB-INF/flex/services-config.xml"); - if(serverPort == -1) { - Assert.fail("Couldn't start server process"); - } - AMFConnection.registerAlias( - "remoting.amfclient.ServerCustomType" /* server type */, - "remoting.amfclient.ClientCustomType" /* client type */); - } - protected void tearDown() throws Exception { - serverWrapper.stopServer(); - serverWrapper = null; - } - }; + @AfterClass + public static void teardown() { + serverWrapper.stopServer(); + serverWrapper = null; } // Not a test, just an example to show how to use AMFConnection. - public void example() - { + public void example() { // Create the AMF connection. AMFConnection amfConnection = new AMFConnection(); // Connect to the remote url. - try - { - amfConnection.connect(getConnectionUrl()); - } - catch (ClientStatusException cse) - { + try { + amfConnection.connect(getConnectionUrl(), serializationContext); + } catch (ClientStatusException cse) { return; } // Make a remoting call and retrieve the result. - try - { + try { Object result = amfConnection.call(DEFAULT_AMF_OPERATION, DEFAULT_METHOD_ARG); Assert.assertEquals(DEFAULT_METHOD_ARG, result); - } - catch (ClientStatusException cse) - { + } catch (ClientStatusException cse) { // Ignore. - } - catch (ServerStatusException sse) - { + } catch (ServerStatusException sse) { // Ignore. } // Close the connection. amfConnection.close(); } - public void testConnect() - { + @Test + public void testConnect() { AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testConnectAndClose() - { + @Test + public void testConnectAndClose() { AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); Assert.assertEquals(null, amfConnection.getUrl()); } } - public void testConnectBadUrl() - { + @Test + public void testConnectBadUrl() { String badUrl = "badUrl"; AMFConnection amfConnection = new AMFConnection(); - try - { + try { amfConnection.connect(badUrl); - fail("ClientStatusException expected"); - } - catch (ClientStatusException cse) - { + Assert.fail("ClientStatusException expected"); + } catch (ClientStatusException cse) { Assert.assertEquals(ClientStatusException.AMF_CONNECT_FAILED_CODE, cse.getCode()); - } - finally - { + } finally { amfConnection.close(); } } - public void testCallMultipleTimes() - { + @Test + public void testCallMultipleTimes() { AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); } // Make a remoting call and retrieve the result. - try - { - for (int i = 1; i < 4; i++) - { + try { + for (int i = 1; i < 4; i++) { String stringToEcho = DEFAULT_METHOD_ARG + i; Object result = amfConnection.call(DEFAULT_AMF_OPERATION, stringToEcho); Assert.assertEquals(stringToEcho, result); } - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); - } - finally - { + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); + } finally { amfConnection.close(); } } - public void testCallNoConnect() - { + @Test + public void testCallNoConnect() { AMFConnection amfConnection = new AMFConnection(); // Make a remoting call without connect. - try - { + try { Object result = amfConnection.call(DEFAULT_AMF_OPERATION, DEFAULT_METHOD_ARG); Assert.assertEquals(DEFAULT_METHOD_ARG, result); - } - catch (ClientStatusException cse) - { + } catch (ClientStatusException cse) { Assert.assertEquals(ClientStatusException.AMF_CALL_FAILED_CODE, cse.getCode()); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); - } - finally - { + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); + } finally { amfConnection.close(); } } - public void testCallNoConnectStringMsg() - { + @Test + public void testCallNoConnectStringMsg() { AMFConnection amfConnection = new AMFConnection(); // Make a remoting call without connect. - try - { + try { Object result = amfConnection.call(DEFAULT_AMF_OPERATION, DEFAULT_METHOD_ARG); Assert.assertEquals(DEFAULT_METHOD_ARG, result); - } - catch (ClientStatusException cse) - { + } catch (ClientStatusException cse) { Assert.assertEquals(ClientStatusException.AMF_CALL_FAILED_CODE, cse.getCode()); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); - } - finally - { + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); + } finally { amfConnection.close(); } } - public void testCallUnreachableConnectUrl() - { + @Test + public void testCallUnreachableConnectUrl() { String unreachableUrl = "http://localhost:8400/team/messagebroker/unreachable"; AMFConnection amfConnection = new AMFConnection(); - try - { + try { // Connect does not actually connect but simply sets the url. amfConnection.connect(unreachableUrl); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); } // Make a remoting call and retrieve the result. - try - { + try { Object result = amfConnection.call(DEFAULT_AMF_OPERATION, DEFAULT_METHOD_ARG); Assert.assertEquals(DEFAULT_METHOD_ARG, result); - } - catch (ClientStatusException cse) - { + } catch (ClientStatusException cse) { Assert.assertEquals(ClientStatusException.AMF_CALL_FAILED_CODE, cse.getCode()); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); - } - finally - { + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); + } finally { amfConnection.close(); } } - public void testCallNonexistantMethod() - { + @Test + public void testCallNonexistantMethod() { String method = "nonExistantMethod"; - try - { - internalTestCall(getOperationCall(method), "Wombat", new CallResultHandler(){ - public void onResult(Object result) - { - fail("Unexcepted result: " + result); + try { + internalTestCall(getOperationCall(method), "Wombat", new CallResultHandler() { + public void onResult(Object result) { + Assert.fail("Unexcepted result: " + result); } }); - } - catch (ServerStatusException sse) - { - ASObject status = (ASObject)sse.getData(); - String code = (String)status.get("code"); + } catch (ServerStatusException sse) { + ASObject status = (ASObject) sse.getData(); + String code = (String) status.get("code"); Assert.assertEquals(MessageException.CODE_SERVER_RESOURCE_UNAVAILABLE, code); HttpResponseInfo info = sse.getHttpResponseInfo(); // AMF status messages are reported as HTTP_OK still. Assert.assertEquals(HttpURLConnection.HTTP_OK, info.getResponseCode()); Assert.assertEquals("OK", info.getResponseMessage()); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testHttpResponseInfoWithNonexistantMethod() - { + @Test + public void testHttpResponseInfoWithNonexistantMethod() { String method = "nonExistantMethod"; final ClientCustomType methodArg = new ClientCustomType(); methodArg.setId(1); - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - fail("Unexcepted result: " + result); + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + Assert.fail("Unexcepted result: " + result); } }); - } - catch (ServerStatusException sse) - { + } catch (ServerStatusException sse) { HttpResponseInfo info = sse.getHttpResponseInfo(); // AMF status messages are reported as HTTP_OK still. Assert.assertEquals(HttpURLConnection.HTTP_OK, info.getResponseCode()); Assert.assertEquals("OK", info.getResponseMessage()); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCloseNoConnect() - { + @Test + public void testCloseNoConnect() { AMFConnection amfConnection = new AMFConnection(); // Closing with no connection or call. - try - { + try { amfConnection.close(); Assert.assertEquals(null, amfConnection.getUrl()); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testSetGetObjectEncoding() - { + @Test + public void testSetGetObjectEncoding() { int retAMF; AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); amfConnection.setObjectEncoding(MessageIOConstants.AMF0); retAMF = amfConnection.getObjectEncoding(); Assert.assertEquals(MessageIOConstants.AMF0, retAMF); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testSetGetDefaultObjectEncoding() - { + @Test + public void testSetGetDefaultObjectEncoding() { int retAMF; AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); AMFConnection.setDefaultObjectEncoding(MessageIOConstants.AMF3); retAMF = AMFConnection.getDefaultObjectEncoding(); Assert.assertEquals(MessageIOConstants.AMF3, retAMF); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } @@ -444,233 +318,179 @@ public void testSetGetDefaultObjectEncoding() * There doesn't seem to be a single implementation of AMFHeaderProcessor therefore this test * is pretty useless. */ - public void testSetGetAMFHeaderProcessor() - { - AMFHeaderProcessor setAMF = null; - AMFHeaderProcessor retAMF; + @Test + public void testSetGetAMFHeaderProcessor() { AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); - amfConnection.setAMFHeaderProcessor(setAMF); - retAMF = amfConnection.getAMFHeaderProcessor(); - Assert.assertEquals(setAMF, retAMF); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + amfConnection.setAMFHeaderProcessor(null); + AMFHeaderProcessor retAMF = amfConnection.getAMFHeaderProcessor(); + Assert.assertNull(retAMF); + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testAddRemoveAMFHeaderTwoParam() - { + @Test + public void testAddRemoveAMFHeaderTwoParam() { boolean retAMF; Object val = 1; AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); - amfConnection.addAmfHeader(FOO_STRING,val); + amfConnection.addAmfHeader(FOO_STRING, val); retAMF = amfConnection.removeAmfHeader(FOO_STRING); Assert.assertTrue(retAMF); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testAddRemoveAMFHeader() - { + @Test + public void testAddRemoveAMFHeader() { boolean retAMF; Object val = 1; AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); - amfConnection.addAmfHeader(FOO_STRING,true,val); + amfConnection.addAmfHeader(FOO_STRING, true, val); retAMF = amfConnection.removeAmfHeader(FOO_STRING); Assert.assertTrue(retAMF); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testAddRemoveAllAMFHeaders() - { + @Test + public void testAddRemoveAllAMFHeaders() { Object val1 = 1; Object val2 = 2; AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); - amfConnection.addAmfHeader(FOO_STRING,true,val1); - amfConnection.addAmfHeader(BAR_STRING,true,val2); + amfConnection.addAmfHeader(FOO_STRING, true, val1); + amfConnection.addAmfHeader(BAR_STRING, true, val2); amfConnection.removeAllAmfHeaders(); Assert.assertTrue(true); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testAddRemoveHTTPRequestHeader() - { + @Test + public void testAddRemoveHTTPRequestHeader() { boolean retHttp; AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); - amfConnection.addHttpRequestHeader(FOO_STRING,BAR_STRING); + amfConnection.addHttpRequestHeader(FOO_STRING, BAR_STRING); retHttp = amfConnection.removeHttpRequestHeader(FOO_STRING); Assert.assertTrue(retHttp); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testAddRemoveAllHTTPRequestHeaders() - { + @Test + public void testAddRemoveAllHTTPRequestHeaders() { AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); - amfConnection.addHttpRequestHeader(FOO_STRING,BAR_STRING); - amfConnection.addHttpRequestHeader(BAR_STRING,FOO_STRING); + amfConnection.addHttpRequestHeader(FOO_STRING, BAR_STRING); + amfConnection.addHttpRequestHeader(BAR_STRING, FOO_STRING); amfConnection.removeAllHttpRequestHeaders(); Assert.assertTrue(true); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testRemoveAMFHeader() - { + @Test + public void testRemoveAMFHeader() { boolean retAMF; AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); retAMF = amfConnection.removeAmfHeader(FOO_STRING); Assert.assertFalse(retAMF); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testRemoveAllAMFHeaders() - { + @Test + public void testRemoveAllAMFHeaders() { AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); amfConnection.removeAllAmfHeaders(); Assert.assertTrue(true); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testRemoveHTTPRequestHeader() - { + @Test + public void testRemoveHTTPRequestHeader() { boolean retHttp; AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); retHttp = amfConnection.removeHttpRequestHeader(FOO_STRING); Assert.assertFalse(retHttp); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - public void testRemoveAllHTTPRequestHeaders() - { + @Test + public void testRemoveAllHTTPRequestHeaders() { AMFConnection amfConnection = new AMFConnection(); - try - { - amfConnection.connect(getConnectionUrl()); + try { + amfConnection.connect(getConnectionUrl(), serializationContext); Assert.assertEquals(getConnectionUrl(), amfConnection.getUrl()); amfConnection.removeAllHttpRequestHeaders(); Assert.assertTrue(true); - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } finally { amfConnection.close(); } } - - public void testInstantiateTypes() - { + @Test + public void testInstantiateTypes() { String method = "getObject2"; - try - { + try { AMFConnection amfConnection = new AMFConnection(); - amfConnection.connect(getConnectionUrl()); + amfConnection.connect(getConnectionUrl(), serializationContext); // First, make sure we get the strong type. Object result = amfConnection.call(getOperationCall(method)); @@ -681,51 +501,40 @@ public void testInstantiateTypes() result = amfConnection.call(getOperationCall(method)); Assert.assertTrue(!(result instanceof ClientCustomType)); amfConnection.close(); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testSetGetAMFTrace() - { + @Test + public void testSetGetAMFTrace() { AMFConnection amfConnection = new AMFConnection(); - try - { + try { AmfTrace trace = new AmfTrace(); - amfConnection.connect(getConnectionUrl()); + amfConnection.connect(getConnectionUrl(), serializationContext); amfConnection.setAmfTrace(trace); String stringToEcho = DEFAULT_METHOD_ARG + 1; Object result = amfConnection.call(DEFAULT_AMF_OPERATION, stringToEcho); Assert.assertEquals(stringToEcho, result); if (trace.toString().length() > 0) Assert.assertTrue(true); - else fail("AmfTrace did not get anything: " + trace.toString() + " " + trace.toString().length()); + else Assert.fail("AmfTrace did not get anything: " + trace.toString() + " " + trace.toString().length()); amfConnection.close(); - - } - catch (ClientStatusException cse) - { - fail(UNEXPECTED_EXCEPTION_STRING + cse); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); - } - finally - { + } catch (ClientStatusException cse) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + cse); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); + } finally { amfConnection.close(); } } - public void testHTTPProxy() - { + @Test + public void testHTTPProxy() { AMFConnection amfconn = new AMFConnection(); - try - { + try { amfconn.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8888))); amfconn.connect("http://localhost:8400/team/messagebroker/amf"); RemotingMessage call = new RemotingMessage(); @@ -736,41 +545,50 @@ public void testHTTPProxy() call.setOperation("echo"); call.setBody("hello"); amfconn.call("foo", call); - fail("ClientStatusException expected"); - } - catch (ClientStatusException cse) - { + Assert.fail("ClientStatusException expected"); + } catch (ClientStatusException cse) { Assert.assertEquals(ClientStatusException.AMF_CALL_FAILED_CODE, cse.getCode()); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); - } - finally - { + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); + } finally { amfconn.close(); } } + /////////////////////////////////////////////////////////////////////////////// + // Utility methods + /////////////////////////////////////////////////////////////////////////////// + + /** + * Given a remote method name, returns the AMF connection call needed using + * the default destination id. + */ + private static String getOperationCall(String method) { + return DEFAULT_DESTINATION_ID + "." + method; + } + + private static String getConnectionUrl() { + return String.format(DEFAULT_URL, serverPort); + } + // A simple interface to handle AMF call results. - private interface CallResultHandler - { + private interface CallResultHandler { void onResult(Object result); } // Helper method used by JUnit tests to pass in an operation and method argument // When the AMF call returns, CallResultHandler.onResult is called to Assert things. - private void internalTestCall(String operation, Object methodArg, CallResultHandler resultHandler) throws ClientStatusException, ServerStatusException - { + private void internalTestCall(String operation, Object methodArg, CallResultHandler resultHandler) throws ClientStatusException, ServerStatusException { AMFConnection amfConnection = new AMFConnection(); // Connect. - amfConnection.connect(getConnectionUrl()); + amfConnection.connect(getConnectionUrl(), serializationContext); // Make a remoting call and retrieve the result. Object result; - if (methodArg == null) + if (methodArg == null) { result = amfConnection.call(operation); - else + } else { result = amfConnection.call(operation, methodArg); + } resultHandler.onResult(result); amfConnection.close(); }
remoting/src/test/java/flex/messaging/io/amf/client/AMFDataTypeIT.java+262 −398 modified@@ -16,31 +16,27 @@ */ package flex.messaging.io.amf.client; -import java.util.Date; -import java.util.List; - import flex.messaging.io.SerializationContext; +import flex.messaging.io.amf.client.exceptions.ClientStatusException; +import flex.messaging.io.amf.client.exceptions.ServerStatusException; import flex.messaging.util.TestServerWrapper; -import junit.extensions.TestSetup; -import org.w3c.dom.Document; - +import flex.messaging.util.XMLUtil; +import flex.messaging.validators.ClassDeserializationValidator; +import org.junit.AfterClass; import org.junit.Assert; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - +import org.junit.BeforeClass; +import org.junit.Test; +import org.w3c.dom.Document; import remoting.amfclient.ClientCustomType; -import flex.messaging.io.amf.client.exceptions.ClientStatusException; -import flex.messaging.io.amf.client.exceptions.ServerStatusException; -import flex.messaging.util.XMLUtil; +import java.util.Date; +import java.util.List; /** * JUnit tests for AMFConnection. Note that most of the tests require a running - * server with the specified destination. + * server with the specified destination. */ -public class AMFDataTypeIT extends TestCase -{ +public class AMFDataTypeIT { private static final String DEFAULT_DESTINATION_ID = "amfConnectionTestService"; private static final String DEFAULT_METHOD_NAME = "echoString"; private static final String DEFAULT_METHOD_ARG = "echo me"; @@ -55,534 +51,399 @@ public class AMFDataTypeIT extends TestCase private static int customValidationServerPort; private static SerializationContext serializationContext; - /** - * Given a remote method name, returns the AMF connection call needed using - * the default destination id. - */ - private static String getOperationCall(String method) - { - return DEFAULT_DESTINATION_ID + "." + method; - } - - protected String getStandardValidationConnectionUrl() { - return String.format(DEFAULT_URL, standardValidationServerPort); - } - - protected String getCustomValidationConnectionUrl() { - return String.format(DEFAULT_URL, customValidationServerPort); - } - - public AMFDataTypeIT(String name) - { - super(name); + @BeforeClass + public static void setup() { + standardValidationServerWrapper = new TestServerWrapper(); + standardValidationServerPort = standardValidationServerWrapper.startServer("classpath:/WEB-INF/flex/services-config.xml"); + if (standardValidationServerPort == -1) { + Assert.fail("Couldn't start server (standard validation) process"); + } + + customValidationServerWrapper = new TestServerWrapper(); + customValidationServerPort = customValidationServerWrapper.startServer("classpath:/WEB-INF/flex/services-config-customized-validation.xml"); + if(customValidationServerPort == -1) { + Assert.fail("Couldn't start server (custom validation) process"); + } + + AMFConnection.registerAlias( + "remoting.amfclient.ServerCustomType" /* server type */, + "remoting.amfclient.ClientCustomType" /* client type */); + + serializationContext = SerializationContext.getSerializationContext(); + ClassDeserializationValidator deserializationValidator = + (ClassDeserializationValidator) serializationContext.getDeserializationValidator(); + deserializationValidator.addAllowClassPattern("remoting.amfclient.*"); + serializationContext.createASObjectForMissingType = true; + // Make sure collections are written out as Arrays (vs. ArrayCollection), + // in case the server does not recognize ArrayCollections. + serializationContext.legacyCollection = true; + // When legacyMap is true, Java Maps are serialized as ECMA arrays + // instead of anonymous Object. + serializationContext.legacyMap = true; + // Disable serialization of xml documents. + serializationContext.allowXml = false; } - public static Test suite() - { - //TestSuite suite = new TestSuite(AMFDataTypeIT.class); - TestSuite suite = new TestSuite(); - suite.addTest(new AMFDataTypeIT("testCallStringArgStringReturn")); - suite.addTest(new AMFDataTypeIT("testCallIntArgIntReturn")); - suite.addTest(new AMFDataTypeIT("testCallBooleanArgBooleanReturn")); - suite.addTest(new AMFDataTypeIT("testCallObjectArgObjectReturn")); - suite.addTest(new AMFDataTypeIT("testCallObjectArgCustomReturn")); - suite.addTest(new AMFDataTypeIT("testCallCustomArgObjectReturn")); - suite.addTest(new AMFDataTypeIT("testCallCustomArgCustomReturn")); - suite.addTest(new AMFDataTypeIT("testCallNoArgObjectReturn")); - suite.addTest(new AMFDataTypeIT("testCallNoArgCustomReturn")); - suite.addTest(new AMFDataTypeIT("testCallNoArgObjectArrayReturn")); - suite.addTest(new AMFDataTypeIT("testCallDateArgDateReturn")); - suite.addTest(new AMFDataTypeIT("testCallShortArgShortReturn")); - suite.addTest(new AMFDataTypeIT("testCallDoubleArgDoubleReturn")); - suite.addTest(new AMFDataTypeIT("testCallIntArrayArgIntArrayReturn")); - suite.addTest(new AMFDataTypeIT("testCallObjectArrayArgObjectArrayReturn")); - suite.addTest(new AMFDataTypeIT("testXMLDocumentEnabledXml")); - suite.addTest(new AMFDataTypeIT("testXMLDocumentDisabledXml")); - - suite.addTest(new AMFDataTypeIT("testCallObjectArgObjectReturnCustomizedValidation")); - suite.addTest(new AMFDataTypeIT("testCallCustomArgObjectReturnCustomizedValidation")); - suite.addTest(new AMFDataTypeIT("testCallObjectArgCustomReturnCustomizedValidation")); - suite.addTest(new AMFDataTypeIT("testCallCustomArgCustomReturnCustomizedValidation")); - suite.addTest(new AMFDataTypeIT("testCallObjectArrayArgObjectArrayReturnCustomizedValidation")); - - return new TestSetup(suite) { - protected void setUp() throws Exception { - standardValidationServerWrapper = new TestServerWrapper(); - standardValidationServerPort = standardValidationServerWrapper.startServer("classpath:/WEB-INF/flex/services-config.xml"); - if(standardValidationServerPort == -1) { - Assert.fail("Couldn't start server (standard validation) process"); - } - - customValidationServerWrapper = new TestServerWrapper(); - customValidationServerPort = customValidationServerWrapper.startServer("classpath:/WEB-INF/flex/services-config-customized-validation.xml"); - if(customValidationServerPort == -1) { - Assert.fail("Couldn't start server (custom validation) process"); - } - - AMFConnection.registerAlias( - "remoting.amfclient.ServerCustomType" /* server type */, - "remoting.amfclient.ClientCustomType" /* client type */); - - serializationContext = new SerializationContext(); - serializationContext.createASObjectForMissingType = true; - // Make sure collections are written out as Arrays (vs. ArrayCollection), - // in case the server does not recognize ArrayCollections. - serializationContext.legacyCollection = true; - // When legacyMap is true, Java Maps are serialized as ECMA arrays - // instead of anonymous Object. - serializationContext.legacyMap = true; - // Disable serialization of xml documents. - serializationContext.allowXml = false; - } - protected void tearDown() throws Exception { - standardValidationServerWrapper.stopServer(); - standardValidationServerWrapper = null; - customValidationServerWrapper.stopServer(); - customValidationServerWrapper = null; - } - }; + @AfterClass + public static void teardown() { + standardValidationServerWrapper.stopServer(); + standardValidationServerWrapper = null; + customValidationServerWrapper.stopServer(); + customValidationServerWrapper = null; } - public void testCallStringArgStringReturn() - { - try - { - internalTestCall(DEFAULT_AMF_OPERATION, DEFAULT_METHOD_ARG, new CallResultHandler(){ - public void onResult(Object result) - { + @Test + public void testCallStringArgStringReturn() { + try { + internalTestCall(DEFAULT_AMF_OPERATION, DEFAULT_METHOD_ARG, new CallResultHandler() { + public void onResult(Object result) { Assert.assertEquals(DEFAULT_METHOD_ARG, result); } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallIntArgIntReturn() - { + @Test + public void testCallIntArgIntReturn() { String method = "echoInt"; final int methodArg = 1; - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - Assert.assertEquals(methodArg, ((Double)result).intValue()); + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + Assert.assertEquals(methodArg, ((Double) result).intValue()); } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallBooleanArgBooleanReturn() - { - try - { + @Test + public void testCallBooleanArgBooleanReturn() { + try { String method = "echoBoolean"; final boolean methodArg = true; - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { Assert.assertEquals(methodArg, result); } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallDateArgDateReturn() - { + @Test + public void testCallDateArgDateReturn() { String method = "echoDate"; final Date methodArg = new Date(999991); - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { Assert.assertEquals(methodArg, result); } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallShortArgShortReturn() - { + @Test + public void testCallShortArgShortReturn() { String method = "echoShort"; final short methodArg = 32000; - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - Assert.assertEquals(methodArg, ((Double)result).shortValue()); + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + Assert.assertEquals(methodArg, ((Double) result).shortValue()); } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallDoubleArgDoubleReturn() - { + @Test + public void testCallDoubleArgDoubleReturn() { String method = "echoDouble"; final double methodArg = -95.25; - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { Assert.assertEquals(methodArg, result); } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallObjectArgObjectReturn() - { + @Test + public void testCallObjectArgObjectReturn() { String method = "echoObject1"; ClientCustomType temp = new ClientCustomType(); temp.setId(1); final Object methodArg = temp; - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - ClientCustomType temp2 = (ClientCustomType)result; + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + ClientCustomType temp2 = (ClientCustomType) result; Assert.assertEquals(1, temp2.getId()); } }, false); - fail(UNEXPECTED_SUCCESS_STRING); - } - catch (Exception e) - { + Assert.fail(UNEXPECTED_SUCCESS_STRING); + } catch (Exception e) { // An exception is what we expect here. } } - public void testCallObjectArgObjectReturnCustomizedValidation() - { + @Test + public void testCallObjectArgObjectReturnCustomizedValidation() { String method = "echoObject1"; ClientCustomType temp = new ClientCustomType(); temp.setId(1); final Object methodArg = temp; - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - ClientCustomType temp2 = (ClientCustomType)result; + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + ClientCustomType temp2 = (ClientCustomType) result; Assert.assertEquals(1, temp2.getId()); } }, true); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallObjectArgCustomReturn() - { + @Test + public void testCallObjectArgCustomReturn() { String method = "echoObject2"; ClientCustomType temp = new ClientCustomType(); temp.setId(1); final Object methodArg = temp; - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - ClientCustomType temp2 = (ClientCustomType)result; + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + ClientCustomType temp2 = (ClientCustomType) result; Assert.assertEquals(1, temp2.getId()); } }, false); - fail(UNEXPECTED_SUCCESS_STRING); - } - catch (Exception e) - { + Assert.fail(UNEXPECTED_SUCCESS_STRING); + } catch (Exception e) { // An exception is what we expect here. } } - public void testCallObjectArgCustomReturnCustomizedValidation() - { + @Test + public void testCallObjectArgCustomReturnCustomizedValidation() { String method = "echoObject2"; ClientCustomType temp = new ClientCustomType(); temp.setId(1); final Object methodArg = temp; - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - ClientCustomType temp2 = (ClientCustomType)result; + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + ClientCustomType temp2 = (ClientCustomType) result; Assert.assertEquals(1, temp2.getId()); } }, true); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallCustomArgObjectReturn() - { + @Test + public void testCallCustomArgObjectReturn() { String method = "echoObject3"; final ClientCustomType methodArg = new ClientCustomType(); methodArg.setId(1); - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - ClientCustomType temp2 = (ClientCustomType)result; + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + ClientCustomType temp2 = (ClientCustomType) result; Assert.assertEquals(1, temp2.getId()); } }, false); - fail(UNEXPECTED_SUCCESS_STRING); - } - catch (Exception e) - { + Assert.fail(UNEXPECTED_SUCCESS_STRING); + } catch (Exception e) { // An exception is what we expect here. } } - public void testCallCustomArgObjectReturnCustomizedValidation() - { + @Test + public void testCallCustomArgObjectReturnCustomizedValidation() { String method = "echoObject3"; final ClientCustomType methodArg = new ClientCustomType(); methodArg.setId(1); - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - ClientCustomType temp2 = (ClientCustomType)result; + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + ClientCustomType temp2 = (ClientCustomType) result; Assert.assertEquals(1, temp2.getId()); } }, true); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallCustomArgCustomReturn() - { + @Test + public void testCallCustomArgCustomReturn() { String method = "echoObject4"; final ClientCustomType methodArg = new ClientCustomType(); methodArg.setId(1); - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - ClientCustomType temp2 = (ClientCustomType)result; + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + ClientCustomType temp2 = (ClientCustomType) result; Assert.assertEquals(1, temp2.getId()); } }, false); - fail(UNEXPECTED_SUCCESS_STRING); - } - catch (Exception e) - { + Assert.fail(UNEXPECTED_SUCCESS_STRING); + } catch (Exception e) { // An exception is what we expect here. } } - public void testCallCustomArgCustomReturnCustomizedValidation() - { + @Test + public void testCallCustomArgCustomReturnCustomizedValidation() { String method = "echoObject4"; final ClientCustomType methodArg = new ClientCustomType(); methodArg.setId(1); - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - ClientCustomType temp2 = (ClientCustomType)result; + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + ClientCustomType temp2 = (ClientCustomType) result; Assert.assertEquals(1, temp2.getId()); } }, true); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallNoArgObjectReturn() - { + @Test + public void testCallNoArgObjectReturn() { String method = "getObject1"; - try - { - internalTestCall(getOperationCall(method), null, new CallResultHandler(){ - public void onResult(Object result) - { - ClientCustomType temp2 = (ClientCustomType)result; + try { + internalTestCall(getOperationCall(method), null, new CallResultHandler() { + public void onResult(Object result) { + ClientCustomType temp2 = (ClientCustomType) result; Assert.assertEquals(1, temp2.getId()); } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallNoArgCustomReturn() - { + @Test + public void testCallNoArgCustomReturn() { String method = "getObject2"; - try - { - internalTestCall(getOperationCall(method), null, new CallResultHandler(){ - public void onResult(Object result) - { - ClientCustomType temp2 = (ClientCustomType)result; + try { + internalTestCall(getOperationCall(method), null, new CallResultHandler() { + public void onResult(Object result) { + ClientCustomType temp2 = (ClientCustomType) result; Assert.assertEquals(1, temp2.getId()); } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallNoArgObjectArrayReturn() - { + @Test + public void testCallNoArgObjectArrayReturn() { String method = "getObjectArray1"; - try - { - internalTestCall(getOperationCall(method), null, new CallResultHandler(){ - public void onResult(Object result) - { - List temp = (List)result; - for (int i = 0; i < temp.size(); i++) - { - ClientCustomType temp2 = (ClientCustomType)temp.get(i); + try { + internalTestCall(getOperationCall(method), null, new CallResultHandler() { + public void onResult(Object result) { + List temp = (List) result; + for (int i = 0; i < temp.size(); i++) { + ClientCustomType temp2 = (ClientCustomType) temp.get(i); Assert.assertEquals(i, temp2.getId()); } } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallIntArrayArgIntArrayReturn() - { + @Test + public void testCallIntArrayArgIntArrayReturn() { String method = "echoObject5"; - final int[] methodArg = new int[] {0,1,2,3}; - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - List temp = (List)result; - for (int i = 0; i < temp.size(); i++) - { - Assert.assertEquals(i, ((Integer)temp.get(i)).intValue()); + final int[] methodArg = new int[]{0, 1, 2, 3}; + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + List temp = (List) result; + for (int i = 0; i < temp.size(); i++) { + Assert.assertEquals(i, ((Integer) temp.get(i)).intValue()); } } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - public void testCallObjectArrayArgObjectArrayReturn() - { + @Test + public void testCallObjectArrayArgObjectArrayReturn() { String method = "echoObject1"; Object[] temp = new Object[3]; - for (int i = 0; i < temp.length; i++) - { + for (int i = 0; i < temp.length; i++) { ClientCustomType cct = new ClientCustomType(); cct.setId(i); temp[i] = cct; } final Object[] methodArg = temp; - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - List temp = (List)result; - for (int i = 0; i < temp.size(); i++) - { - ClientCustomType temp2 = (ClientCustomType)temp.get(i); + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + List temp = (List) result; + for (int i = 0; i < temp.size(); i++) { + ClientCustomType temp2 = (ClientCustomType) temp.get(i); Assert.assertEquals(i, temp2.getId()); } } }, false); - fail(UNEXPECTED_SUCCESS_STRING); - } - catch (Exception e) - { + Assert.fail(UNEXPECTED_SUCCESS_STRING); + } catch (Exception e) { // An exception is what we expect here. } } - public void testCallObjectArrayArgObjectArrayReturnCustomizedValidation() - { + @Test + public void testCallObjectArrayArgObjectArrayReturnCustomizedValidation() { String method = "echoObject1"; Object[] temp = new Object[3]; - for (int i = 0; i < temp.length; i++) - { + for (int i = 0; i < temp.length; i++) { ClientCustomType cct = new ClientCustomType(); cct.setId(i); temp[i] = cct; } final Object[] methodArg = temp; - try - { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - List temp = (List)result; - for (int i = 0; i < temp.size(); i++) - { - ClientCustomType temp2 = (ClientCustomType)temp.get(i); + try { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + List temp = (List) result; + for (int i = 0; i < temp.size(); i++) { + ClientCustomType temp2 = (ClientCustomType) temp.get(i); Assert.assertEquals(i, temp2.getId()); } } }, true); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } - - public void testXMLDocumentEnabledXml() - { - try - { + @Test + public void testXMLDocumentEnabledXml() { + try { // Temporarily enable xml serialization/deserialization. serializationContext.allowXml = true; @@ -592,78 +453,81 @@ public void testXMLDocumentEnabledXml() Document xmlDoc = XMLUtil.stringToDocument(xml.toString()); final Object methodArg = xmlDoc; - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - try - { - Document retXmlDoc = (Document)result; + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + try { + Document retXmlDoc = (Document) result; String retXML = XMLUtil.documentToString(retXmlDoc); Assert.assertEquals(xml.toString(), retXML); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } }, false); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); - } - finally { + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); + } finally { // Disable xml serialization/deserialization again. serializationContext.allowXml = false; } } - - public void testXMLDocumentDisabledXml() - { - try - { + @Test + public void testXMLDocumentDisabledXml() { + try { String method = "echoObject1"; final StringBuffer xml = new StringBuffer(512); xml.append("<test> <item id=\"1\"> <sweet/> </item></test>"); Document xmlDoc = XMLUtil.stringToDocument(xml.toString()); final Object methodArg = xmlDoc; - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ - public void onResult(Object result) - { - try - { - Document retXmlDoc = (Document)result; + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler() { + public void onResult(Object result) { + try { + Document retXmlDoc = (Document) result; String retXML = XMLUtil.documentToString(retXmlDoc); Assert.assertEquals("", retXML); - } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } } }, false); + } catch (Exception e) { + Assert.fail(UNEXPECTED_EXCEPTION_STRING + e); } - catch (Exception e) - { - fail(UNEXPECTED_EXCEPTION_STRING + e); - } + } + + /////////////////////////////////////////////////////////////////////////////// + // Utility methods + /////////////////////////////////////////////////////////////////////////////// + + /** + * Given a remote method name, returns the AMF connection call needed using + * the default destination id. + */ + private static String getOperationCall(String method) { + return DEFAULT_DESTINATION_ID + "." + method; + } + + private static String getStandardValidationConnectionUrl() { + return String.format(DEFAULT_URL, standardValidationServerPort); + } + + private static String getCustomValidationConnectionUrl() { + return String.format(DEFAULT_URL, customValidationServerPort); } // A simple interface to handle AMF call results. - private interface CallResultHandler - { + private interface CallResultHandler { void onResult(Object result); } // Helper method used by JUnit tests to pass in an operation and method argument // When the AMF call returns, CallResultHandler.onResult is called to Assert things. - private void internalTestCall(String operation, Object methodArg, CallResultHandler resultHandler, boolean customizedValidation) throws ClientStatusException, ServerStatusException - { + private void internalTestCall(String operation, Object methodArg, CallResultHandler resultHandler, boolean customizedValidation) throws ClientStatusException, ServerStatusException { AMFConnection amfConnection = new AMFConnection(); // Connect. - if(customizedValidation) { + if (customizedValidation) { amfConnection.connect(getCustomValidationConnectionUrl(), serializationContext); } else { amfConnection.connect(getStandardValidationConnectionUrl(), serializationContext);
remoting/src/test/java/flex/messaging/util/TestServerWrapper.java+3 −3 modified@@ -42,9 +42,9 @@ public int startServer(String configPath) { final String path = System.getProperty("java.home") + separator + "bin" + separator + "java"; List<String> args = new LinkedList<String>(); args.add(path); -/* if(configPath.contains("customized-validation")) { - args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"); - }*/ + //if(configPath.contains("customized-validation")) { +// args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"); + //} args.add("-cp"); args.add(classpath); args.add(TestServer.class.getCanonicalName());
f861f0993c35- Made BlazeDS use the ClassDeserializationValidator as default validator, if no validator is provided.
9 files changed · +366 −148
core/src/main/java/flex/messaging/config/ServerConfigurationParser.java+22 −5 modified@@ -16,6 +16,7 @@ */ package flex.messaging.config; +import flex.messaging.validators.ClassDeserializationValidator; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -1865,21 +1866,37 @@ private void messageFilter(Node messageFilter, String filterType) private void validators(Node root) { Node validatorsNode = selectSingleNode(root, VALIDATORS_ELEMENT); - if (validatorsNode == null) + if (validatorsNode == null) { + // Default to the ClassDeserializationValidator + defaultValidator(); return; + } // Validation allowedChildElements(validatorsNode, VALIDATORS_CHILDREN); // Validator NodeList validators = selectNodeList(validatorsNode, VALIDATOR_ELEMENT); - for (int i = 0; i < validators.getLength(); i++) - { - Node validator = validators.item(i); - validator(validator); + if(validators.getLength() > 0) { + for (int i = 0; i < validators.getLength(); i++) { + Node validator = validators.item(i); + validator(validator); + } + } else { + // Default to the ClassDeserializationValidator + defaultValidator(); } } + /** + * Initialize a efault validator that protects BlazeDS against the most obvious attacks. + */ + private void defaultValidator() { + ValidatorSettings validatorSettings = new ValidatorSettings(); + validatorSettings.setClassName(ClassDeserializationValidator.class.getName()); + ((MessagingConfiguration)config).addValidatorSettings(validatorSettings); + } + private void validator(Node validator) { // Validation
core/src/main/java/flex/messaging/io/SerializationContext.java+1 −0 modified@@ -17,6 +17,7 @@ package flex.messaging.io; import flex.messaging.util.ClassUtil; +import flex.messaging.validators.ClassDeserializationValidator; import flex.messaging.validators.DeserializationValidator; import java.io.Serializable;
core/src/main/java/flex/messaging/MessageBroker.java+1 −0 modified@@ -57,6 +57,7 @@ import flex.messaging.util.StringUtils; import flex.messaging.util.UUIDGenerator; import flex.messaging.util.UUIDUtils; +import flex.messaging.validators.ClassDeserializationValidator; import flex.messaging.validators.DeserializationValidator; import javax.servlet.ServletContext;
core/src/main/java/flex/messaging/validators/ClassDeserializationValidator.java+82 −102 modified@@ -16,23 +16,18 @@ */ package flex.messaging.validators; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; - import flex.messaging.config.ConfigMap; +import java.util.*; +import java.util.regex.Pattern; + /** * The <code>ClassDeserializationValidator</code> is provided as a default * implementation of <code>DeserializationValidator</code> and it simply * validates the creation of allowed and disallowed classes as specified in * the configuration. */ -public class ClassDeserializationValidator implements DeserializationValidator -{ +public class ClassDeserializationValidator implements DeserializationValidator { //-------------------------------------------------------------------------- // // Public Static Constants @@ -43,25 +38,36 @@ public class ClassDeserializationValidator implements DeserializationValidator public static final String PROPERTY_DISALLOW_CLASSES = "disallow-classes"; public static final String PROPERTY_CLASS_ATTR = "class"; public static final String PROPERTY_NAME_ATTR = "name"; - - private static final String [] DEFAULT_ALLOW_CLASSES = { - "flex.messaging.*", - "flex.data.*", - "java.lang.Boolean", - "java.lang.Byte", - "java.lang.Character", - "java.lang.Double", - "java.lang.Float", - "java.lang.Integer", - "java.lang.Long", - "java.lang.Object", - "java.lang.Short", - "java.lang.String", - "java.io.Externalizable", - "java.util.*", - "org.w3c.dom.Document", - "\\[B", - "\\[Ljava.lang.Object;" + + private static final String[] DEFAULT_ALLOW_CLASSES = { + "flex.messaging.io.amf.SerializedObject", + "flex.messaging.io.ArrayCollection", + "flex.messaging.io.ObjectProxy", + "flex.messaging.io.SerializationProxy", + "flex.messaging.messages.AcknowledgeMessageExt", + "flex.messaging.messages.AsyncMessageExt", + "flex.messaging.messages.CommandMessageExt", + "flex.data.messages.DataMessageExt", + "flex.data.messages.ManagedRemotingMessageExt", + "flex.data.messages.PagedMessageExt", + "flex.data.messages.SequencedMessageExt", + "flex.data.messages.UpdateCollectionMessageExt", + "flex.data.ChangedItems", + "java.lang.Boolean", + "java.lang.Byte", + "java.lang.Character", + "java.lang.Double", + "java.lang.Float", + "java.lang.Integer", + "java.lang.Long", + "java.lang.Object", + "java.lang.Short", + "java.lang.String", + "java.io.Externalizable", + "java.util.Date", + "org.w3c.dom.Document", + "\\[B", + "\\[Ljava.lang.Object;" }; //-------------------------------------------------------------------------- @@ -87,6 +93,10 @@ public class ClassDeserializationValidator implements DeserializationValidator private Map<String, Pattern> allowClassPatterns; private Map<String, Pattern> disallowClassPatterns; + public ClassDeserializationValidator() { + } + + //-------------------------------------------------------------------------- // // Public Methods @@ -98,10 +108,8 @@ public class ClassDeserializationValidator implements DeserializationValidator * * @param classNamePattern The name of the class which can be a regular expression. */ - public void addAllowClassPattern(String classNamePattern) - { - synchronized (lock) - { + public void addAllowClassPattern(String classNamePattern) { + synchronized (lock) { if (allowClassPatterns == null) allowClassPatterns = new HashMap<String, Pattern>(); @@ -116,10 +124,8 @@ public void addAllowClassPattern(String classNamePattern) * * @param classNamePattern The name of the class which can be a regular expression. */ - public void removeAllowClassPattern(String classNamePattern) - { - synchronized (lock) - { + public void removeAllowClassPattern(String classNamePattern) { + synchronized (lock) { if (allowClassPatterns != null) allowClassPatterns.remove(classNamePattern); @@ -132,10 +138,8 @@ public void removeAllowClassPattern(String classNamePattern) * * @param classNamePattern The name of the class which can be a regular expression. */ - public void addDisallowClassPattern(String classNamePattern) - { - synchronized (lock) - { + public void addDisallowClassPattern(String classNamePattern) { + synchronized (lock) { if (disallowClassPatterns == null) disallowClassPatterns = new HashMap<String, Pattern>(); @@ -150,10 +154,8 @@ public void addDisallowClassPattern(String classNamePattern) * * @param classNamePattern The name of the class which can be a regular expression. */ - public void removeDisallowClassPattern(String classNamePattern) - { - synchronized (lock) - { + public void removeDisallowClassPattern(String classNamePattern) { + synchronized (lock) { if (disallowClassPatterns != null) disallowClassPatterns.remove(classNamePattern); @@ -167,12 +169,11 @@ public void removeDisallowClassPattern(String classNamePattern) * therefore this method always returns true. * * @param instance The Array or List instance. - * @param index The index at which the value is being assigned. - * @param value The value that is assigned to the index. + * @param index The index at which the value is being assigned. + * @param value The value that is assigned to the index. * @return True. */ - public boolean validateAssignment(Object instance, int index, Object value) - { + public boolean validateAssignment(Object instance, int index, Object value) { return true; } @@ -181,13 +182,12 @@ public boolean validateAssignment(Object instance, int index, Object value) * to a value but this class only deals with class creations, therefore this * method always returns true. * - * @param instance The instance with the property that is being assigned a new value. + * @param instance The instance with the property that is being assigned a new value. * @param propertyName The name of the property that is being assigned. - * @param value The value that the property is being assigned to. + * @param value The value that the property is being assigned to. * @return True. */ - public boolean validateAssignment(Object instance, String propertyName, Object value) - { + public boolean validateAssignment(Object instance, String propertyName, Object value) { return true; } @@ -199,9 +199,8 @@ public boolean validateAssignment(Object instance, String propertyName, Object v * @param c The class that is being created. * @return True if the creation is valid. */ - public boolean validateCreation(Class<?> c) - { - String className = c == null? null : c.getName(); + public boolean validateCreation(Class<?> c) { + String className = c == null ? null : c.getName(); if (className == null) return true; @@ -217,25 +216,19 @@ public boolean validateCreation(Class<?> c) // go through the disallow and allow class patterns list. // Disallow the class if there's a disallow-classes list, and the class is in that list. - if (disallowClassPatterns != null && !disallowClassPatterns.isEmpty()) - { - for (Pattern pattern : disallowClassPatterns.values()) - { - if (pattern.matcher(className).matches()) - { + if (disallowClassPatterns != null && !disallowClassPatterns.isEmpty()) { + for (Pattern pattern : disallowClassPatterns.values()) { + if (pattern.matcher(className).matches()) { addDisallowClass(className); return false; } } } // Disallow the class if there's an allowed-classes list, and the class is NOT in that list. - if (allowClassPatterns != null && !allowClassPatterns.isEmpty()) - { - for (Pattern pattern : allowClassPatterns.values()) - { - if (pattern.matcher(className).matches()) - { + if (allowClassPatterns != null && !allowClassPatterns.isEmpty()) { + for (Pattern pattern : allowClassPatterns.values()) { + if (pattern.matcher(className).matches()) { addAllowClass(className); return true; } @@ -250,43 +243,37 @@ public boolean validateCreation(Class<?> c) return true; } - /** {@inheritDoc} */ - public void initialize(String id, ConfigMap properties) - { + /** + * {@inheritDoc} + */ + public void initialize(String id, ConfigMap properties) { // Apply default allow classes - for (String defaultAllowClassPattern : DEFAULT_ALLOW_CLASSES) - { + for (String defaultAllowClassPattern : DEFAULT_ALLOW_CLASSES) { addAllowClassPattern(defaultAllowClassPattern); } - + if (properties == null || properties.size() == 0) return; // Process allow-classes. ConfigMap allowedClassesMap = properties.getPropertyAsMap(PROPERTY_ALLOW_CLASSES, null); - if (allowedClassesMap != null && !allowedClassesMap.isEmpty()) - { + if (allowedClassesMap != null && !allowedClassesMap.isEmpty()) { List<?> names = allowedClassesMap.getPropertyAsList(PROPERTY_CLASS_ATTR, null); - if (names != null && !names.isEmpty()) - { - for (Object element : names) - { - String name = ((ConfigMap)element).getProperty(PROPERTY_NAME_ATTR); + if (names != null && !names.isEmpty()) { + for (Object element : names) { + String name = ((ConfigMap) element).getProperty(PROPERTY_NAME_ATTR); addAllowClassPattern(name); } } } // Process disallow-classes. ConfigMap disallowedClassesMap = properties.getPropertyAsMap(PROPERTY_DISALLOW_CLASSES, null); - if (disallowedClassesMap != null && !disallowedClassesMap.isEmpty()) - { + if (disallowedClassesMap != null && !disallowedClassesMap.isEmpty()) { List<?> names = disallowedClassesMap.getPropertyAsList(PROPERTY_CLASS_ATTR, null); - if (names != null && !names.isEmpty()) - { - for (Object element : names) - { - String name = ((ConfigMap)element).getProperty(PROPERTY_NAME_ATTR); + if (names != null && !names.isEmpty()) { + for (Object element : names) { + String name = ((ConfigMap) element).getProperty(PROPERTY_NAME_ATTR); addDisallowClassPattern(name); } } @@ -299,10 +286,8 @@ public void initialize(String id, ConfigMap properties) // //-------------------------------------------------------------------------- - protected void addAllowClass(String className) - { - synchronized (lock) - { + protected void addAllowClass(String className) { + synchronized (lock) { if (allowClasses == null) allowClasses = new HashSet<String>(); @@ -311,26 +296,21 @@ protected void addAllowClass(String className) } } - protected void addDisallowClass(String className) - { - synchronized (lock) - { + protected void addDisallowClass(String className) { + synchronized (lock) { if (disallowClasses == null) disallowClasses = new HashSet<String>(); if (!disallowClasses.contains(className)) disallowClasses.add(className); } } - - protected void clearClassCache() - { - if (allowClasses != null) - { + + protected void clearClassCache() { + if (allowClasses != null) { allowClasses.clear(); } - if (disallowClasses != null) - { + if (disallowClasses != null) { disallowClasses.clear(); } }
remoting/src/test/java/flex/messaging/io/amf/client/AMFConnectionIT.java+4 −5 modified@@ -28,7 +28,7 @@ import junit.framework.TestCase; import junit.framework.TestSuite; -import amfclient.ClientCustomType; +import remoting.amfclient.ClientCustomType; import flex.messaging.MessageException; import flex.messaging.messages.RemotingMessage; @@ -116,7 +116,7 @@ protected void setUp() throws Exception { } AMFConnection.registerAlias( "remoting.amfclient.ServerCustomType" /* server type */, - "amfclient.ClientCustomType" /* client type */); + "remoting.amfclient.ClientCustomType" /* client type */); } protected void tearDown() throws Exception { serverWrapper.stopServer(); @@ -329,11 +329,9 @@ public void testCallUnreachableConnectUrl() public void testCallNonexistantMethod() { String method = "nonExistantMethod"; - final ClientCustomType methodArg = new ClientCustomType(); - methodArg.setId(1); try { - internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ + internalTestCall(getOperationCall(method), "Wombat", new CallResultHandler(){ public void onResult(Object result) { fail("Unexcepted result: " + result); @@ -382,6 +380,7 @@ public void onResult(Object result) fail(UNEXPECTED_EXCEPTION_STRING + e); } } + public void testCloseNoConnect() { AMFConnection amfConnection = new AMFConnection();
remoting/src/test/java/flex/messaging/io/amf/client/AMFDataTypeIT.java+177 −31 modified@@ -29,7 +29,7 @@ import junit.framework.TestCase; import junit.framework.TestSuite; -import amfclient.ClientCustomType; +import remoting.amfclient.ClientCustomType; import flex.messaging.io.amf.client.exceptions.ClientStatusException; import flex.messaging.io.amf.client.exceptions.ServerStatusException; @@ -47,9 +47,12 @@ public class AMFDataTypeIT extends TestCase private static final String DEFAULT_URL = "http://localhost:%s/qa-regress/messagebroker/amf"; private static final String DEFAULT_AMF_OPERATION = getOperationCall(DEFAULT_METHOD_NAME); private static final String UNEXPECTED_EXCEPTION_STRING = "Unexpected exception: "; + private static final String UNEXPECTED_SUCCESS_STRING = "Unexpected success of previous operation"; - private static TestServerWrapper serverWrapper; - private static int serverPort; + private static TestServerWrapper standardValidationServerWrapper; + private static int standardValidationServerPort; + private static TestServerWrapper customValidationServerWrapper; + private static int customValidationServerPort; private static SerializationContext serializationContext; /** @@ -61,10 +64,13 @@ private static String getOperationCall(String method) return DEFAULT_DESTINATION_ID + "." + method; } - protected String getConnectionUrl() { - return String.format(DEFAULT_URL, serverPort); + protected String getStandardValidationConnectionUrl() { + return String.format(DEFAULT_URL, standardValidationServerPort); } + protected String getCustomValidationConnectionUrl() { + return String.format(DEFAULT_URL, customValidationServerPort); + } public AMFDataTypeIT(String name) { @@ -93,17 +99,29 @@ public static Test suite() suite.addTest(new AMFDataTypeIT("testXMLDocumentEnabledXml")); suite.addTest(new AMFDataTypeIT("testXMLDocumentDisabledXml")); + suite.addTest(new AMFDataTypeIT("testCallObjectArgObjectReturnCustomizedValidation")); + suite.addTest(new AMFDataTypeIT("testCallCustomArgObjectReturnCustomizedValidation")); + suite.addTest(new AMFDataTypeIT("testCallObjectArgCustomReturnCustomizedValidation")); + suite.addTest(new AMFDataTypeIT("testCallCustomArgCustomReturnCustomizedValidation")); + suite.addTest(new AMFDataTypeIT("testCallObjectArrayArgObjectArrayReturnCustomizedValidation")); return new TestSetup(suite) { protected void setUp() throws Exception { - serverWrapper = new TestServerWrapper(); - serverPort = serverWrapper.startServer("classpath:/WEB-INF/flex/services-config.xml"); - if(serverPort == -1) { - Assert.fail("Couldn't start server process"); + standardValidationServerWrapper = new TestServerWrapper(); + standardValidationServerPort = standardValidationServerWrapper.startServer("classpath:/WEB-INF/flex/services-config.xml"); + if(standardValidationServerPort == -1) { + Assert.fail("Couldn't start server (standard validation) process"); + } + + customValidationServerWrapper = new TestServerWrapper(); + customValidationServerPort = customValidationServerWrapper.startServer("classpath:/WEB-INF/flex/services-config-customized-validation.xml"); + if(customValidationServerPort == -1) { + Assert.fail("Couldn't start server (custom validation) process"); } + AMFConnection.registerAlias( "remoting.amfclient.ServerCustomType" /* server type */, - "amfclient.ClientCustomType" /* client type */); + "remoting.amfclient.ClientCustomType" /* client type */); serializationContext = new SerializationContext(); serializationContext.createASObjectForMissingType = true; @@ -117,8 +135,10 @@ protected void setUp() throws Exception { serializationContext.allowXml = false; } protected void tearDown() throws Exception { - serverWrapper.stopServer(); - serverWrapper = null; + standardValidationServerWrapper.stopServer(); + standardValidationServerWrapper = null; + customValidationServerWrapper.stopServer(); + customValidationServerWrapper = null; } }; } @@ -132,7 +152,7 @@ public void onResult(Object result) { Assert.assertEquals(DEFAULT_METHOD_ARG, result); } - }); + }, false); } catch (Exception e) { @@ -151,7 +171,7 @@ public void onResult(Object result) { Assert.assertEquals(methodArg, ((Double)result).intValue()); } - }); + }, false); } catch (Exception e) { @@ -170,7 +190,7 @@ public void onResult(Object result) { Assert.assertEquals(methodArg, result); } - }); + }, false); } catch (Exception e) { @@ -189,7 +209,7 @@ public void onResult(Object result) { Assert.assertEquals(methodArg, result); } - }); + }, false); } catch (Exception e) { @@ -208,7 +228,7 @@ public void onResult(Object result) { Assert.assertEquals(methodArg, ((Double)result).shortValue()); } - }); + }, false); } catch (Exception e) { @@ -227,7 +247,7 @@ public void onResult(Object result) { Assert.assertEquals(methodArg, result); } - }); + }, false); } catch (Exception e) { @@ -249,7 +269,30 @@ public void onResult(Object result) ClientCustomType temp2 = (ClientCustomType)result; Assert.assertEquals(1, temp2.getId()); } - }); + }, false); + fail(UNEXPECTED_SUCCESS_STRING); + } + catch (Exception e) + { + // An exception is what we expect here. + } + } + + public void testCallObjectArgObjectReturnCustomizedValidation() + { + String method = "echoObject1"; + ClientCustomType temp = new ClientCustomType(); + temp.setId(1); + final Object methodArg = temp; + try + { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ + public void onResult(Object result) + { + ClientCustomType temp2 = (ClientCustomType)result; + Assert.assertEquals(1, temp2.getId()); + } + }, true); } catch (Exception e) { @@ -271,7 +314,30 @@ public void onResult(Object result) ClientCustomType temp2 = (ClientCustomType)result; Assert.assertEquals(1, temp2.getId()); } - }); + }, false); + fail(UNEXPECTED_SUCCESS_STRING); + } + catch (Exception e) + { + // An exception is what we expect here. + } + } + + public void testCallObjectArgCustomReturnCustomizedValidation() + { + String method = "echoObject2"; + ClientCustomType temp = new ClientCustomType(); + temp.setId(1); + final Object methodArg = temp; + try + { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ + public void onResult(Object result) + { + ClientCustomType temp2 = (ClientCustomType)result; + Assert.assertEquals(1, temp2.getId()); + } + }, true); } catch (Exception e) { @@ -292,7 +358,29 @@ public void onResult(Object result) ClientCustomType temp2 = (ClientCustomType)result; Assert.assertEquals(1, temp2.getId()); } - }); + }, false); + fail(UNEXPECTED_SUCCESS_STRING); + } + catch (Exception e) + { + // An exception is what we expect here. + } + } + + public void testCallCustomArgObjectReturnCustomizedValidation() + { + String method = "echoObject3"; + final ClientCustomType methodArg = new ClientCustomType(); + methodArg.setId(1); + try + { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ + public void onResult(Object result) + { + ClientCustomType temp2 = (ClientCustomType)result; + Assert.assertEquals(1, temp2.getId()); + } + }, true); } catch (Exception e) { @@ -313,7 +401,29 @@ public void onResult(Object result) ClientCustomType temp2 = (ClientCustomType)result; Assert.assertEquals(1, temp2.getId()); } - }); + }, false); + fail(UNEXPECTED_SUCCESS_STRING); + } + catch (Exception e) + { + // An exception is what we expect here. + } + } + + public void testCallCustomArgCustomReturnCustomizedValidation() + { + String method = "echoObject4"; + final ClientCustomType methodArg = new ClientCustomType(); + methodArg.setId(1); + try + { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ + public void onResult(Object result) + { + ClientCustomType temp2 = (ClientCustomType)result; + Assert.assertEquals(1, temp2.getId()); + } + }, true); } catch (Exception e) { @@ -332,7 +442,7 @@ public void onResult(Object result) ClientCustomType temp2 = (ClientCustomType)result; Assert.assertEquals(1, temp2.getId()); } - }); + }, false); } catch (Exception e) { @@ -351,7 +461,7 @@ public void onResult(Object result) ClientCustomType temp2 = (ClientCustomType)result; Assert.assertEquals(1, temp2.getId()); } - }); + }, false); } catch (Exception e) { @@ -374,7 +484,7 @@ public void onResult(Object result) Assert.assertEquals(i, temp2.getId()); } } - }); + }, false); } catch (Exception e) { @@ -397,7 +507,7 @@ public void onResult(Object result) Assert.assertEquals(i, ((Integer)temp.get(i)).intValue()); } } - }); + }, false); } catch (Exception e) { @@ -428,7 +538,39 @@ public void onResult(Object result) Assert.assertEquals(i, temp2.getId()); } } - }); + }, false); + fail(UNEXPECTED_SUCCESS_STRING); + } + catch (Exception e) + { + // An exception is what we expect here. + } + } + + public void testCallObjectArrayArgObjectArrayReturnCustomizedValidation() + { + String method = "echoObject1"; + Object[] temp = new Object[3]; + for (int i = 0; i < temp.length; i++) + { + ClientCustomType cct = new ClientCustomType(); + cct.setId(i); + temp[i] = cct; + } + final Object[] methodArg = temp; + try + { + internalTestCall(getOperationCall(method), methodArg, new CallResultHandler(){ + public void onResult(Object result) + { + List temp = (List)result; + for (int i = 0; i < temp.size(); i++) + { + ClientCustomType temp2 = (ClientCustomType)temp.get(i); + Assert.assertEquals(i, temp2.getId()); + } + } + }, true); } catch (Exception e) { @@ -464,7 +606,7 @@ public void onResult(Object result) fail(UNEXPECTED_EXCEPTION_STRING + e); } } - }); + }, false); } catch (Exception e) { @@ -501,7 +643,7 @@ public void onResult(Object result) fail(UNEXPECTED_EXCEPTION_STRING + e); } } - }); + }, false); } catch (Exception e) { @@ -517,11 +659,15 @@ private interface CallResultHandler // Helper method used by JUnit tests to pass in an operation and method argument // When the AMF call returns, CallResultHandler.onResult is called to Assert things. - private void internalTestCall(String operation, Object methodArg, CallResultHandler resultHandler) throws ClientStatusException, ServerStatusException + private void internalTestCall(String operation, Object methodArg, CallResultHandler resultHandler, boolean customizedValidation) throws ClientStatusException, ServerStatusException { AMFConnection amfConnection = new AMFConnection(); // Connect. - amfConnection.connect(getConnectionUrl(), serializationContext); + if(customizedValidation) { + amfConnection.connect(getCustomValidationConnectionUrl(), serializationContext); + } else { + amfConnection.connect(getStandardValidationConnectionUrl(), serializationContext); + } // Make a remoting call and retrieve the result. Object result; if (methodArg == null)
remoting/src/test/java/flex/messaging/util/TestServerWrapper.java+13 −4 modified@@ -19,6 +19,9 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; /** * Simple little wrapper starting up a BlazeDS server in a separate VM useful for unit testing the @@ -37,11 +40,17 @@ public int startServer(String configPath) { final String separator = System.getProperty("file.separator"); final String classpath = System.getProperty("java.class.path"); final String path = System.getProperty("java.home") + separator + "bin" + separator + "java"; + List<String> args = new LinkedList<String>(); + args.add(path); +/* if(configPath.contains("customized-validation")) { + args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"); + }*/ + args.add("-cp"); + args.add(classpath); + args.add(TestServer.class.getCanonicalName()); + args.add(configPath); System.out.print("Starting test-server"); - final ProcessBuilder processBuilder = new ProcessBuilder(path, - //"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005", - "-cp", /*"\"" +*/ classpath /*+ "\""*/, - TestServer.class.getCanonicalName(), /*"\"" +*/ configPath /*+ "\""*/); + final ProcessBuilder processBuilder = new ProcessBuilder(args.toArray(new String[0])); processBuilder.redirectErrorStream(true); try { serverProcess = processBuilder.start();
remoting/src/test/java/remoting/amfclient/ClientCustomType.java+1 −1 renamed@@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package amfclient; +package remoting.amfclient; /** * The client side object used by the AMFConnectionIT. There is a corresponding
remoting/src/test/resources/WEB-INF/flex/services-config-customized-validation.xml+65 −0 added@@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<services-config> + + <validators> + <validator class="flex.messaging.validators.ClassDeserializationValidator"> + <properties> + <allow-classes> + <class name="remoting.amfclient.ClientCustomType"/> + <class name="remoting.amfclient.ServerCustomType"/> + </allow-classes> + </properties> + </validator> + </validators> + + <services> + <service-include file-path="remoting-config.xml" /> + </services> + + <channels> + <channel-definition id="amf" class="mx.messaging.channels.AMFChannel"> + <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/> + <properties> + <serialization> + <allow-xml>true</allow-xml> + </serialization> + </properties> + </channel-definition> + </channels> + + <logging> + <target class="flex.messaging.log.ConsoleTarget" level="Error"> + <properties> + <prefix>[BlazeDS] </prefix> + <includeDate>false</includeDate> + <includeTime>false</includeTime> + <includeLevel>false</includeLevel> + <includeCategory>false</includeCategory> + </properties> + <filters> + <pattern>Endpoint.*</pattern> + <pattern>Service.*</pattern> + <pattern>Configuration</pattern> + </filters> + </target> + </logging> + +</services-config>
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
17- github.com/advisories/GHSA-w8v7-prhw-xjpwghsaADVISORY
- issues.apache.org/jira/browse/FLEX-35290nvdIssue TrackingVendor AdvisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2017-5641ghsaADVISORY
- support.hpe.com/hpsc/doc/public/displaynvdThird Party AdvisoryWEB
- www.kb.cert.org/vuls/id/307983nvdThird Party AdvisoryUS Government ResourceWEB
- www.zerodayinitiative.com/advisories/ZDI-22-506/nvdThird Party AdvisoryVDB Entry
- www.zerodayinitiative.com/advisories/ZDI-22-507/nvdThird Party AdvisoryVDB Entry
- mail-archives.apache.org/mod_mbox/flex-dev/201703.mbox/%3C6B86C8D0-6E36-48F5-AC81-4AB3978F6746@c-ware.de%3EghsaWEB
- www.securityfocus.com/bid/97383nvdBroken Link
- www.securitytracker.com/id/1038273nvdBroken Link
- github.com/apache/flex-blazeds/commit/11b0aa132d9a43bf81fa12654ff227ff247b4627ghsaWEB
- github.com/apache/flex-blazeds/commit/f861f0993c35e664906609cad275e45a71e2aaf1ghsaWEB
- web.archive.org/web/20170920093830/http://www.securitytracker.com/id/1038273ghsaWEB
- web.archive.org/web/20210124021605/http://www.securityfocus.com/bid/97383ghsaWEB
- www.zerodayinitiative.com/advisories/ZDI-22-506ghsaWEB
- www.zerodayinitiative.com/advisories/ZDI-22-507ghsaWEB
- mail-archives.apache.org/mod_mbox/flex-dev/201703.mbox/%3C6B86C8D0-6E36-48F5-AC81-4AB3978F6746%40c-ware.de%3Envd
News mentions
0No linked articles in our index yet.