This is an automated email from the ASF dual-hosted git repository.
robbie pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git
The following commit(s) were added to refs/heads/main by this push:
new 8250e611df ARTEMIS-4963 Check send auth on openwire producer create
8250e611df is described below
commit 8250e611dfac7ec9b1353a636464fbdc877a8ec1
Author: Timothy Bish <[email protected]>
AuthorDate: Fri Aug 2 10:56:28 2024 -0400
ARTEMIS-4963 Check send auth on openwire producer create
Check that an attaching Openwire producer has SEND permission on the target
destination and reject it if it does not instead of delaying checks until
the
actual send. For anonymous producers check early in the send process to
reduce
overhead in the JVM handling messages that are going to fail to send.
---
.../core/protocol/openwire/OpenWireConnection.java | 19 +-
.../core/protocol/openwire/amq/AMQSession.java | 30 +
.../integration/openwire/BasicSecurityTest.java | 93 ++-
.../integration/openwire/SecurityOpenWireTest.java | 669 ++++++++++++++++++++-
4 files changed, 768 insertions(+), 43 deletions(-)
diff --git
a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireConnection.java
b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireConnection.java
index 733a60f82f..28f7a46662 100644
---
a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireConnection.java
+++
b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireConnection.java
@@ -1256,18 +1256,21 @@ public class OpenWireConnection extends
AbstractRemotingConnection implements Se
// Avoid replaying dup commands
if (!ss.getProducerIds().contains(info.getProducerId())) {
- ActiveMQDestination destination = info.getDestination();
+ final ActiveMQDestination destination = info.getDestination();
+ final AMQSession session =
getSession(info.getProducerId().getParentId());
- if (destination != null &&
!AdvisorySupport.isAdvisoryTopic(destination)) {
- OpenWireConnection.this.addDestination(new
DestinationInfo(getContext().getConnectionId(),
DestinationInfo.ADD_OPERATION_TYPE, destination));
+ if (destination != null) {
+ session.checkDestinationForSendPermission(destination);
+
+ if (!AdvisorySupport.isAdvisoryTopic(destination)) {
+ OpenWireConnection.this.addDestination(new
DestinationInfo(getContext().getConnectionId(),
DestinationInfo.ADD_OPERATION_TYPE, destination));
+ }
}
ss.addProducer(info);
-
getSession(info.getProducerId().getParentId()).getCoreSession().addProducer(
- info.getProducerId().toString(),
- OpenWireProtocolManagerFactory.OPENWIRE_PROTOCOL_NAME,
- info.getDestination() != null ?
info.getDestination().getPhysicalName() : null);
-
+
session.getCoreSession().addProducer(info.getProducerId().toString(),
+
OpenWireProtocolManagerFactory.OPENWIRE_PROTOCOL_NAME,
+ info.getDestination() != null
? info.getDestination().getPhysicalName() : null);
}
return null;
}
diff --git
a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQSession.java
b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQSession.java
index f073ee9c51..80c6cc1666 100644
---
a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQSession.java
+++
b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/amq/AMQSession.java
@@ -37,6 +37,7 @@ import
org.apache.activemq.artemis.core.protocol.openwire.OpenWireConnection;
import
org.apache.activemq.artemis.core.protocol.openwire.OpenWireMessageConverter;
import
org.apache.activemq.artemis.core.protocol.openwire.OpenWireProtocolManager;
import org.apache.activemq.artemis.core.protocol.openwire.util.OpenWireUtil;
+import org.apache.activemq.artemis.core.security.CheckType;
import org.apache.activemq.artemis.core.server.ActiveMQMessageBundle;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.MessageReference;
@@ -364,6 +365,14 @@ public class AMQSession implements SessionCallback {
final ActiveMQDestination destination = messageSend.getDestination();
+ if (producerInfo.getDestination() == null) {
+ // a named producer will have its target destination checked on
create but an
+ // anonymous producer can send to different addresses on each send so
we need to
+ // check here before going into message conversion and pre-dispatch
stages before
+ // the target gets a security check.
+ checkDestinationForSendPermission(destination);
+ }
+
final ActiveMQDestination[] actualDestinations;
final int actualDestinationsCount;
if (destination.isComposite()) {
@@ -568,4 +577,25 @@ public class AMQSession implements SessionCallback {
public boolean isInternal() {
return sessInfo.getSessionId().getValue() == -1;
}
+
+ public void checkDestinationForSendPermission(ActiveMQDestination
destination) throws Exception {
+ if (server.getSecurityStore().isSecurityEnabled()) {
+ if (destination.isComposite()) {
+ for (ActiveMQDestination composite :
destination.getCompositeDestinations()) {
+ doCheckDestinationForSendPermission(composite);
+ }
+ } else {
+ doCheckDestinationForSendPermission(destination);
+ }
+ }
+ }
+
+ private void doCheckDestinationForSendPermission(ActiveMQDestination
destination) throws Exception {
+ final SimpleString destinationName =
SimpleString.of(destination.getPhysicalName());
+ final SimpleString address =
CompositeAddress.extractAddressName(destinationName);
+ final SimpleString queue =
CompositeAddress.isFullyQualified(destinationName) ?
+ CompositeAddress.extractQueueName(destinationName) : null;
+
+ server.getSecurityStore().check(address, queue, CheckType.SEND,
getCoreSession());
+ }
}
diff --git
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/BasicSecurityTest.java
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/BasicSecurityTest.java
index 10ecb4628a..edbe51799d 100644
---
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/BasicSecurityTest.java
+++
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/BasicSecurityTest.java
@@ -39,6 +39,8 @@ import javax.jms.Topic;
import javax.jms.TopicSubscriber;
import java.io.Serializable;
+import org.apache.activemq.artemis.api.core.QueueConfiguration;
+import org.apache.activemq.artemis.api.core.RoutingType;
import org.apache.activemq.command.ActiveMQQueue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -148,10 +150,18 @@ public class BasicSecurityTest extends BasicOpenWireTest {
MessageProducer producer = null;
- producer = receivingSession.createProducer(dest);
+ try {
+ receivingSession.createProducer(dest);
+ fail("Should not be able to create a producer when not authorized
to send");
+ } catch (JMSSecurityException ex) {
+ // expected
+ }
+
+ producer = receivingSession.createProducer(null);
try {
- producer.send(message);
+ producer.send(dest, message);
+ fail("exception expected");
} catch (JMSSecurityException e) {
//expected
producer.close();
@@ -185,6 +195,84 @@ public class BasicSecurityTest extends BasicOpenWireTest {
}
}
+ @Test
+ public void testSendReceiveAuthorizationOnComposite() throws Exception {
+ Connection sendingConn = null;
+ Connection receivingConn = null;
+
+ final String compositeName = queueName + "," + queueName2;
+
+ //Sender
+ try {
+ Destination composite = new ActiveMQQueue(compositeName);
+ Destination dest1 = new ActiveMQQueue(queueName);
+ Destination dest2 = new ActiveMQQueue(queueName2);
+
+ // Server must have this composite version of the Address and Queue
for this test to work
+ // as the user does not have auto create permissions and it will try
to create this.
+
server.createQueue(QueueConfiguration.of(compositeName).setAddress(compositeName).setRoutingType(RoutingType.ANYCAST));
+
+ receivingConn = factory.createConnection("openwireReceiver",
"ReCeIvEr");
+ receivingConn.start();
+
+ sendingConn = factory.createConnection("openwireSender", "SeNdEr");
+ sendingConn.start();
+
+ Session sendingSession = sendingConn.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ Session receivingSession = receivingConn.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+
+ TextMessage message = sendingSession.createTextMessage("Hello World");
+
+ MessageProducer producer = null;
+
+ try {
+ receivingSession.createProducer(composite);
+ fail("Should get a security exception on create");
+ } catch (JMSSecurityException ex) {
+ // expected
+ }
+
+ producer = receivingSession.createProducer(null);
+
+ try {
+ producer.send(composite, message);
+ fail("exception expected");
+ } catch (JMSSecurityException e) {
+ //expected
+ producer.close();
+ }
+
+ producer = sendingSession.createProducer(composite);
+ producer.send(message);
+
+ try {
+ sendingSession.createConsumer(dest1);
+ fail("exception expected");
+ } catch (JMSSecurityException e) {
+ e.printStackTrace();
+ //expected
+ }
+
+ MessageConsumer consumer1 = receivingSession.createConsumer(dest1);
+ TextMessage received1 = (TextMessage) consumer1.receive(5000);
+ MessageConsumer consumer2 = receivingSession.createConsumer(dest2);
+ TextMessage received2 = (TextMessage) consumer2.receive(5000);
+
+ assertNotNull(received1);
+ assertEquals("Hello World", received1.getText());
+ assertNotNull(received2);
+ assertEquals("Hello World", received2.getText());
+ } finally {
+ if (sendingConn != null) {
+ sendingConn.close();
+ }
+
+ if (receivingConn != null) {
+ receivingConn.close();
+ }
+ }
+ }
+
@Test
public void testCreateTempDestinationAuthorization() throws Exception {
Connection conn1 = null;
@@ -444,5 +532,4 @@ public class BasicSecurityTest extends BasicOpenWireTest {
}
}
}
-
}
diff --git
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/SecurityOpenWireTest.java
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/SecurityOpenWireTest.java
index b562db8b88..c97e7ac106 100644
---
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/SecurityOpenWireTest.java
+++
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/SecurityOpenWireTest.java
@@ -16,70 +16,675 @@
*/
package org.apache.activemq.artemis.tests.integration.openwire;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.Set;
+
import javax.jms.Connection;
import javax.jms.DeliveryMode;
-import javax.jms.JMSException;
+import javax.jms.Destination;
+import javax.jms.JMSSecurityException;
import javax.jms.MessageProducer;
-import javax.jms.Queue;
import javax.jms.Session;
-import java.util.HashSet;
-import java.util.Set;
-
import org.apache.activemq.artemis.api.core.QueueConfiguration;
import org.apache.activemq.artemis.api.core.RoutingType;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.security.Role;
import
org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
+import org.apache.activemq.artemis.tests.util.RandomUtil;
+import org.apache.activemq.artemis.utils.CompositeAddress;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
-import static org.junit.jupiter.api.Assertions.fail;
-
+@Timeout(20)
public class SecurityOpenWireTest extends BasicOpenWireTest {
+ // This set specifically tests that two FQQNs under the same address can be
isolated for
+ // two distinct users each being allowed only access to a given queue under
the address
+ private final String FQQN_USER1 = "fqqnUser1";
+ private final String FQQN_USER2 = "fqqnUser2";
+ private final String FQQN_ROLE1 = "fqqnRole1";
+ private final String FQQN_ROLE2 = "fqqnRole2";
+ private final String FQQN_ADDRESS = "fqqnAddress";
+ private final String FQQN_QUEUE1 = "fqqnQueue1";
+ private final String FQQN_QUEUE2 = "fqqnQueue2";
+ private final String FQQN_FOR_USER1 =
CompositeAddress.toFullyQualified(FQQN_ADDRESS, FQQN_QUEUE1);
+ private final String FQQN_FOR_USER2 =
CompositeAddress.toFullyQualified(FQQN_ADDRESS, FQQN_QUEUE2);
+
+ private final String ALLOWED_USER = "allowedUser";
+ private final String ALLOWED_ROLE = "allowedRole";
+ private final String ALLOWED_USER_ALTERNATE = "allowedUserAlternate";
+ private final String ALLOWED_ROLE_ALTERNATE = "allowedRoleAlternate";
+ private final String DENIED_USER = "deniedUser";
+ private final String DENIED_ROLE = "deniedRole";
+ private final String PASS = RandomUtil.randomString();
+ private final String ADDRESS = "myAddress";
+ private final String ALTERNATE_ADDRESS = "myOtherAddress";
+ private final String ALTERNATE_QUEUE = "myOtherQueue";
+ private final String QUEUE = "myQueue";
+ private final String FQQN = CompositeAddress.toFullyQualified(ADDRESS,
QUEUE);
+ private final String FQQN_ALTERNATE =
CompositeAddress.toFullyQualified(ALTERNATE_ADDRESS, ALTERNATE_QUEUE);
+
@Override
@BeforeEach
public void setUp() throws Exception {
- //this system property is used to construct the executor in
-
//org.apache.activemq.transport.AbstractInactivityMonitor.createExecutor()
- //and affects the pool's shutdown time. (default is 30 sec)
- //set it to 2 to make tests shutdown quicker.
+ // this system property is used to construct the executor in
+ //
org.apache.activemq.transport.AbstractInactivityMonitor.createExecutor()
+ // and affects the pool's shutdown time. (default is 30 sec)
+ // set it to 2 to make tests shutdown quicker.
System.setProperty("org.apache.activemq.transport.AbstractInactivityMonitor.keepAliveTime",
"2");
- this.realStore = true;
+
+ realStore = true;
enableSecurity = true;
+
super.setUp();
}
@Override
- protected void extraServerConfig(Configuration serverConfig) {
+ protected void extraServerConfig(Configuration configuration) {
+ super.extraServerConfig(configuration);
+
+ final Role allowed = new Role(ALLOWED_ROLE, true, false, false, false,
false, false, false, false, true, false, false, false);
+ final Role denied = new Role(DENIED_ROLE, false, false, false, false,
false, false, false, false, false, false, false, false);
+ final Role alternate = new Role(ALLOWED_ROLE_ALTERNATE, true, false,
false, false, false, false, false, false, true, false, false, false);
+
+ final ActiveMQJAASSecurityManager securityManager =
(ActiveMQJAASSecurityManager) server.getSecurityManager();
+
+ securityManager.getConfiguration().addUser(ALLOWED_USER, PASS);
+ securityManager.getConfiguration().addRole(ALLOWED_USER, ALLOWED_ROLE);
+ securityManager.getConfiguration().addUser(ALLOWED_USER_ALTERNATE, PASS);
+ securityManager.getConfiguration().addRole(ALLOWED_USER_ALTERNATE,
ALLOWED_ROLE_ALTERNATE);
+ securityManager.getConfiguration().addUser(DENIED_USER, PASS);
+ securityManager.getConfiguration().addRole(DENIED_USER, DENIED_ROLE);
+ securityManager.getConfiguration().addRole(ALLOWED_USER,
"advisoryReceiver");
+ securityManager.getConfiguration().addRole(ALLOWED_USER_ALTERNATE,
"advisoryReceiver");
+ securityManager.getConfiguration().addRole(DENIED_USER,
"advisoryReceiver");
+
+ configuration.putSecurityRoles(FQQN, Set.of(allowed, denied));
+ configuration.putSecurityRoles(ADDRESS, Set.of(allowed, denied));
+ configuration.putSecurityRoles(FQQN_ALTERNATE, Set.of(alternate,
denied));
+ configuration.putSecurityRoles(ALTERNATE_ADDRESS, Set.of(alternate,
denied));
+
+
configuration.addQueueConfiguration(QueueConfiguration.of(QUEUE).setAddress(ADDRESS).setRoutingType(RoutingType.ANYCAST));
+
configuration.addQueueConfiguration(QueueConfiguration.of(ALTERNATE_QUEUE).setAddress(ALTERNATE_ADDRESS).setRoutingType(RoutingType.ANYCAST));
+
+ // This section create a split FQQN set under a single address where
each user can only write to their
+ // own Queue under the base FQQN address, these roles disallow auto
create to ensure neither can just
+ // create their way into a working configuration.
+
+ final Role fqqn1 = new Role(FQQN_ROLE1, true, false, false, false,
false, false, false, false, false, false, false, false);
+ final Role fqqn2 = new Role(FQQN_ROLE2, true, false, false, false,
false, false, false, false, false, false, false, false);
+
+ securityManager.getConfiguration().addUser(FQQN_USER1, PASS);
+ securityManager.getConfiguration().addRole(FQQN_USER1, FQQN_ROLE1);
+ securityManager.getConfiguration().addRole(FQQN_USER1,
"advisoryReceiver");
+ securityManager.getConfiguration().addUser(FQQN_USER2, PASS);
+ securityManager.getConfiguration().addRole(FQQN_USER2, FQQN_ROLE2);
+ securityManager.getConfiguration().addRole(FQQN_USER2,
"advisoryReceiver");
+
+ configuration.putSecurityRoles(FQQN_FOR_USER1, Set.of(fqqn1));
+ configuration.putSecurityRoles(FQQN_FOR_USER2, Set.of(fqqn2));
+
+
configuration.addQueueConfiguration(QueueConfiguration.of(FQQN_FOR_USER1).setAddress(FQQN_ADDRESS).setRoutingType(RoutingType.ANYCAST));
+
configuration.addQueueConfiguration(QueueConfiguration.of(FQQN_FOR_USER2).setAddress(FQQN_ADDRESS).setRoutingType(RoutingType.ANYCAST));
+ }
+
+ @Test
+ public void testAnonymousSendNoAuthToQueue() throws Exception {
+ doTestAnonymousSendNoAuth(false);
+ }
+
+ @Test
+ public void testAnonymousSendNoAuthToTopic() throws Exception {
+ doTestAnonymousSendNoAuth(true);
+ }
+
+ private void doTestAnonymousSendNoAuth(boolean topic) throws Exception {
+ try (Connection connection = factory.createConnection(DENIED_USER,
PASS)) {
+ final Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Destination destination;
+
+ if (topic) {
+ destination = session.createTopic(ADDRESS);
+ } else {
+ destination = session.createQueue(ADDRESS);
+ }
+
+ final MessageProducer producer = session.createProducer(null);
+
+ producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+
+ try {
+ producer.send(destination, session.createTextMessage());
+ fail("Should not be able to send to this destination");
+ } catch (JMSSecurityException e) {
+ // expected to fail as not authorized
+ }
+ }
+ }
+
+ @Test
+ public void testAnonymousSendWithAuthToQueue() throws Exception {
+ doTestAnonymousSendWithAuth(false);
+ }
+
+ @Test
+ public void testAnonymousSendWithAuthToTopic() throws Exception {
+ doTestAnonymousSendWithAuth(true);
+ }
+
+ private void doTestAnonymousSendWithAuth(boolean topic) throws Exception {
+ try (Connection connection = factory.createConnection(ALLOWED_USER,
PASS)) {
+ final Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final MessageProducer producer = session.createProducer(null);
+ final Destination destination;
+
+ if (topic) {
+ destination = session.createTopic(ADDRESS);
+ } else {
+ destination = session.createQueue(ADDRESS);
+ }
+
+ producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+
+ try {
+ producer.send(destination, session.createMessage());
+ // Expected: can send to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("unexpected error: " + e.getMessage());
+ }
+ }
+ }
+
+ @Test
+ public void testSendWithAuthToQueue() throws Exception {
+ doTestSendWithAuth(false);
+ }
+
+ @Test
+ public void testSendWithAuthToTopic() throws Exception {
+ doTestSendWithAuth(true);
+ }
+
+ private void doTestSendWithAuth(boolean topic) throws Exception {
+ try (Connection connection = factory.createConnection(ALLOWED_USER,
PASS)) {
+ final Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Destination destination;
+
+ if (topic) {
+ destination = session.createTopic(ADDRESS);
+ } else {
+ destination = session.createQueue(ADDRESS);
+ }
+
+ final MessageProducer producer = session.createProducer(destination);
+
+ producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+
+ try {
+ producer.send(session.createMessage());
+ // Expected: can send to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("unexpected error: " + e.getMessage());
+ }
+ }
+ }
+
+ @Test
+ public void testCreateSenderNoAuthToQueue() throws Exception {
+ doTestCreateSenderNoAuth(false);
+ }
+
+ @Test
+ public void testCreateSenderNoAuthToTopic() throws Exception {
+ doTestCreateSenderNoAuth(true);
+ }
+
+ private void doTestCreateSenderNoAuth(boolean topic) throws Exception {
+ try (Connection connection = factory.createConnection(DENIED_USER,
PASS)) {
+ final Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Destination destination;
+
+ if (topic) {
+ destination = session.createTopic(ADDRESS);
+ } else {
+ destination = session.createQueue(ADDRESS);
+ }
+
+ try {
+ session.createProducer(destination);
+ fail("Should not be able to create producer on restricted
destination");
+ } catch (JMSSecurityException e) {
+ // expected to fail as not authorized
+ }
+ }
+ }
+
+ @Test
+ public void testCreateSenderWithAuthToFQQNAsQueue() throws Exception {
+ doTestCreateSenderWithAuthToFQQN(false);
+ }
+
+ @Test
+ public void testCreateSenderWithAuthToFQQNAsTopic() throws Exception {
+ doTestCreateSenderWithAuthToFQQN(true);
+ }
+
+ private void doTestCreateSenderWithAuthToFQQN(boolean topic) throws
Exception {
+ try (Connection connection = factory.createConnection(ALLOWED_USER,
PASS)) {
+ final Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Destination destination;
+ final Destination otherDestination;
+
+ if (topic) {
+ destination = session.createTopic(FQQN);
+ otherDestination = session.createTopic(FQQN_ALTERNATE); // Does
not have authorization to this FQQN
+ } else {
+ destination = session.createQueue(FQQN);
+ otherDestination = session.createQueue(FQQN_ALTERNATE); // Does
not have authorization to this FQQN
+ }
+
+ try {
+ session.createProducer(destination);
+ // Expected: can attach to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("Should be able to send to given FQQN: " + e.getMessage());
+ }
+
+ try {
+ session.createProducer(otherDestination);
+ fail("Should not be able to send to given alternate FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: cannot attach to FQQN destination that is not in the
security match settings
+ }
+ }
+ }
+
+ @Test
+ public void testCreateSenderNoAuthToFQQNAsQueue() throws Exception {
+ doTestCreateSenderNoAuthToFQQN(false);
+ }
+
+ @Test
+ public void testCreateSenderNoAuthToFQQNAsTopic() throws Exception {
+ doTestCreateSenderNoAuthToFQQN(true);
+ }
+
+ private void doTestCreateSenderNoAuthToFQQN(boolean topic) throws Exception
{
+ try (Connection connection = factory.createConnection(DENIED_USER,
PASS)) {
+ final Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Destination destination;
+
+ if (topic) {
+ destination = session.createTopic(FQQN);
+ } else {
+ destination = session.createQueue(FQQN);
+ }
+
+ try {
+ session.createProducer(destination);
+ fail("Should not be able to send to given FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: cannot attach to denied destination
+ }
+ }
+ }
+
+ @Test
+ public void testAnonymousSenderWithAuthToFQQNAsQueue() throws Exception {
+ doTestAnonymousSenderWithAuthToFQQN(false);
+ }
+
+ @Test
+ public void testAnonymousSenderWithAuthToFQQNAsTopic() throws Exception {
+ doTestAnonymousSenderWithAuthToFQQN(true);
+ }
+
+ private void doTestAnonymousSenderWithAuthToFQQN(boolean topic) throws
Exception {
+ try (Connection connection = factory.createConnection(ALLOWED_USER,
PASS)) {
+ final Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Destination destination;
+ final Destination otherDestination;
+
+ if (topic) {
+ destination = session.createTopic(FQQN);
+ otherDestination = session.createTopic(FQQN_ALTERNATE); // Does
not have authorization to this FQQN
+ } else {
+ destination = session.createQueue(FQQN);
+ otherDestination = session.createQueue(FQQN_ALTERNATE); // Does
not have authorization to this FQQN
+ }
+
+ final MessageProducer producer = session.createProducer(null);
+
+ producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+
+ try {
+ producer.send(destination, session.createMessage());
+ // Expected: should send to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("Should be able to send to given FQQN: " + e.getMessage());
+ }
+
+ try {
+ producer.send(otherDestination, session.createMessage());
+ fail("Should not be able to send to given alternate FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: should fail to send to this destination
+ }
+ }
+ }
+
+ @Test
+ public void testAnonymousSenderNoAuthToFQQNAsQueue() throws Exception {
+ doTestAnonymousSenderNoAuthToFQQN(false);
+ }
+
+ @Test
+ public void testAnonymousSenderNoAuthToFQQNAsTopic() throws Exception {
+ doTestAnonymousSenderNoAuthToFQQN(true);
+ }
+
+ private void doTestAnonymousSenderNoAuthToFQQN(boolean topic) throws
Exception {
+ try (Connection connection = factory.createConnection(DENIED_USER,
PASS)) {
+ final Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Destination destination;
+
+ if (topic) {
+ destination = session.createTopic(FQQN);
+ } else {
+ destination = session.createQueue(FQQN);
+ }
+
+ final MessageProducer producer = session.createProducer(null);
+
+ producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+
+ try {
+ producer.send(destination, session.createMessage());
+ fail("Should not be able to send to given FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: cannot attach to denied destination
+ }
+ }
+ }
+
+ @Test
+ public void testCreateSendersWithFineGrainedAuthToFQQNAsQueues() throws
Exception {
+ doTestCreateSenderWithFineGrainedAuthToFQQNs(false);
+ }
+
+ @Test
+ public void testCreateSendersWithFineGrainedAuthToFQQNAsTopics() throws
Exception {
+ doTestCreateSenderWithFineGrainedAuthToFQQNs(true);
+ }
+
+ private void doTestCreateSenderWithFineGrainedAuthToFQQNs(boolean topic)
throws Exception {
+ try (Connection connection1 = factory.createConnection(ALLOWED_USER,
PASS);
+ Connection connection2 =
factory.createConnection(ALLOWED_USER_ALTERNATE, PASS)) {
+
+ final Session session1 = connection1.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Session session2 = connection2.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+
+ final Destination destination1;
+ final Destination destination2;
+
+ if (topic) {
+ destination1 = session1.createTopic(FQQN);
+ destination2 = session2.createTopic(FQQN_ALTERNATE);
+ } else {
+ destination1 = session1.createQueue(FQQN);
+ destination2 = session2.createQueue(FQQN_ALTERNATE);
+ }
+
+ try {
+ session1.createProducer(destination1);
+ // Expected: should be able to create sender to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("Should be able to create sender to given FQQN: " +
e.getMessage());
+ }
+
+ try {
+ session1.createProducer(destination2);
+ fail("Should not be able to create sender to given FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: should fail to create sender to this FQQN destination
+ }
+
+ try {
+ session2.createProducer(destination2);
+ // Expected: should be able to create sender to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("Should be able to create sender to given FQQN: " +
e.getMessage());
+ }
+
+ try {
+ session2.createProducer(destination1);
+ fail("Should not be able to create sender to given FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: should fail to create sender to this FQQN destination
+ }
+ }
+ }
+
+ @Test
+ public void testAnonymousSendersWithFineGrainedAuthToFQQNAsQueues() throws
Exception {
+ doTestAnonymousSenderWithFineGrainedAuthToFQQNs(false);
+ }
+
+ @Test
+ public void testAnonymousSendersWithFineGrainedAuthToFQQNAsTopics() throws
Exception {
+ doTestAnonymousSenderWithFineGrainedAuthToFQQNs(true);
+ }
+
+ private void doTestAnonymousSenderWithFineGrainedAuthToFQQNs(boolean topic)
throws Exception {
+ try (Connection connection1 = factory.createConnection(ALLOWED_USER,
PASS);
+ Connection connection2 =
factory.createConnection(ALLOWED_USER_ALTERNATE, PASS)) {
+
+ final Session session1 = connection1.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Session session2 = connection2.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+
+ final Destination destination1;
+ final Destination destination2;
+
+ if (topic) {
+ destination1 = session1.createTopic(FQQN);
+ destination2 = session2.createTopic(FQQN_ALTERNATE);
+ } else {
+ destination1 = session1.createQueue(FQQN);
+ destination2 = session2.createQueue(FQQN_ALTERNATE);
+ }
+
+ final MessageProducer producer1 = session1.createProducer(null);
+ final MessageProducer producer2 = session2.createProducer(null);
+
+ producer1.setDeliveryMode(DeliveryMode.PERSISTENT); // ALLOWED USER
+ producer2.setDeliveryMode(DeliveryMode.PERSISTENT); // ALTERNATE
ALLOWED USER
+
+ try {
+ producer1.send(destination1, session1.createMessage());
+ // Expected: should send to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("Should be able to send to given FQQN: " + e.getMessage());
+ }
+
+ try {
+ producer1.send(destination2, session1.createMessage());
+ fail("Should not be able to send to given FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: should fail to send to this destination
+ }
+
+ try {
+ producer2.send(destination2, session2.createMessage());
+ // Expected: should send to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("Should be able to send to given FQQN: " + e.getMessage());
+ }
+
+ try {
+ producer2.send(destination1, session2.createMessage());
+ fail("Should not be able to send to given FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: should fail to send to this destination
+ }
+ }
+ }
+
+ @Test
+ public void testCreateSenderNoAuthToCompositeAsQueue() throws Exception {
+ doTestCreateSenderNoAuthToComposite(false);
+ }
+
+ @Test
+ public void testCreateSenderNoAuthToCompositeAsTopic() throws Exception {
+ doTestCreateSenderNoAuthToComposite(true);
+ }
+
+ private void doTestCreateSenderNoAuthToComposite(boolean topic) throws
Exception {
+ try (Connection connection = factory.createConnection(DENIED_USER,
PASS)) {
+ final Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Destination destination;
+
+ if (topic) {
+ destination = session.createTopic(ADDRESS + "," +
ALTERNATE_ADDRESS);
+ } else {
+ destination = session.createQueue(ADDRESS + "," +
ALTERNATE_ADDRESS);
+ }
+
+ try {
+ session.createProducer(destination);
+ fail("Should not be able to create a producer to given composite
destination");
+ } catch (JMSSecurityException e) {
+ // Expected: cannot attach to denied destination
+ }
+ }
+ }
- super.extraServerConfig(serverConfig);
- ActiveMQJAASSecurityManager securityManager =
(ActiveMQJAASSecurityManager) server.getSecurityManager();
- securityManager.getConfiguration().addUser("denyQ", "denyQ");
- securityManager.getConfiguration().addRole("denyQ", "denyQ");
- securityManager.getConfiguration().addRole("denyQ", "advisoryReceiver");
+ @Test
+ public void testAnonymousSenderNoAuthToCompositeAsQueue() throws Exception {
+ doTestAnonymousSenderNoAuthToComposite(false);
}
@Test
- public void testSendNoAuth() throws Exception {
- Set<Role> roles = new HashSet<>();
- roles.add(new Role("programmers", false, false, false, false, false,
false, false, false, false, false, false, false));
+ public void testAnonymousSenderNoAuthToCompositeAsTopic() throws Exception {
+ doTestAnonymousSenderNoAuthToComposite(true);
+ }
+
+ private void doTestAnonymousSenderNoAuthToComposite(boolean topic) throws
Exception {
+ try (Connection connection = factory.createConnection(DENIED_USER,
PASS)) {
+ final Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Destination destination;
+
+ if (topic) {
+ destination = session.createTopic(ADDRESS + "," +
ALTERNATE_ADDRESS);
+ } else {
+ destination = session.createQueue(ADDRESS + "," +
ALTERNATE_ADDRESS);
+ }
+
+ final MessageProducer producer = session.createProducer(null);
- server.getSecurityRepository().addMatch("denyQ", roles);
- String denyQ = "denyQ";
-
server.createQueue(QueueConfiguration.of(denyQ).setRoutingType(RoutingType.ANYCAST));
- try (Connection connection = factory.createConnection(denyQ, denyQ)) {
- Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
- Queue queue = session.createQueue(denyQ);
- MessageProducer producer = session.createProducer(queue);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+
try {
- producer.send(session.createTextMessage());
- fail();
- } catch (JMSException e) {
- //pass
+ producer.send(destination, session.createMessage());
+ fail("Should not be able to send to given composite destination");
+ } catch (JMSSecurityException e) {
+ // Expected: cannot attach to denied destination
}
}
}
+ @Test
+ public void testFQQNUserIsolationUnderSameAddressOnSenderCreate() throws
Exception {
+ try (Connection connection1 = factory.createConnection(FQQN_USER1, PASS);
+ Connection connection2 = factory.createConnection(FQQN_USER2,
PASS)) {
+
+ final Session session1 = connection1.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Session session2 = connection2.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+
+ final Destination destination1 = session1.createQueue(FQQN_FOR_USER1);
+ final Destination destination2 = session2.createQueue(FQQN_FOR_USER2);
+
+ // FQQN USER 1 is isolated to the queue under address created for it
+
+ try {
+ session1.createProducer(destination1);
+ // Expected: should be able to create sender to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("Should be able to create sender to given FQQN: " +
e.getMessage());
+ }
+
+ try {
+ session1.createProducer(destination2);
+ fail("Should not be able to create sender to given FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: should fail to create sender to this FQQN destination
+ }
+
+ // FQQN USER 2 is isolated to the queue under address created for it
+
+ try {
+ session2.createProducer(destination2);
+ // Expected: should be able to create sender to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("Should be able to create sender to given FQQN: " +
e.getMessage());
+ }
+
+ try {
+ session2.createProducer(destination1);
+ fail("Should not be able to create sender to given FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: should fail to create sender to this FQQN destination
+ }
+ }
+ }
+
+ @Test
+ public void testFQQNUserIsolationUnderSameAddressWithAnonymousSends()
throws Exception {
+ try (Connection connection1 = factory.createConnection(FQQN_USER1, PASS);
+ Connection connection2 = factory.createConnection(FQQN_USER2,
PASS)) {
+
+ final Session session1 = connection1.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+ final Session session2 = connection2.createSession(false,
Session.AUTO_ACKNOWLEDGE);
+
+ final Destination destination1 = session1.createQueue(FQQN_FOR_USER1);
+ final Destination destination2 = session2.createQueue(FQQN_FOR_USER2);
+
+ final MessageProducer producer1 = session1.createProducer(null);
+ final MessageProducer producer2 = session2.createProducer(null);
+
+ // FQQN USER 1 is isolated to the queue under address created for it
+
+ try {
+ producer1.send(destination1, session1.createMessage());
+ // Expected: should be able to send to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("Should be able to send to given FQQN: " + e.getMessage());
+ }
+
+ try {
+ producer1.send(destination2, session1.createMessage());
+ fail("Should not be able to send to given FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: should fail to send to this FQQN destination
+ }
+
+ // FQQN USER 2 is isolated to the queue under address created for it
+
+ try {
+ producer2.send(destination2, session1.createMessage());
+ // Expected: should be able to send to allowed destination
+ } catch (JMSSecurityException e) {
+ fail("Should be able to send to given FQQN: " + e.getMessage());
+ }
+
+ try {
+ producer2.send(destination1, session1.createMessage());
+ fail("Should not be able to send to given FQQN");
+ } catch (JMSSecurityException e) {
+ // Expected: should fail to send to this FQQN destination
+ }
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information, visit: https://activemq.apache.org/contact