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.
This commit is contained in:
Timothy Bish 2024-08-02 10:56:28 -04:00 committed by Robbie Gemmell
parent 47acdc4517
commit 8250e611df
4 changed files with 770 additions and 45 deletions

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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 {
}
}
}
}

View File

@ -16,70 +16,675 @@
*/
package org.apache.activemq.artemis.tests.integration.openwire;
import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import java.util.HashSet;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.Set;
import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSSecurityException;
import javax.jms.MessageProducer;
import javax.jms.Session;
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);
super.extraServerConfig(serverConfig);
ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager();
securityManager.getConfiguration().addUser("denyQ", "denyQ");
securityManager.getConfiguration().addRole("denyQ", "denyQ");
securityManager.getConfiguration().addRole("denyQ", "advisoryReceiver");
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 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 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);
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.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
}
}
}
@Test
public void testAnonymousSenderNoAuthToCompositeAsQueue() throws Exception {
doTestAnonymousSenderNoAuthToComposite(false);
}
@Test
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);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
try {
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
}
}
}
}