This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch 4.1.x-fixes in repository https://gitbox.apache.org/repos/asf/cxf.git
commit e892f633f4db7c5f2462dd616f9f85b351476ea4 Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Mon Jul 27 15:34:19 2026 +0100 Disable JMS ObjectMessage deserialization by default (#3337) (cherry picked from commit 7f4cb4e3b765e632216fb7fc8acfa2c64e2179bf) --- .../org/apache/cxf/transport/jms/JMSConduit.java | 3 +- .../apache/cxf/transport/jms/JMSConfigFactory.java | 2 + .../apache/cxf/transport/jms/JMSConfiguration.java | 29 ++++++++++++ .../apache/cxf/transport/jms/JMSDestination.java | 4 +- .../apache/cxf/transport/jms/JMSMessageUtils.java | 15 ++++-- .../apache/cxf/transport/jms/uri/JMSEndpoint.java | 26 ++++++++++ .../transport/jms/util/JMSMessageConverter.java | 13 +++++ .../cxf/transport/jms/JMSConfigFactoryTest.java | 14 ++++++ .../cxf/transport/jms/uri/JMSEndpointTest.java | 24 ++++++++++ .../jms/util/JMSMessageConverterTest.java | 55 ++++++++++++++++++++++ .../apache/cxf/transport/jms/util/JMSUtilTest.java | 11 +++-- 11 files changed, 187 insertions(+), 9 deletions(-) diff --git a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConduit.java b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConduit.java index 41d3377a72d..4f8db4a28cb 100644 --- a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConduit.java +++ b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConduit.java @@ -472,7 +472,8 @@ public class JMSConduit extends AbstractConduit implements JMSExchangeSender, Me LOG.log(Level.FINE, "client received reply: ", jmsMessage); try { Message inMessage = JMSMessageUtils.asCXFMessage(jmsMessage, - JMSConstants.JMS_CLIENT_RESPONSE_HEADERS); + JMSConstants.JMS_CLIENT_RESPONSE_HEADERS, + jmsConfig.isAllowObjectMessages()); if (jmsConfig.isCreateSecurityContext()) { SecurityContext securityContext = SecurityContextFactory.buildSecurityContext(jmsMessage, jmsConfig); inMessage.put(SecurityContext.class, securityContext); diff --git a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConfigFactory.java b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConfigFactory.java index 5a95b40d406..2cfe46df416 100644 --- a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConfigFactory.java +++ b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConfigFactory.java @@ -83,6 +83,8 @@ public final class JMSConfigFactory { jmsConfig.setConcurrentConsumers(endpoint.getConcurrentConsumers()); jmsConfig.setOneSessionPerConnection(endpoint.isOneSessionPerConnection()); jmsConfig.setMessageSelector(endpoint.getMessageSelector()); + jmsConfig.setUseObjectMessageFallback(endpoint.isUseObjectMessageFallback()); + jmsConfig.setAllowObjectMessages(endpoint.isAllowObjectMessages()); TransactionManager tm = getTransactionManager(bus, endpoint); jmsConfig.setTransactionManager(tm); diff --git a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConfiguration.java b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConfiguration.java index b72a111885d..e6cbb9da07f 100644 --- a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConfiguration.java +++ b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSConfiguration.java @@ -87,7 +87,16 @@ public class JMSConfiguration { private volatile Destination replyToDestinationDest; private String messageType = JMSConstants.TEXT_MESSAGE_TYPE; + /** + * Outbound only: when true, non-text payloads may fall back to ObjectMessage. + * When false, non-text payloads are sent as BytesMessage. + */ private boolean useObjectMessageFallback; + /** + * Inbound only: when true, ObjectMessage deserialization is allowed. + * When false, inbound ObjectMessage is rejected. + */ + private boolean allowObjectMessages; private boolean pubSubDomain; private boolean replyPubSubDomain; @@ -285,14 +294,34 @@ public class JMSConfiguration { this.messageType = messageType; } + /** + * Outbound only: controls ObjectMessage fallback in payload creation. + */ public boolean isUseObjectMessageFallback() { return useObjectMessageFallback; } + /** + * Outbound only: controls ObjectMessage fallback in payload creation. + */ public void setUseObjectMessageFallback(boolean useObjectMessageFallback) { this.useObjectMessageFallback = useObjectMessageFallback; } + /** + * Inbound only: controls whether ObjectMessage deserialization is permitted. + */ + public boolean isAllowObjectMessages() { + return allowObjectMessages; + } + + /** + * Inbound only: controls whether ObjectMessage deserialization is permitted. + */ + public void setAllowObjectMessages(boolean allowObjectMessages) { + this.allowObjectMessages = allowObjectMessages; + } + public boolean isPubSubDomain() { return pubSubDomain; } diff --git a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSDestination.java b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSDestination.java index 1430d80f9f7..a54c265afe3 100644 --- a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSDestination.java +++ b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSDestination.java @@ -228,7 +228,9 @@ public class JMSDestination extends AbstractMultiplexDestination implements Mess getLogger().log(Level.FINE, "JMS destination received message " + message + " on " + jmsConfig.getTargetDestination()); - Message inMessage = JMSMessageUtils.asCXFMessage(message, JMSConstants.JMS_SERVER_REQUEST_HEADERS); + Message inMessage = JMSMessageUtils.asCXFMessage(message, + JMSConstants.JMS_SERVER_REQUEST_HEADERS, + jmsConfig.isAllowObjectMessages()); if (jmsConfig.isCreateSecurityContext()) { SecurityContext securityContext = SecurityContextFactory.buildSecurityContext(message, jmsConfig); inMessage.put(SecurityContext.class, securityContext); diff --git a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSMessageUtils.java b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSMessageUtils.java index 5e28ebbad4c..4a5c80232c2 100644 --- a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSMessageUtils.java +++ b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/JMSMessageUtils.java @@ -58,11 +58,18 @@ final class JMSMessageUtils { } public static org.apache.cxf.message.Message asCXFMessage(Message message, String jmsHeadersKey) throws UnsupportedEncodingException, JMSException { + return asCXFMessage(message, jmsHeadersKey, false); + } + + public static org.apache.cxf.message.Message asCXFMessage(Message message, + String jmsHeadersKey, + boolean allowObjectMessage) + throws UnsupportedEncodingException, JMSException { org.apache.cxf.message.Message inMessage = new MessageImpl(); JMSMessageHeadersType messageHeaders = JMSMessageHeadersType.from(message); inMessage.put(jmsHeadersKey, messageHeaders); populateIncomingContext(messageHeaders, inMessage); - retrieveAndSetPayload(inMessage, message); + retrieveAndSetPayload(inMessage, message, allowObjectMessage); return inMessage; } @@ -74,10 +81,12 @@ final class JMSMessageUtils { * @throws UnsupportedEncodingException * @throws JMSException */ - private static void retrieveAndSetPayload(org.apache.cxf.message.Message inMessage, Message message) + private static void retrieveAndSetPayload(org.apache.cxf.message.Message inMessage, + Message message, + boolean allowObjectMessage) throws UnsupportedEncodingException, JMSException { final String messageType; - Object converted = new JMSMessageConverter().fromMessage(message); + Object converted = new JMSMessageConverter(allowObjectMessage).fromMessage(message); if (converted instanceof String) { inMessage.setContent(Reader.class, new StringReader((String)converted)); messageType = JMSConstants.TEXT_MESSAGE_TYPE; diff --git a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/uri/JMSEndpoint.java b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/uri/JMSEndpoint.java index a05571d67ac..886e5317a95 100644 --- a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/uri/JMSEndpoint.java +++ b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/uri/JMSEndpoint.java @@ -89,6 +89,8 @@ public class JMSEndpoint { private int retryInterval = 5000; private boolean oneSessionPerConnection; private boolean ignoreTimeoutException; + private boolean useObjectMessageFallback; + private boolean allowObjectMessages; /** * @param endpointUri @@ -517,4 +519,28 @@ public class JMSEndpoint { this.ignoreTimeoutException = ignoreTimeoutException; } + public boolean isAllowObjectMessages() { + return allowObjectMessages; + } + + public void setAllowObjectMessages(boolean allowObjectMessages) { + this.allowObjectMessages = allowObjectMessages; + } + + public void setAllowObjectMessages(String allowObjectMessages) { + this.allowObjectMessages = Boolean.parseBoolean(allowObjectMessages); + } + + public boolean isUseObjectMessageFallback() { + return useObjectMessageFallback; + } + + public void setUseObjectMessageFallback(boolean useObjectMessageFallback) { + this.useObjectMessageFallback = useObjectMessageFallback; + } + + public void setUseObjectMessageFallback(String useObjectMessageFallback) { + this.useObjectMessageFallback = Boolean.parseBoolean(useObjectMessageFallback); + } + } diff --git a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/util/JMSMessageConverter.java b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/util/JMSMessageConverter.java index c25287366a7..9744fefac5e 100644 --- a/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/util/JMSMessageConverter.java +++ b/rt/transports/jms/src/main/java/org/apache/cxf/transport/jms/util/JMSMessageConverter.java @@ -37,6 +37,16 @@ import jakarta.jms.TextMessage; */ public class JMSMessageConverter { + private final boolean allowObjectMessage; + + public JMSMessageConverter() { + this(false); + } + + public JMSMessageConverter(boolean allowObjectMessage) { + this.allowObjectMessage = allowObjectMessage; + } + public Message toMessage(Object object, Session session) throws JMSException { if (object instanceof Message) { return (Message)object; @@ -67,6 +77,9 @@ public class JMSMessageConverter { message1.readBytes(bytes); return bytes; } else if (message instanceof ObjectMessage) { + if (!allowObjectMessage) { + throw new JMSException("ObjectMessage is disabled by configuration"); + } return ((ObjectMessage)message).getObject(); } else if (message instanceof StreamMessage) { StreamMessage streamMessage = (StreamMessage)message; diff --git a/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/JMSConfigFactoryTest.java b/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/JMSConfigFactoryTest.java index 0c4af03be86..ffcdca0a119 100644 --- a/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/JMSConfigFactoryTest.java +++ b/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/JMSConfigFactoryTest.java @@ -136,4 +136,18 @@ public class JMSConfigFactoryTest extends AbstractJMSTester { JMSConfiguration config = JMSConfigFactory.createFromEndpointInfo(bus, ei, null); Assert.assertEquals("customJMSAttribute=helloWorld", config.getMessageSelector()); } + + @Test + public void testUseObjectMessageFallbackIsSet() { + JMSEndpoint endpoint = new JMSEndpoint("jms:queue:Foo.Bar?useObjectMessageFallback=true"); + JMSConfiguration jmsConfig = JMSConfigFactory.createFromEndpoint(bus, endpoint); + Assert.assertTrue(jmsConfig.isUseObjectMessageFallback()); + } + + @Test + public void testAllowObjectMessagesIsSet() { + JMSEndpoint endpoint = new JMSEndpoint("jms:queue:Foo.Bar?allowObjectMessages=true"); + JMSConfiguration jmsConfig = JMSConfigFactory.createFromEndpoint(bus, endpoint); + Assert.assertTrue(jmsConfig.isAllowObjectMessages()); + } } diff --git a/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/uri/JMSEndpointTest.java b/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/uri/JMSEndpointTest.java index bc9b4400929..158d81633fa 100644 --- a/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/uri/JMSEndpointTest.java +++ b/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/uri/JMSEndpointTest.java @@ -190,6 +190,30 @@ public class JMSEndpointTest { } + @Test + public void testAllowObjectMessagesDefaultsToFalse() { + JMSEndpoint endpoint = new JMSEndpoint("jms:queue:Foo.Bar"); + assertFalse(endpoint.isAllowObjectMessages()); + } + + @Test + public void testAllowObjectMessagesCanBeEnabledFromUri() { + JMSEndpoint endpoint = new JMSEndpoint("jms:queue:Foo.Bar?allowObjectMessages=true"); + assertTrue(endpoint.isAllowObjectMessages()); + } + + @Test + public void testUseObjectMessageFallbackDefaultsToFalse() { + JMSEndpoint endpoint = new JMSEndpoint("jms:queue:Foo.Bar"); + assertFalse(endpoint.isUseObjectMessageFallback()); + } + + @Test + public void testUseObjectMessageFallbackCanBeEnabledFromUri() { + JMSEndpoint endpoint = new JMSEndpoint("jms:queue:Foo.Bar?useObjectMessageFallback=true"); + assertTrue(endpoint.isUseObjectMessageFallback()); + } + @Test public void nonSoapJMS() throws Exception { JMSEndpoint endpoint = new JMSEndpoint("jms://"); diff --git a/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/util/JMSMessageConverterTest.java b/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/util/JMSMessageConverterTest.java new file mode 100644 index 00000000000..8e08d33d17a --- /dev/null +++ b/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/util/JMSMessageConverterTest.java @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cxf.transport.jms.util; + +import jakarta.jms.JMSException; +import jakarta.jms.ObjectMessage; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class JMSMessageConverterTest { + + @Test + public void testObjectMessageIsRejectedByDefault() throws Exception { + JMSMessageConverter converter = new JMSMessageConverter(); + ObjectMessage objectMessage = mock(ObjectMessage.class); + + try { + converter.fromMessage(objectMessage); + fail("Expected JMSException to be thrown"); + } catch (JMSException ex) { + assertEquals("ObjectMessage is disabled by configuration", ex.getMessage()); + } + } + + @Test + public void testObjectMessageCanBeEnabled() throws Exception { + JMSMessageConverter converter = new JMSMessageConverter(true); + ObjectMessage objectMessage = mock(ObjectMessage.class); + when(objectMessage.getObject()).thenReturn("payload"); + + Object payload = converter.fromMessage(objectMessage); + assertEquals("payload", payload); + } +} diff --git a/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/util/JMSUtilTest.java b/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/util/JMSUtilTest.java index 5345b9bf540..b66ed47ddeb 100644 --- a/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/util/JMSUtilTest.java +++ b/rt/transports/jms/src/test/java/org/apache/cxf/transport/jms/util/JMSUtilTest.java @@ -83,14 +83,17 @@ public class JMSUtilTest { Connection connection = JMSFactory.createConnection(jmsConfig); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); jakarta.jms.Message jmsMessage = - JMSUtil.createAndSetPayload(testBytes, session, JMSConstants.BYTE_MESSAGE_TYPE); + JMSUtil.createAndSetPayload(testBytes, session, JMSConstants.BYTE_MESSAGE_TYPE, false); assertTrue("Message should have been of type BytesMessage ", jmsMessage instanceof BytesMessage); - jmsMessage = JMSUtil.createAndSetPayload(testBytes, session, JMSConstants.BINARY_MESSAGE_TYPE); - assertTrue("Binary message fallback should have been of type ObjectMessage ", - jmsMessage instanceof ObjectMessage); + jmsMessage = JMSUtil.createAndSetPayload(testBytes, session, JMSConstants.BINARY_MESSAGE_TYPE, false); + assertTrue("Default binary message should have been of type BytesMessage ", + jmsMessage instanceof BytesMessage); jmsMessage = JMSUtil.createAndSetPayload(testBytes, session, JMSConstants.BINARY_MESSAGE_TYPE, false); assertTrue("Fallback-disabled binary message should have been of type BytesMessage ", jmsMessage instanceof BytesMessage); + jmsMessage = JMSUtil.createAndSetPayload(testBytes, session, JMSConstants.BINARY_MESSAGE_TYPE, true); + assertTrue("Fallback-enabled binary message should have been of type ObjectMessage ", + jmsMessage instanceof ObjectMessage); jmsMessage = JMSUtil.createAndSetPayload(testBytes, session, "application/octet-stream", true); assertTrue("Non-text message fallback should have been of type ObjectMessage ", jmsMessage instanceof ObjectMessage);
