Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

W-14487260 #526

Draft
wants to merge 34 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
54bc5e0
added tests for new host verification scenarios
sabecasismulesoft Nov 16, 2023
14459d4
some tests
sabecasismulesoft Nov 17, 2023
1e16005
Adding verifyHostName property to the brokerURL
sabecasismulesoft Nov 17, 2023
495f0e5
created default value to fix vulnerability
sabecasismulesoft Nov 22, 2023
16d3d80
refactored code
sabecasismulesoft Nov 22, 2023
4ee3b60
applied format
sabecasismulesoft Nov 22, 2023
b3b360a
removed duplicate mule sdk version
sabecasismulesoft Nov 22, 2023
cd7234f
forced spring core library to let activeMq client version work as exp…
sabecasismulesoft Nov 24, 2023
058025c
removed explicit spring version
sabecasismulesoft Nov 24, 2023
974b3e6
forced dependencies
sabecasismulesoft Nov 26, 2023
9832400
added new spring core and spring jms versions
sabecasismulesoft Nov 27, 2023
dc85421
restored proper order of dependencies
sabecasismulesoft Nov 27, 2023
9f6636a
Merge branch 'main' into fix/W-14487260
sabecasismulesoft Nov 28, 2023
7c5cee3
W-14487260 set xaAckMode
sabecasismulesoft Nov 28, 2023
37d24bf
W-14487260 set xaAckMode
sabecasismulesoft Nov 28, 2023
17f1d4c
removed spring-jms dependency
sabecasismulesoft Nov 28, 2023
3b34bcf
Added XA ack mode enum
sabecasismulesoft Nov 29, 2023
35308e1
[W-14544171] send-message-through-SSL test fix after activemq version…
sabecasismulesoft Nov 29, 2023
b2191f0
added tests for new host verification scenarios
sabecasismulesoft Nov 16, 2023
9f84ab0
some tests
sabecasismulesoft Nov 17, 2023
b819712
Adding verifyHostName property to the brokerURL
sabecasismulesoft Nov 17, 2023
3ad5c57
created default value to fix vulnerability
sabecasismulesoft Nov 22, 2023
9d3f1dc
refactored code
sabecasismulesoft Nov 22, 2023
39dc00e
applied format
sabecasismulesoft Nov 22, 2023
1d3674a
forced dependencies
sabecasismulesoft Nov 26, 2023
6946cff
added new spring core and spring jms versions
sabecasismulesoft Nov 27, 2023
2c46c39
W-14487260 set xaAckMode
sabecasismulesoft Nov 28, 2023
1e75ba7
removed spring-jms dependency
sabecasismulesoft Nov 28, 2023
8f930ab
Added XA ack mode enum
sabecasismulesoft Nov 29, 2023
8e41b0a
Merge branch 'main' into fix/W-14487260
sabecasismulesoft Nov 29, 2023
d2717c1
formatted code
sabecasismulesoft Nov 29, 2023
3144075
added documentation and description
sabecasismulesoft Nov 29, 2023
9e3b446
added verifyHostName=false to tests
sabecasismulesoft Nov 29, 2023
75e5181
Added verifyHostName=true test scenario
sabecasismulesoft Nov 30, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<description>Mule connector lets you easily send and receive messages to queues and topics for any message service which implements the JMS specification</description>

<properties>
<activemq.version>5.15.16</activemq.version>
<activemq.version>5.16.4</activemq.version>
<artemisVersion>2.25.0</artemisVersion>
<javaxJmsApiVersion>2.0.1</javaxJmsApiVersion>
<commonsIoVersion>2.11.0</commonsIoVersion>
Expand Down
35 changes: 35 additions & 0 deletions src/main/java/org/mule/extensions/jms/api/ack/XaAckMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2023 Salesforce, Inc. All rights reserved.
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.extensions.jms.api.ack;

import org.mule.jms.commons.internal.config.InternalAckMode;

import javax.jms.Session;

import static org.mule.runtime.extension.api.values.ValueBuilder.newValue;

import java.util.Set;

public enum XaAckMode {

SESSION_TRANSACTED(Session.SESSION_TRANSACTED), AUTO_ACKNOWLEDGE(Session.AUTO_ACKNOWLEDGE), CLIENT_ACKNOWLEDGE(
Session.CLIENT_ACKNOWLEDGE), DUPS_OK_ACKNOWLEDGE(Session.DUPS_OK_ACKNOWLEDGE);

private int ackMode;

XaAckMode(int ackMode) {
this.ackMode = ackMode;
}

public int getAckMode() {
return ackMode;
}

public void setAckMode(int ackMode) {
this.ackMode = ackMode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
package org.mule.extensions.jms.api.connection.factory.activemq;

import static org.mule.runtime.api.meta.ExpressionSupport.NOT_SUPPORTED;

import org.mule.extensions.jms.api.ack.XaAckMode;
import org.mule.runtime.extension.api.annotation.Alias;
import org.mule.runtime.extension.api.annotation.Expression;
import org.mule.runtime.extension.api.annotation.param.Optional;
import org.mule.runtime.extension.api.annotation.param.Parameter;
import org.mule.runtime.extension.api.annotation.param.display.DisplayName;
import org.mule.runtime.extension.api.annotation.param.display.Example;
import org.mule.runtime.extension.api.annotation.param.display.Summary;
import org.mule.sdk.api.annotation.semantics.connectivity.ExcludeFromConnectivitySchema;
Expand Down Expand Up @@ -52,6 +55,19 @@ public class ActiveMQConnectionFactoryConfiguration {
@Expression(NOT_SUPPORTED)
private boolean enableXA;

/**
* Indicates how ACK is going to be handled in an XA Session.
* Since ActiveMQ version 5.16.0 this value is mandatory for XA sessions without an XA transaction associated.
* The possible value is one of the fields available in {@link "https://docs.oracle.com/javaee/6/api/javax/jms/Session.html?is-external=true#AUTO_ACKNOWLEDGE"}
*/
@DisplayName("XA ack mode")
@Parameter
@Optional(defaultValue = "AUTO_ACKNOWLEDGE")
@Summary("Indicates how ACK is going to be handled in an XA Session.")
@Expression(NOT_SUPPORTED)
@ExcludeFromConnectivitySchema
private XaAckMode xaAckMode;

/**
* Used to configure the {@link RedeliveryPolicy#getInitialRedeliveryDelay()}
*/
Expand Down Expand Up @@ -106,6 +122,19 @@ public class ActiveMQConnectionFactoryConfiguration {
@ExcludeFromConnectivitySchema
private boolean trustAllPackages;

/**
* Indicates whether an SSL connection socket must verify the broker URL hostname matches the CN value in the
* TSL certificate.
* Starting with version 5.15.6 ActiveMQ requires you to explicitly set this value.
*/
@Parameter
@Optional(defaultValue = "false")
@Summary("Indicates whether an SSL connection socket must verify the broker URL hostname matches the CN value in " +
"the TSL certificate. \n We recommend setting this value to true.")
@Expression(NOT_SUPPORTED)
@ExcludeFromConnectivitySchema
@DisplayName("Verify hostname")
private boolean verifyHostName;

public int getMaxRedelivery() {
return maxRedelivery;
Expand Down Expand Up @@ -163,18 +192,25 @@ public boolean isTrustAllPackages() {
return trustAllPackages;
}

public boolean getTrustAllPackages() {
return trustAllPackages;
}

public void setTrustAllPackages(boolean trustAllPackages) {
this.trustAllPackages = trustAllPackages;
}

public boolean getVerifyHostName() {
//TODO: change the default value to a parameter. This default is required to support a security fix and avoid
// breaking backwards compatibility (GUS ticket: W-14487260)
return false;
return verifyHostName;
}

public void setVerifyHostName(boolean verifyHostName) {
this.verifyHostName = verifyHostName;
}

public XaAckMode getXaAckMode() {
return xaAckMode;
}

public void setXaAckMode(XaAckMode xaAckMode) {
this.xaAckMode = xaAckMode;
}


Expand All @@ -190,13 +226,15 @@ public boolean equals(Object o) {
redeliveryDelay == that.redeliveryDelay &&
maxRedelivery == that.maxRedelivery &&
trustAllPackages == that.trustAllPackages &&
verifyHostName == that.verifyHostName &&
xaAckMode == that.xaAckMode &&
Objects.equals(brokerUrl, that.brokerUrl) &&
Objects.equals(trustedPackages, that.trustedPackages);
}

@Override
public int hashCode() {
return Objects.hash(brokerUrl, enableXA, initialRedeliveryDelay, redeliveryDelay, maxRedelivery, trustedPackages,
trustAllPackages);
trustAllPackages, verifyHostName, xaAckMode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ public class ActiveMQConnectionFactoryProvider {
private static final String ACTIVEMQ_XA_SSL_CONNECTION_FACTORY_CLASS = "org.apache.activemq.ActiveMQXASslConnectionFactory";

private static final int REDELIVERY_IGNORE = -1;

private static final String VERIFY_HOSTNAME = "socket.verifyHostName";

/**
* Parameters required to configure a default {@link ActiveMQConnectionFactory}
*/
Expand Down Expand Up @@ -121,11 +121,28 @@ private void applyVendorSpecificConnectionFactoryProperties(ConnectionFactory co
setRedeliveryDelay(redeliveryPolicy);
setTrustedPackages(connectionFactory);
setTrustAllPackages(connectionFactory);
setXAAckMode(connectionFactory, factoryConfiguration.getXaAckMode().getAckMode());
} catch (Exception e) {
LOGGER.error("Failed to set custom ConnectionFactoryProperties for ActiveMQ RedeliveryPolicy: " + e.getMessage(), e);
}
}

private void setXAAckMode(ConnectionFactory factory,
int xaAckMode)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
String factoryClassName = factory.getClass().getCanonicalName();
if (isActiveMqXaFactory(factoryClassName)) {
Class[] parameters = new Class[1];
parameters[0] = int.class;
factory.getClass().getMethod("setXaAckMode", parameters).invoke(factory, xaAckMode);
}
}

private boolean isActiveMqXaFactory(String factoryClassName) {
return factoryClassName == ACTIVEMQ_XA_CONNECTION_FACTORY_CLASS ||
factoryClassName == ACTIVEMQ_XA_SSL_CONNECTION_FACTORY_CLASS;
}

private String setPropertiesInURL(String brokerURL, String factoryClass,
ActiveMQConnectionFactoryConfiguration factoryConfiguration)
throws URISyntaxException {
Expand Down
38 changes: 32 additions & 6 deletions src/test/munit/activemq-over-ssl-test-case.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,56 @@

<munit:config name="activemq-over-ssl-test-case" minMuleVersion="4.3.0">
<munit:parameterizations>
<munit:parameterization name="invalid-broker-url">
<munit:parameterization name="invalid-broker-url-default">
<munit:parameters>
<!-- a valid ip which is not the host defined in the CN for the TSL connection certificate -->
<munit:parameter propertyName="brokerUrl" value="ssl://0.0.0.0:${activemq.port}"/>
<munit:parameter propertyName="config" value="config-with-ssl-default"/>
</munit:parameters>
</munit:parameterization>
<munit:parameterization name="valid-broker-url">
<munit:parameterization name="valid-broker-url-default">
<munit:parameters>
<!-- a host which is not the one defined in the CN for the TSL connection certificate -->
<munit:parameter propertyName="brokerUrl" value="ssl://localhost:${activemq.port}"/>
<munit:parameter propertyName="config" value="config-with-ssl-default"/>
</munit:parameters>
</munit:parameterization>
<munit:parameterization name="invalid-broker-url-false">
<munit:parameters>
<!-- a valid ip which is not the host defined in the CN for the TSL connection certificate -->
<munit:parameter propertyName="brokerUrl" value="ssl://0.0.0.0:${activemq.port}"/>
<munit:parameter propertyName="config" value="config-with-ssl-default"/>
</munit:parameters>
</munit:parameterization>
<munit:parameterization name="valid-broker-url-false">
<munit:parameters>
<!-- a host which is not the one defined in the CN for the TSL connection certificate -->
<munit:parameter propertyName="brokerUrl" value="ssl://localhost:${activemq.port}"/>
<munit:parameter propertyName="config" value="config-with-ssl-default"/>
</munit:parameters>
</munit:parameterization>
</munit:parameterizations>
</munit:config>

<munit:dynamic-port propertyName="activemq.port"/>

<jms:config name="config-with-ssl">
<jms:config name="config-with-ssl-default">
<jms:active-mq-connection>
<tls:context >
<tls:trust-store insecure="true" />
<tls:key-store type="jks" path="tls/client.ks" keyPassword="password" password="password" algorithm="PKIX"/>
</tls:context>
<jms:factory-configuration brokerUrl="${brokerUrl}"/>
</jms:active-mq-connection>
</jms:config>

<jms:config name="config-with-ssl-false">
<jms:active-mq-connection>
<tls:context >
<tls:trust-store insecure="true" />
<tls:key-store type="jks" path="tls/client.ks" keyPassword="password" password="password" algorithm="PKIX"/>
</tls:context>
<jms:factory-configuration brokerUrl="${brokerUrl}" />
<jms:factory-configuration brokerUrl="${brokerUrl}" verifyHostName="false"/>
</jms:active-mq-connection>
</jms:config>

Expand All @@ -61,12 +87,12 @@
<munit:test name="send-message-through-SSL">
<munit:execution>
<set-variable variableName="message" value="#[&quot;I'm a secure message&quot;]"/>
<jms:publish config-ref="config-with-ssl" destination="someDest">
<jms:publish config-ref="${config}" destination="someDest">
<jms:message>
<jms:body>#[vars.message]</jms:body>
</jms:message>
</jms:publish>
<jms:consume config-ref="config-with-ssl" destination="someDest"/>
<jms:consume config-ref="${config}" destination="someDest"/>
</munit:execution>
<munit:validation>
<munit-tools:assert-that expression="#[payload]" is="#[MunitTools::equalTo(vars.message)]"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jms="http://www.mulesoft.org/schema/mule/jms"
xmlns:java="http://www.mulesoft.org/schema/mule/java"
xmlns:munit-tools="http://www.mulesoft.org/schema/mule/munit-tools"
xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:tls="http://www.mulesoft.org/schema/mule/tls"
xmlns:munit="http://www.mulesoft.org/schema/mule/munit"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/jms http://www.mulesoft.org/schema/mule/jms/current/mule-jms.xsd
http://www.mulesoft.org/schema/mule/tls http://www.mulesoft.org/schema/mule/tls/current/mule-tls.xsd
http://www.mulesoft.org/schema/mule/munit-tools http://www.mulesoft.org/schema/mule/munit-tools/current/mule-munit-tools.xsd
http://www.mulesoft.org/schema/mule/java http://www.mulesoft.org/schema/mule/java/current/mule-java.xsd
http://www.mulesoft.org/schema/mule/munit http://www.mulesoft.org/schema/mule/munit/current/mule-munit.xsd">

<munit:config name="activemq-over-ssl-test-case" minMuleVersion="4.3.0"/>

<munit:dynamic-port propertyName="activemq.port"/>

<jms:config name="config-with-ssl">
<jms:active-mq-connection>
<tls:context >
<tls:trust-store insecure="true" />
<tls:key-store type="jks" path="tls/client.ks" keyPassword="password" password="password" algorithm="PKIX"/>
</tls:context>
<jms:factory-configuration brokerUrl="ssl://0.0.0.0:${activemq.port}" verifyHostName="true"/>
</jms:active-mq-connection>
</jms:config>

<munit:before-suite name="setUpServer">
<java:invoke-static class="org.mule.extensions.jms.test.ActiveMQSSLServer" method="start(String)">
<java:args >#[{ port : p('activemq.port') }]</java:args>
</java:invoke-static>
</munit:before-suite>

<munit:after-suite name="tearDown">
<java:invoke-static class="org.mule.extensions.jms.test.ActiveMQSSLServer" method="stop()"/>
</munit:after-suite>

<munit:after-test name="afterTest-activemq-over-ssl-test-case" description="after test">
<set-variable variableName="brokerName" value="localhost"/>
<set-variable variableName="destinationName" value="someDest"/>
<flow-ref name="purgeQueue"/>
</munit:after-test>

<munit:test name="send-message-through-SSL" expectedException="org.mule.runtime.api.connection.ConnectionException">
<munit:execution>
<set-variable variableName="message" value="#[&quot;I'm a secure message&quot;]"/>
<jms:publish config-ref="config-with-ssl" destination="someDest">
<jms:message>
<jms:body>#[vars.message]</jms:body>
</jms:message>
</jms:publish>
<jms:consume config-ref="config-with-ssl" destination="someDest"/>
</munit:execution>
<munit:validation>
<munit-tools:assert-that expression="#[payload]" is="#[MunitTools::equalTo(vars.message)]"/>
</munit:validation>
</munit:test>

</mule>