From 2e17a4a007b23e4ca02206c7c0fb81b56f5aee1e Mon Sep 17 00:00:00 2001 From: Gary Tully Date: Wed, 14 Feb 2024 14:08:08 +0000 Subject: [PATCH] ARTEMIS-4582 - view and edit permissions, mops. security-settings for rbac on management apis --- .../commands/tools/xml/XmlDataImporter.java | 20 +- .../config/ActiveMQDefaultConfiguration.java | 18 + .../management/ActiveMQServerControl.java | 15 + .../core/management/ObjectNameBuilder.java | 7 +- .../activemq/artemis/core/security/Role.java | 65 +- .../artemis/utils/SecurityFormatter.java | 2 +- .../resources/org.apache.activemq.artemis.cfg | 1 + artemis-hawtio/artemis-console/pom.xml | 9 +- .../activemq/artemis/osgi/OsgiBroker.java | 6 + .../artemis/core/config/Configuration.java | 13 + .../core/config/impl/ConfigurationImpl.java | 37 +- .../impl/FileConfigurationParser.java | 18 +- .../impl/ActiveMQServerControlImpl.java | 39 +- .../management/impl/AddressControlImpl.java | 16 +- .../impl/ManagementRemotingConnection.java | 5 +- .../config/PersistedSecuritySetting.java | 68 +- .../artemis/core/security/CheckType.java | 31 + .../core/security/impl/SecurityStoreImpl.java | 41 +- .../impl/LegacyLDAPSecuritySettingPlugin.java | 4 +- .../core/server/impl/ServerSessionImpl.java | 2 +- .../management/ArtemisMBeanServerBuilder.java | 5 +- .../management/ArtemisMBeanServerGuard.java | 4 +- .../ArtemisRbacInvocationHandler.java | 368 ++++++++++ .../ArtemisRbacMBeanServerBuilder.java | 32 + .../management/GuardInvocationHandler.java | 25 + .../server/management/ManagementContext.java | 26 +- .../server/management/ManagementService.java | 9 +- .../impl/HawtioSecurityControlImpl.java | 6 +- .../impl/ManagementServiceImpl.java | 76 +- .../server/routing/targets/LocalTarget.java | 4 +- .../ActiveMQBasicSecurityManager.java | 5 +- .../security/ActiveMQJAASSecurityManager.java | 26 +- .../security/ActiveMQSecurityManager.java | 7 + .../security/ActiveMQSecurityManager5.java | 1 + .../artemis/utils/SecurityManagerUtil.java | 21 +- .../schema/artemis-configuration.xsd | 27 + .../impl/FileConfigurationParserTest.java | 36 + .../config/impl/FileConfigurationTest.java | 26 +- .../artemis/core/security/RoleTest.java | 29 +- .../security/impl/SecurityStoreImplTest.java | 76 +- .../JAASSecurityManagerClassLoadingTest.java | 5 +- .../group/impl/ClusteredResetMockTest.java | 11 +- .../ArtemisRbacMBeanServerBuilderTest.java | 693 ++++++++++++++++++ ...urityControlImplSecurityStoreRbacTest.java | 29 + .../impl/HawtioSecurityControlImplTest.java | 16 +- .../impl/ManagementServiceImplTest.java | 217 ++++++ .../artemis/core/settings/RepositoryTest.java | 14 +- .../ActiveMQJAASSecurityManagerTest.java | 56 ++ .../utils/SecurityManagerUtilTest.java | 54 ++ .../artemis/utils/SubjectDotDoAsRule.java | 55 ++ docs/user-manual/configuration-index.adoc | 13 + docs/user-manual/management.adoc | 127 +++- docs/user-manual/security.adoc | 19 +- .../amqp/JMSSaslExternalLDAPTest.java | 2 +- .../amqp/SaslKrb5LDAPSecurityTest.java | 2 +- .../JmxSecurityMultipleSubjectTest.java | 139 ++++ .../isolated/security/JmxSecurityTest.java | 355 +++++++++ .../isolated/security/LDAPSecurityTest.java | 4 +- .../MultiThreadedAuditLoggingTest.java | 4 +- .../amqp/AmqpClientTestSupport.java | 8 +- .../integration/amqp/JMSSaslExternalTest.java | 2 +- .../integration/amqp/JMSSaslGssapiTest.java | 2 +- .../client/AutoCreateJmsDestinationTest.java | 4 +- .../integration/client/CoreClientTest.java | 2 +- .../failover/SecurityFailoverTest.java | 2 +- .../tests/integration/jms/RedeployTest.java | 9 +- .../integration/jms/SimpleJNDIClientTest.java | 2 +- .../jms/client/TemporaryDestinationTest.java | 2 +- .../MultiprotocolJMSClientTestSupport.java | 8 +- .../largemessage/ServerLargeMessageTest.java | 2 +- .../management/ActiveMQServerControlTest.java | 10 +- .../ActiveMQServerControlUsingCoreTest.java | 20 +- .../management/AddressControlTest.java | 4 +- .../management/ManagementServiceImplTest.java | 14 +- .../management/MessageAuthorizationTest.java | 6 +- .../SSLSecurityNotificationTest.java | 6 +- .../SecurityManagementMessageRbacTest.java | 114 +++ .../SecurityManagementTestBase.java | 75 +- ...ManagementWithConfiguredAdminUserTest.java | 15 +- ...anagementWithDefaultConfigurationTest.java | 9 +- ...nagementWithModifiedConfigurationTest.java | 11 +- .../management/SecurityNotificationTest.java | 57 +- .../mqtt/MQTTSecurityManagerTest.java | 5 +- .../integration/mqtt/MQTTTestSupport.java | 8 +- .../mqtt/PahoMQTTQOS2SecurityTest.java | 2 +- .../integration/mqtt5/MQTT5TestSupport.java | 12 +- .../CertificateAuthenticationSslTests.java | 2 +- .../openwire/OpenWireTestBase.java | 10 +- .../openwire/SecurityOpenWireTest.java | 2 +- .../RolesConfigurationStorageTest.java | 10 +- .../persistence/XmlImportExportRbacTest.java | 172 +++++ .../ActiveMQMessageHandlerSecurityTest.java | 2 +- .../tests/integration/ra/JMSContextTest.java | 2 +- .../ra/OutgoingConnectionJTATest.java | 2 +- .../ra/OutgoingConnectionNoJTATest.java | 2 +- .../ra/OutgoingConnectionTest.java | 2 +- .../integration/routing/KeyTypeTest.java | 2 +- .../security/BasicSecurityManagerTest.java | 6 +- .../security/FQQNSendSecurityTest.java | 4 +- .../PersistedSecuritySettingTest.java | 2 + .../security/RecursiveNettySecurityTest.java | 5 +- .../security/SecurityPerAcceptorJmsTest.java | 6 +- .../security/SecurityPerAcceptorTest.java | 4 +- .../integration/security/SecurityTest.java | 173 +++-- .../integration/server/ResourceLimitTest.java | 2 +- .../server/ResourceLimitTestWithCerts.java | 2 +- .../ssl/DualAuthenticationTest.java | 4 +- .../tests/integration/ssl/SslPEMTest.java | 4 +- .../stomp/StompAuditLoggingTest.java | 2 +- .../integration/stomp/StompTestBase.java | 2 +- .../reload-security-settings-updated.xml | 2 + .../jmx-rbac-broker-security/broker.xml | 148 ++++ .../jmx-rbac-broker-security/management.xml | 21 + .../jmxrbac/JmxRBACBrokerSecurityTest.java | 224 ++++++ .../tests/smoke/jmxrbac/JmxRBACTest.java | 4 - .../impl/ActiveMQSecurityManagerImplTest.java | 28 +- 116 files changed, 3845 insertions(+), 458 deletions(-) create mode 100644 artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacInvocationHandler.java create mode 100644 artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacMBeanServerBuilder.java create mode 100644 artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/GuardInvocationHandler.java create mode 100644 artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacMBeanServerBuilderTest.java create mode 100644 artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImplSecurityStoreRbacTest.java create mode 100644 artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImplTest.java create mode 100644 artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManagerTest.java create mode 100644 artemis-server/src/test/java/org/apache/activemq/artemis/utils/SecurityManagerUtilTest.java create mode 100644 artemis-unit-test-support/src/main/java/org/apache/activemq/artemis/utils/SubjectDotDoAsRule.java create mode 100644 tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/JmxSecurityMultipleSubjectTest.java create mode 100644 tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/JmxSecurityTest.java create mode 100644 tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementMessageRbacTest.java create mode 100644 tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/XmlImportExportRbacTest.java create mode 100644 tests/smoke-tests/src/main/resources/servers/jmx-rbac-broker-security/broker.xml create mode 100644 tests/smoke-tests/src/main/resources/servers/jmx-rbac-broker-security/management.xml create mode 100644 tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACBrokerSecurityTest.java diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/xml/XmlDataImporter.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/xml/XmlDataImporter.java index 31da6f752e..3447ed9685 100644 --- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/xml/XmlDataImporter.java +++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/tools/xml/XmlDataImporter.java @@ -321,7 +321,7 @@ public final class XmlDataImporter extends ActionAbstract { } for (String queue : queues) { - long queueID; + long queueID = -1; if (queueIDs.containsKey(queue)) { queueID = queueIDs.get(queue); @@ -337,17 +337,27 @@ public final class XmlDataImporter extends ActionAbstract { logger.debug("Requesting ID for: {}", queue); } ClientMessage reply = requestor.request(managementMessage); - Number idObject = (Number) ManagementHelper.getResult(reply); - queueID = idObject.longValue(); + if (ManagementHelper.hasOperationSucceeded(reply)) { + Number idObject = (Number) ManagementHelper.getResult(reply); + queueID = idObject.longValue(); + } else { + if (debugLog) { + logger.debug("Failed to get ID for {}, reply: {}", queue, ManagementHelper.getResult(reply, String.class)); + } + } } if (debugLog) { logger.debug("ID for {} is: {}", queue, queueID); } - queueIDs.put(queue, queueID); // store it so we don't have to look it up every time + if (queueID != -1) { + queueIDs.put(queue, queueID); // store it so we don't have to look it up every time + } } - buffer.putLong(queueID); + if (queueID != -1) { + buffer.putLong(queueID); + } if (debugLog) { debugLogMessage.append(queue).append(", "); } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java index 10e074142b..48fb2b6b2a 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java @@ -692,6 +692,12 @@ public final class ActiveMQDefaultConfiguration { public static final String DEFAULT_LITERAL_MATCH_MARKERS = null; + private static final String DEFAULT_VIEW_PERMISSION_METHOD_MATCH_PATTERN = "^(get|is|count|list|browse|query).*$"; + + private static final String DEFAULT_MANAGEMENT_RBAC_PREFIX = "mops"; + + private static final boolean DEFAULT_MANAGEMENT_MESSAGE_RBAC = false; + /** * If true then the ActiveMQ Artemis Server will make use of any Protocol Managers that are in available on the classpath. If false then only the core protocol will be available, unless in Embedded mode where users can inject their own Protocol Managers. */ @@ -1900,4 +1906,16 @@ public final class ActiveMQDefaultConfiguration { public static String getLiteralMatchMarkers() { return DEFAULT_LITERAL_MATCH_MARKERS; } + + public static String getViewPermissionMethodMatchPattern() { + return DEFAULT_VIEW_PERMISSION_METHOD_MATCH_PATTERN; + } + + public static String getManagementRbacPrefix() { + return DEFAULT_MANAGEMENT_RBAC_PREFIX; + } + + public static boolean getManagementMessagesRbac() { + return DEFAULT_MANAGEMENT_MESSAGE_RBAC; + } } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java index d7930c771b..4d2cea380e 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java @@ -1406,6 +1406,21 @@ public interface ActiveMQServerControl { @Parameter(desc = "a comma-separated list of roles allowed to create addresses", name = "createAddressRoles") String createAddressRoles, @Parameter(desc = "a comma-separated list of roles allowed to delete addresses", name = "deleteAddressRoles") String deleteAddressRoles) throws Exception; + @Operation(desc = "Add security settings for addresses matching the addressMatch", impact = MBeanOperationInfo.ACTION) + void addSecuritySettings(@Parameter(desc = "an address match", name = "addressMatch") String addressMatch, + @Parameter(desc = "a comma-separated list of roles allowed to send messages", name = "send") String sendRoles, + @Parameter(desc = "a comma-separated list of roles allowed to consume messages", name = "consume") String consumeRoles, + @Parameter(desc = "a comma-separated list of roles allowed to create durable queues", name = "createDurableQueueRoles") String createDurableQueueRoles, + @Parameter(desc = "a comma-separated list of roles allowed to delete durable queues", name = "deleteDurableQueueRoles") String deleteDurableQueueRoles, + @Parameter(desc = "a comma-separated list of roles allowed to create non durable queues", name = "createNonDurableQueueRoles") String createNonDurableQueueRoles, + @Parameter(desc = "a comma-separated list of roles allowed to delete non durable queues", name = "deleteNonDurableQueueRoles") String deleteNonDurableQueueRoles, + @Parameter(desc = "a comma-separated list of roles allowed to send management messages messages", name = "manage") String manageRoles, + @Parameter(desc = "a comma-separated list of roles allowed to browse queues", name = "browse") String browseRoles, + @Parameter(desc = "a comma-separated list of roles allowed to create addresses", name = "createAddressRoles") String createAddressRoles, + @Parameter(desc = "a comma-separated list of roles allowed to delete addresses", name = "deleteAddressRoles") String deleteAddressRoles, + @Parameter(desc = "a comma-separated list of roles allowed to view management resources", name = "view") String viewRoles, + @Parameter(desc = "a comma-separated list of roles allowed to edit management resources", name = "edit") String editRoles) throws Exception; + @Operation(desc = "Remove security settings for an address", impact = MBeanOperationInfo.ACTION) void removeSecuritySettings(@Parameter(desc = "an address match", name = "addressMatch") String addressMatch) throws Exception; diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ObjectNameBuilder.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ObjectNameBuilder.java index d08bb27f44..2d103f5916 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ObjectNameBuilder.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ObjectNameBuilder.java @@ -161,7 +161,12 @@ public final class ObjectNameBuilder { return String.format("%s:broker=%s", domain, (jmxUseBrokerName && brokerName != null) ? ObjectName.quote(brokerName) : "artemis"); } + @Deprecated() public ObjectName getManagementContextObjectName() throws Exception { - return ObjectName.getInstance(String.format("hawtio:type=security,area=jmx,name=ArtemisJMXSecurity")); + return getSecurityObjectName(); + } + + public ObjectName getSecurityObjectName() throws Exception { + return ObjectName.getInstance("hawtio:type=security,area=jmx,name=ArtemisJMXSecurity"); } } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/security/Role.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/security/Role.java index 315f66d226..12f3258899 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/security/Role.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/security/Role.java @@ -50,8 +50,13 @@ public class Role implements Serializable { private boolean browse; + private boolean view; + + private boolean edit; + public JsonObject toJson() { - return JsonLoader.createObjectBuilder().add("name", name).add("send", send).add("consume", consume).add("createDurableQueue", createDurableQueue).add("deleteDurableQueue", deleteDurableQueue).add("createNonDurableQueue", createNonDurableQueue).add("deleteNonDurableQueue", deleteNonDurableQueue).add("manage", manage).add("browse", browse).add("createAddress", createAddress).add("deleteAddress", deleteAddress).build(); + return JsonLoader.createObjectBuilder().add("name", name).add("send", send).add("consume", consume).add("createDurableQueue", createDurableQueue).add("deleteDurableQueue", deleteDurableQueue).add("createNonDurableQueue", createNonDurableQueue).add("deleteNonDurableQueue", deleteNonDurableQueue).add("manage", manage) + .add("browse", browse).add("createAddress", createAddress).add("deleteAddress", deleteAddress).add("view", view).add("edit", edit).build(); } public Role() { @@ -79,7 +84,7 @@ public class Role implements Serializable { final boolean deleteNonDurableQueue, final boolean manage) { // This constructor exists for version compatibility on the API. - // it will pass the consume as a browse + // it will pass consume as browse this(name, send, consume, createDurableQueue, deleteDurableQueue, createNonDurableQueue, deleteNonDurableQueue, manage, consume); } @@ -95,7 +100,22 @@ public class Role implements Serializable { final boolean browse) { // This constructor exists for version compatibility on the API. If either createDurableQueue or createNonDurableQueue // is true then createAddress will be true. If either deleteDurableQueue or deleteNonDurableQueue is true then deleteAddress will be true. - this(name, send, consume, createDurableQueue, deleteDurableQueue, createNonDurableQueue, deleteNonDurableQueue, manage, browse, createDurableQueue || createNonDurableQueue, deleteDurableQueue || deleteNonDurableQueue); + this(name, send, consume, createDurableQueue, deleteDurableQueue, createNonDurableQueue, deleteNonDurableQueue, manage, browse, createDurableQueue || createNonDurableQueue, deleteDurableQueue || deleteNonDurableQueue, false, false); + } + + @Deprecated + public Role(final String name, + final boolean send, + final boolean consume, + final boolean createDurableQueue, + final boolean deleteDurableQueue, + final boolean createNonDurableQueue, + final boolean deleteNonDurableQueue, + final boolean manage, + final boolean browse, + final boolean createAddress, + final boolean deleteAddress) { + this(name, send, consume, createDurableQueue, deleteDurableQueue, createNonDurableQueue, deleteNonDurableQueue, manage, browse, createAddress, deleteAddress, false, false); } public Role(final String name, @@ -108,7 +128,9 @@ public class Role implements Serializable { final boolean manage, final boolean browse, final boolean createAddress, - final boolean deleteAddress) { + final boolean deleteAddress, + final boolean view, + final boolean edit) { if (name == null) { throw new NullPointerException("name is null"); } @@ -123,6 +145,8 @@ public class Role implements Serializable { this.deleteNonDurableQueue = deleteNonDurableQueue; this.manage = manage; this.browse = browse; + this.view = view; + this.edit = edit; } public String getName() { @@ -247,7 +271,12 @@ public class Role implements Serializable { if (browse) { stringReturn.append(" browse "); } - + if (view) { + stringReturn.append(" view "); + } + if (edit) { + stringReturn.append(" edit "); + } stringReturn.append("]}"); return stringReturn.toString(); @@ -297,6 +326,12 @@ public class Role implements Serializable { if (!name.equals(role.name)) { return false; } + if (view != role.view) { + return false; + } + if (edit != role.edit) { + return false; + } return true; } @@ -315,6 +350,8 @@ public class Role implements Serializable { result = 31 * result + (deleteNonDurableQueue ? 1 : 0); result = 31 * result + (manage ? 1 : 0); result = 31 * result + (browse ? 1 : 0); + result = 31 * result + (view ? 1 : 0); + result = 31 * result + (edit ? 1 : 0); return result; } @@ -329,5 +366,23 @@ public class Role implements Serializable { deleteNonDurableQueue = deleteNonDurableQueue || other.deleteNonDurableQueue; manage = manage || other.manage; browse = browse || other.browse; + view = view || other.view; + edit = edit || other.edit; + } + + public boolean isEdit() { + return edit; + } + + public void setEdit(boolean edit) { + this.edit = edit; + } + + public boolean isView() { + return view; + } + + public void setView(boolean view) { + this.view = view; } } diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/utils/SecurityFormatter.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/utils/SecurityFormatter.java index 14d2b20c5b..9dfd54c3c5 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/utils/SecurityFormatter.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/utils/SecurityFormatter.java @@ -61,7 +61,7 @@ public class SecurityFormatter { Set roles = new HashSet<>(allRoles.size()); for (String role : allRoles) { - roles.add(new Role(role, send.contains(role), consume.contains(role), createDurableQueue.contains(role), deleteDurableQueue.contains(role), createNonDurableQueue.contains(role), deleteNonDurableQueue.contains(role), manageRoles.contains(role), browse.contains(role), createAddressRoles.contains(role), deleteAddressRoles.contains(role))); + roles.add(new Role(role, send.contains(role), consume.contains(role), createDurableQueue.contains(role), deleteDurableQueue.contains(role), createNonDurableQueue.contains(role), deleteNonDurableQueue.contains(role), manageRoles.contains(role), browse.contains(role), createAddressRoles.contains(role), deleteAddressRoles.contains(role), false, false)); } return roles; } diff --git a/artemis-features/src/main/resources/org.apache.activemq.artemis.cfg b/artemis-features/src/main/resources/org.apache.activemq.artemis.cfg index 12bac35ba5..e756765a96 100644 --- a/artemis-features/src/main/resources/org.apache.activemq.artemis.cfg +++ b/artemis-features/src/main/resources/org.apache.activemq.artemis.cfg @@ -2,3 +2,4 @@ config=file:${karaf.etc}/artemis.xml name=local domain=karaf rolePrincipalClass=org.apache.karaf.jaas.boot.principal.RolePrincipal +userPrincipalClass=org.apache.karaf.jaas.boot.principal.UserPrincipal diff --git a/artemis-hawtio/artemis-console/pom.xml b/artemis-hawtio/artemis-console/pom.xml index 802c9296ab..e6632cee0d 100644 --- a/artemis-hawtio/artemis-console/pom.xml +++ b/artemis-hawtio/artemis-console/pom.xml @@ -132,12 +132,19 @@ - ${project.build.directory}/${project.build.finalName}/index.html + + ${project.build.directory}/${project.build.finalName}/index.html + ${project.build.directory}/${project.build.finalName}/WEB-INF/web.xml + <title>.*</title> <title>${project.name}</title> + + <load-on-startup>1</load-on-startup> + <load-on-startup>-1</load-on-startup> + diff --git a/artemis-server-osgi/src/main/java/org/apache/activemq/artemis/osgi/OsgiBroker.java b/artemis-server-osgi/src/main/java/org/apache/activemq/artemis/osgi/OsgiBroker.java index 05b5984669..8e29aaee35 100644 --- a/artemis-server-osgi/src/main/java/org/apache/activemq/artemis/osgi/OsgiBroker.java +++ b/artemis-server-osgi/src/main/java/org/apache/activemq/artemis/osgi/OsgiBroker.java @@ -57,6 +57,7 @@ public class OsgiBroker { private String name; private String configurationUrl; private String rolePrincipalClass; + private String userPrincipalClass; private Map components; private Map> registrations; private ServiceTracker tracker; @@ -69,11 +70,16 @@ public class OsgiBroker { configurationUrl = getMandatory(properties, "config"); name = getMandatory(properties, "name"); rolePrincipalClass = (String) properties.get("rolePrincipalClass"); + userPrincipalClass = (String) properties.get("userPrincipalClass"); + String domain = getMandatory(properties, "domain"); ActiveMQJAASSecurityManager security = new ActiveMQJAASSecurityManager(domain); if (rolePrincipalClass != null) { security.setRolePrincipalClass(rolePrincipalClass); } + if (userPrincipalClass != null) { + security.setUserPrincipalClass(userPrincipalClass); + } String brokerInstance = null; String artemisDataDir = System.getProperty("artemis.data"); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java index 2ed4ebca82..edb56c3bd7 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java @@ -1496,4 +1496,17 @@ public interface Configuration { Configuration setLargeMessageSync(boolean largeMessageSync); boolean isLargeMessageSync(); + + String getViewPermissionMethodMatchPattern(); + + void setViewPermissionMethodMatchPattern(String permissionMatchPattern); + + boolean isManagementMessageRbac(); + + void setManagementMessageRbac(boolean val); + + String getManagementRbacPrefix(); + + void setManagementRbacPrefix(String prefix); + } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java index 4e7ecf87c1..fd65a73ef4 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java @@ -434,6 +434,12 @@ public class ConfigurationImpl implements Configuration, Serializable { private String literalMatchMarkers = ActiveMQDefaultConfiguration.getLiteralMatchMarkers(); + private String viewPermissionMethodMatchPattern = ActiveMQDefaultConfiguration.getViewPermissionMethodMatchPattern(); + + private String managementRbacPrefix = ActiveMQDefaultConfiguration.getManagementRbacPrefix(); + + private boolean managementMessagesRbac = ActiveMQDefaultConfiguration.getManagementMessagesRbac(); + /** * Parent folder for all data folders. */ @@ -441,7 +447,6 @@ public class ConfigurationImpl implements Configuration, Serializable { private transient JsonObject jsonStatus = JsonLoader.createObjectBuilder().build(); private transient Checksum transientChecksum = null; - private JsonObject getJsonStatus() { if (jsonStatus == null) { jsonStatus = JsonLoader.createObjectBuilder().build(); @@ -3308,6 +3313,36 @@ public class ConfigurationImpl implements Configuration, Serializable { return largeMessageSync; } + @Override + public String getViewPermissionMethodMatchPattern() { + return viewPermissionMethodMatchPattern; + } + + @Override + public void setViewPermissionMethodMatchPattern(String permissionMatchPattern) { + viewPermissionMethodMatchPattern = permissionMatchPattern; + } + + @Override + public boolean isManagementMessageRbac() { + return managementMessagesRbac; + } + + @Override + public void setManagementMessageRbac(boolean val) { + this.managementMessagesRbac = val; + } + + @Override + public String getManagementRbacPrefix() { + return managementRbacPrefix; + } + + @Override + public void setManagementRbacPrefix(String prefix) { + this.managementRbacPrefix = prefix; + } + // extend property utils with ability to auto-fill and locate from collections // collection entries are identified by the name() property private static class CollectionAutoFillPropertiesUtil extends PropertyUtilsBean { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java index 7808df5187..09653e5d6d 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java @@ -204,6 +204,10 @@ public final class FileConfigurationParser extends XMLConfigurationUtil { private static final String DELETEADDRESS_NAME = "deleteAddress"; + private static final String VIEW_NAME = "view"; + + private static final String EDIT_NAME = "edit"; + // Address parsing private static final String DEAD_LETTER_ADDRESS_NODE_NAME = "dead-letter-address"; @@ -839,6 +843,12 @@ public final class FileConfigurationParser extends XMLConfigurationUtil { config.setLargeMessageSync(getBoolean(e, "large-message-sync", config.isLargeMessageSync())); + config.setViewPermissionMethodMatchPattern(getString(e, "view-permission-method-match-pattern", config.getViewPermissionMethodMatchPattern(), NO_CHECK)); + + config.setManagementMessageRbac(getBoolean(e, "management-message-rbac", config.isManagementMessageRbac())); + + config.setManagementRbacPrefix(getString(e, "management-rbac-prefix", config.getManagementRbacPrefix(), NO_CHECK)); + parseAddressSettings(e, config); parseResourceLimits(e, config); @@ -1151,6 +1161,8 @@ public final class FileConfigurationParser extends XMLConfigurationUtil { ArrayList browseRoles = new ArrayList<>(); ArrayList createAddressRoles = new ArrayList<>(); ArrayList deleteAddressRoles = new ArrayList<>(); + ArrayList viewRoles = new ArrayList<>(); + ArrayList editRoles = new ArrayList<>(); ArrayList allRoles = new ArrayList<>(); NodeList children = node.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { @@ -1187,6 +1199,10 @@ public final class FileConfigurationParser extends XMLConfigurationUtil { createAddressRoles.add(role.trim()); } else if (DELETEADDRESS_NAME.equals(type)) { deleteAddressRoles.add(role.trim()); + } else if (VIEW_NAME.equals(type)) { + viewRoles.add(role.trim()); + } else if (EDIT_NAME.equals(type)) { + editRoles.add(role.trim()); } else { ActiveMQServerLogger.LOGGER.rolePermissionConfigurationError(type); } @@ -1198,7 +1214,7 @@ public final class FileConfigurationParser extends XMLConfigurationUtil { } for (String role : allRoles) { - securityRoles.add(new Role(role, send.contains(role), consume.contains(role), createDurableQueue.contains(role), deleteDurableQueue.contains(role), createNonDurableQueue.contains(role), deleteNonDurableQueue.contains(role), manageRoles.contains(role), browseRoles.contains(role), createAddressRoles.contains(role), deleteAddressRoles.contains(role))); + securityRoles.add(new Role(role, send.contains(role), consume.contains(role), createDurableQueue.contains(role), deleteDurableQueue.contains(role), createNonDurableQueue.contains(role), deleteNonDurableQueue.contains(role), manageRoles.contains(role), browseRoles.contains(role), createAddressRoles.contains(role), deleteAddressRoles.contains(role), viewRoles.contains(role), editRoles.contains(role))); } return securityMatch; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java index 9169c91d99..2dcabb3b92 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java @@ -2921,10 +2921,27 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active final String browseRoles, final String createAddressRoles, final String deleteAddressRoles) throws Exception { + addSecuritySettings(addressMatch, sendRoles, consumeRoles, createDurableQueueRoles, deleteDurableQueueRoles, createNonDurableQueueRoles, deleteNonDurableQueueRoles, manageRoles, browseRoles, createAddressRoles, deleteAddressRoles, "", ""); + } + + @Override + public void addSecuritySettings(final String addressMatch, + final String sendRoles, + final String consumeRoles, + final String createDurableQueueRoles, + final String deleteDurableQueueRoles, + final String createNonDurableQueueRoles, + final String deleteNonDurableQueueRoles, + final String manageRoles, + final String browseRoles, + final String createAddressRoles, + final String deleteAddressRoles, + final String viewRoles, + final String editRoles) throws Exception { if (AuditLogger.isBaseLoggingEnabled()) { AuditLogger.addSecuritySettings(this.server, addressMatch, sendRoles, consumeRoles, createDurableQueueRoles, deleteDurableQueueRoles, createNonDurableQueueRoles, deleteNonDurableQueueRoles, manageRoles, - browseRoles, createAddressRoles, deleteAddressRoles); + browseRoles, createAddressRoles, deleteAddressRoles, viewRoles, editRoles); } checkStarted(); @@ -2934,7 +2951,7 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active server.getSecurityRepository().addMatch(addressMatch, roles); - PersistedSecuritySetting persistedRoles = new PersistedSecuritySetting(addressMatch, sendRoles, consumeRoles, createDurableQueueRoles, deleteDurableQueueRoles, createNonDurableQueueRoles, deleteNonDurableQueueRoles, manageRoles, browseRoles, createAddressRoles, deleteAddressRoles); + PersistedSecuritySetting persistedRoles = new PersistedSecuritySetting(addressMatch, sendRoles, consumeRoles, createDurableQueueRoles, deleteDurableQueueRoles, createNonDurableQueueRoles, deleteNonDurableQueueRoles, manageRoles, browseRoles, createAddressRoles, deleteAddressRoles, viewRoles, editRoles); storageManager.storeSecuritySetting(persistedRoles); } finally { @@ -2974,19 +2991,7 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active int i = 0; for (Role role : roles) { - objRoles[i++] = new Object[]{ - role.getName(), - CheckType.SEND.hasRole(role), - CheckType.CONSUME.hasRole(role), - CheckType.CREATE_DURABLE_QUEUE.hasRole(role), - CheckType.DELETE_DURABLE_QUEUE.hasRole(role), - CheckType.CREATE_NON_DURABLE_QUEUE.hasRole(role), - CheckType.DELETE_NON_DURABLE_QUEUE.hasRole(role), - CheckType.MANAGE.hasRole(role), - CheckType.BROWSE.hasRole(role), - CheckType.CREATE_ADDRESS.hasRole(role), - CheckType.DELETE_ADDRESS.hasRole(role) - }; + objRoles[i++] = CheckType.asObjectArray(role); } return objRoles; } finally { @@ -4668,5 +4673,9 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active } ((SecurityStoreImpl)server.getSecurityStore()).invalidateAuthorizationCache(); } + + public ActiveMQServer getServer() { + return server; + } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/AddressControlImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/AddressControlImpl.java index 9044936d63..5aca9fa77f 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/AddressControlImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/AddressControlImpl.java @@ -214,19 +214,7 @@ public class AddressControlImpl extends AbstractControl implements AddressContro int i = 0; for (Role role : roles) { - objRoles[i++] = new Object[]{ - role.getName(), - CheckType.SEND.hasRole(role), - CheckType.CONSUME.hasRole(role), - CheckType.CREATE_DURABLE_QUEUE.hasRole(role), - CheckType.DELETE_DURABLE_QUEUE.hasRole(role), - CheckType.CREATE_NON_DURABLE_QUEUE.hasRole(role), - CheckType.DELETE_NON_DURABLE_QUEUE.hasRole(role), - CheckType.MANAGE.hasRole(role), - CheckType.BROWSE.hasRole(role), - CheckType.CREATE_ADDRESS.hasRole(role), - CheckType.DELETE_ADDRESS.hasRole(role) - }; + objRoles[i++] = CheckType.asObjectArray(role); } return objRoles; } finally { @@ -485,7 +473,7 @@ public class AddressControlImpl extends AbstractControl implements AddressContro try { return sendMessage(addressInfo.getName(), server, headers, type, body, durable, user, password, createMessageId); } catch (Exception e) { - e.printStackTrace(); + logger.debug("Failed to sendMessage", e); throw new IllegalStateException(e.getMessage()); } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ManagementRemotingConnection.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ManagementRemotingConnection.java index 3c494356ed..b3487a54d0 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ManagementRemotingConnection.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ManagementRemotingConnection.java @@ -35,6 +35,8 @@ import org.apache.activemq.artemis.spi.core.remoting.ReadyListener; public class ManagementRemotingConnection implements RemotingConnection { + Subject subject; + @Override public Object getID() { return "management"; @@ -170,11 +172,12 @@ public class ManagementRemotingConnection implements RemotingConnection { @Override public void setSubject(Subject subject) { + this.subject = subject; } @Override public Subject getSubject() { - return null; + return subject; } @Override diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/config/PersistedSecuritySetting.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/config/PersistedSecuritySetting.java index d17de9ec4f..02c4f45d96 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/config/PersistedSecuritySetting.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/persistence/config/PersistedSecuritySetting.java @@ -50,6 +50,10 @@ public class PersistedSecuritySetting implements EncodingSupport { private SimpleString deleteAddressRoles; + private SimpleString viewRoles; + + private SimpleString editRoles; + public PersistedSecuritySetting() { } @@ -66,6 +70,8 @@ public class PersistedSecuritySetting implements EncodingSupport { * @param browseRoles * @param createAddressRoles * @param deleteAddressRoles + * @param viewRoles + * @param editRoles */ public PersistedSecuritySetting(final String addressMatch, final String sendRoles, @@ -77,7 +83,9 @@ public class PersistedSecuritySetting implements EncodingSupport { final String manageRoles, final String browseRoles, final String createAddressRoles, - final String deleteAddressRoles) { + final String deleteAddressRoles, + final String viewRoles, + final String editRoles) { super(); this.addressMatch = SimpleString.toSimpleString(addressMatch); this.sendRoles = SimpleString.toSimpleString(sendRoles); @@ -90,6 +98,8 @@ public class PersistedSecuritySetting implements EncodingSupport { this.browseRoles = SimpleString.toSimpleString(browseRoles); this.createAddressRoles = SimpleString.toSimpleString(createAddressRoles); this.deleteAddressRoles = SimpleString.toSimpleString(deleteAddressRoles); + this.viewRoles = SimpleString.toSimpleString(viewRoles); + this.editRoles = SimpleString.toSimpleString(editRoles); } @@ -112,70 +122,83 @@ public class PersistedSecuritySetting implements EncodingSupport { * @return the sendRoles */ public String getSendRoles() { - return sendRoles != null ? sendRoles.toString() : null; + return stringFrom(sendRoles); } /** * @return the consumeRoles */ public String getConsumeRoles() { - return consumeRoles != null ? consumeRoles.toString() : null; + return stringFrom(consumeRoles); } /** * @return the createDurableQueueRoles */ public String getCreateDurableQueueRoles() { - return createDurableQueueRoles != null ? createDurableQueueRoles.toString() : null; + return stringFrom(createDurableQueueRoles); } /** * @return the deleteDurableQueueRoles */ public String getDeleteDurableQueueRoles() { - return deleteDurableQueueRoles != null ? deleteDurableQueueRoles.toString() : null; + return stringFrom(deleteDurableQueueRoles); } /** * @return the createNonDurableQueueRoles */ public String getCreateNonDurableQueueRoles() { - return createNonDurableQueueRoles != null ? createNonDurableQueueRoles.toString() : null; + return stringFrom(createNonDurableQueueRoles); } /** * @return the deleteNonDurableQueueRoles */ public String getDeleteNonDurableQueueRoles() { - return deleteNonDurableQueueRoles != null ? deleteNonDurableQueueRoles.toString() : null; + return stringFrom(deleteNonDurableQueueRoles); } /** * @return the manageRoles */ public String getManageRoles() { - return manageRoles != null ? manageRoles.toString() : null; + return stringFrom(manageRoles); } /** * @return the browseRoles */ public String getBrowseRoles() { - return browseRoles != null ? browseRoles.toString() : null; + return stringFrom(browseRoles); } /** * @return the createAddressRoles */ public String getCreateAddressRoles() { - return createAddressRoles != null ? createAddressRoles.toString() : null; + return stringFrom(createAddressRoles); } /** * @return the deleteAddressRoles */ public String getDeleteAddressRoles() { - return deleteAddressRoles != null ? deleteAddressRoles.toString() : null; + return stringFrom(deleteAddressRoles); + } + + + public String getViewRoles() { + return stringFrom(viewRoles); + } + + public String getEditRoles() { + return stringFrom(editRoles); + } + + private String stringFrom(SimpleString possiblyNullSimpleString) { + return possiblyNullSimpleString != null ? possiblyNullSimpleString.toString() : null; } @Override @@ -194,6 +217,8 @@ public class PersistedSecuritySetting implements EncodingSupport { buffer.writeNullableSimpleString(browseRoles); buffer.writeNullableSimpleString(createAddressRoles); buffer.writeNullableSimpleString(deleteAddressRoles); + buffer.writeNullableSimpleString(viewRoles); + buffer.writeNullableSimpleString(editRoles); } @Override @@ -209,7 +234,9 @@ public class PersistedSecuritySetting implements EncodingSupport { (manageRoles == null ? SIZE_NULL : SimpleString.sizeofNullableString(manageRoles)) + (browseRoles == null ? SIZE_NULL : SimpleString.sizeofNullableString(browseRoles)) + (createAddressRoles == null ? SIZE_NULL : SimpleString.sizeofNullableString(createAddressRoles)) + - (deleteAddressRoles == null ? SIZE_NULL : SimpleString.sizeofNullableString(deleteAddressRoles)); + (deleteAddressRoles == null ? SIZE_NULL : SimpleString.sizeofNullableString(deleteAddressRoles)) + + (viewRoles == null ? SIZE_NULL : SimpleString.sizeofNullableString(viewRoles)) + + (editRoles == null ? SIZE_NULL : SimpleString.sizeofNullableString(editRoles)); } @Override @@ -225,6 +252,8 @@ public class PersistedSecuritySetting implements EncodingSupport { browseRoles = buffer.readNullableSimpleString(); createAddressRoles = buffer.readNullableSimpleString(); deleteAddressRoles = buffer.readNullableSimpleString(); + viewRoles = buffer.readNullableSimpleString(); + editRoles = buffer.readNullableSimpleString(); } /* (non-Javadoc) @@ -245,6 +274,8 @@ public class PersistedSecuritySetting implements EncodingSupport { result = prime * result + ((createAddressRoles == null) ? 0 : createAddressRoles.hashCode()); result = prime * result + ((deleteAddressRoles == null) ? 0 : deleteAddressRoles.hashCode()); result = prime * result + ((sendRoles == null) ? 0 : sendRoles.hashCode()); + result = prime * result + ((viewRoles == null) ? 0 : viewRoles.hashCode()); + result = prime * result + ((editRoles == null) ? 0 : editRoles.hashCode()); result = prime * result + (int) (storeId ^ (storeId >>> 32)); return result; } @@ -316,6 +347,16 @@ public class PersistedSecuritySetting implements EncodingSupport { return false; } else if (!sendRoles.equals(other.sendRoles)) return false; + if (viewRoles == null) { + if (other.viewRoles != null) + return false; + } else if (!viewRoles.equals(other.viewRoles)) + return false; + if (editRoles == null) { + if (other.editRoles != null) + return false; + } else if (!editRoles.equals(other.editRoles)) + return false; if (storeId != other.storeId) return false; return true; @@ -349,6 +390,9 @@ public class PersistedSecuritySetting implements EncodingSupport { createAddressRoles + ", deleteAddressRoles=" + deleteAddressRoles + + ", viewRoles=" + + viewRoles + + ", editRoles=" + editRoles + "]"; } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/CheckType.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/CheckType.java index c4bd70539c..ab345ac4b2 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/CheckType.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/CheckType.java @@ -76,7 +76,38 @@ public enum CheckType { public boolean hasRole(final Role role) { return role.isBrowse(); } + }, + VIEW { + @Override + public boolean hasRole(final Role role) { + return role.isView(); + } + }, + EDIT { + @Override + public boolean hasRole(final Role role) { + return role.isEdit(); + } }; + public static Object[] asObjectArray(Role role) { + // order is important! + return new Object[]{ + role.getName(), + CheckType.SEND.hasRole(role), + CheckType.CONSUME.hasRole(role), + CheckType.CREATE_DURABLE_QUEUE.hasRole(role), + CheckType.DELETE_DURABLE_QUEUE.hasRole(role), + CheckType.CREATE_NON_DURABLE_QUEUE.hasRole(role), + CheckType.DELETE_NON_DURABLE_QUEUE.hasRole(role), + CheckType.MANAGE.hasRole(role), + CheckType.BROWSE.hasRole(role), + CheckType.CREATE_ADDRESS.hasRole(role), + CheckType.DELETE_ADDRESS.hasRole(role), + CheckType.VIEW.hasRole(role), + CheckType.EDIT.hasRole(role) + }; + } + public abstract boolean hasRole(Role role); } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java index 201e521371..26440c379e 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java @@ -46,7 +46,6 @@ import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager4; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5; import org.apache.activemq.artemis.spi.core.security.jaas.NoCacheLoginException; -import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; import org.apache.activemq.artemis.utils.CompositeAddress; import org.apache.activemq.artemis.utils.collections.ConcurrentHashSet; import org.apache.activemq.artemis.utils.collections.TypedProperties; @@ -221,7 +220,11 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC connection.setSubject(subject); } if (AuditLogger.isResourceLoggingEnabled()) { - AuditLogger.userSuccesfullyAuthenticatedInAudit(subject, connection.getRemoteAddress(), connection.getID().toString()); + if (connection != null) { + AuditLogger.userSuccesfullyAuthenticatedInAudit(subject, connection.getRemoteAddress(), connection.getID().toString()); + } else { + AuditLogger.userSuccesfullyAuthenticatedInAudit(subject, null, null); + } } return validatedUser; @@ -303,7 +306,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC props.putSimpleStringProperty(ManagementHelper.HDR_ADDRESS, bareAddress); props.putSimpleStringProperty(ManagementHelper.HDR_CHECK_TYPE, new SimpleString(checkType.toString())); - props.putSimpleStringProperty(ManagementHelper.HDR_USER, SimpleString.toSimpleString(user)); + props.putSimpleStringProperty(ManagementHelper.HDR_USER, SimpleString.toSimpleString(getCaller(user, session.getRemotingConnection().getSubject()))); Notification notification = new Notification(null, CoreNotificationType.SECURITY_PERMISSION_VIOLATION, props); @@ -312,15 +315,23 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC Exception ex; if (bareQueue == null) { - ex = ActiveMQMessageBundle.BUNDLE.userNoPermissions(session.getUsername(), checkType, bareAddress); + ex = ActiveMQMessageBundle.BUNDLE.userNoPermissions(getCaller(user, session.getRemotingConnection().getSubject()), checkType, bareAddress); } else { - ex = ActiveMQMessageBundle.BUNDLE.userNoPermissionsQueue(session.getUsername(), checkType, bareQueue, bareAddress); + ex = ActiveMQMessageBundle.BUNDLE.userNoPermissionsQueue(getCaller(user, session.getRemotingConnection().getSubject()), checkType, bareQueue, bareAddress); } AuditLogger.securityFailure(session.getRemotingConnection().getSubject(), session.getRemotingConnection().getRemoteAddress(), ex.getMessage(), ex); throw ex; } // if we get here we're granted, add to the cache + + if (user == null) { + // should get all user/pass into a subject and only cache subjects + // till then when subject is in play, the user may be null and + // we cannot cache as we don't have a unique key + return; + } + ConcurrentHashSet set; String key = createAuthorizationCacheKey(user, checkType); ConcurrentHashSet act = getAuthorizationCacheEntry(key); @@ -340,19 +351,15 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC // we don't invalidate the authentication cache here because it's not necessary } - public static String getUserFromSubject(Subject subject) { - if (subject == null) { - return null; - } + public String getUserFromSubject(Subject subject) { + return securityManager.getUserFromSubject(subject); + } - String validatedUser = ""; - Set users = subject.getPrincipals(UserPrincipal.class); - - // should only ever be 1 UserPrincipal - for (UserPrincipal userPrincipal : users) { - validatedUser = userPrincipal.getName(); + public String getCaller(String user, Subject subject) { + if (user != null) { + return user; } - return validatedUser; + return getUserFromSubject(subject); } /** @@ -390,7 +397,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC ActiveMQServerLogger.LOGGER.securityProblemWhileAuthenticating(e.getMessage()); if (AuditLogger.isResourceLoggingEnabled()) { - AuditLogger.userFailedAuthenticationInAudit(null, e.getMessage(), connection.getID().toString()); + AuditLogger.userFailedAuthenticationInAudit(null, e.getMessage(), connection == null ? "null" : connection.getID().toString()); } throw e; diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/LegacyLDAPSecuritySettingPlugin.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/LegacyLDAPSecuritySettingPlugin.java index d31a242970..e9942c48ec 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/LegacyLDAPSecuritySettingPlugin.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/LegacyLDAPSecuritySettingPlugin.java @@ -463,7 +463,9 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin { mapAdminToManage ? admin : false, // manage - map to admin based on configuration read, // browse admin, // createAddress - admin); // deleteAddress + admin, // deleteAddress + read, // view + write); // edit if (existingRole != null) { existingRole.merge(newRole); } else { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java index 3e3f268d64..60d3079de4 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ServerSessionImpl.java @@ -2214,7 +2214,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener { throw e; } - Message reply = managementService.handleMessage(message); + Message reply = managementService.handleMessage(this, message); SimpleString replyTo = message.getReplyTo(); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisMBeanServerBuilder.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisMBeanServerBuilder.java index 58fc5cf31d..7eea8ed314 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisMBeanServerBuilder.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisMBeanServerBuilder.java @@ -51,7 +51,7 @@ public class ArtemisMBeanServerBuilder extends MBeanServerBuilder { private static final class MBeanInvocationHandler implements InvocationHandler { private final MBeanServer wrapped; - private final List guarded = Collections.unmodifiableList(Arrays.asList("invoke", "getAttribute", "getAttributes", "setAttribute", "setAttributes")); + private final List guarded = Collections.unmodifiableList(Arrays.asList("invoke", "getAttribute", "getAttributes", "setAttribute", "setAttributes", "queryMBeans")); MBeanInvocationHandler(MBeanServer mbeanServer) { wrapped = mbeanServer; @@ -75,9 +75,6 @@ public class ArtemisMBeanServerBuilder extends MBeanServerBuilder { } guard.invoke(proxy, method, args); } - if (method.getName().equals("queryMBeans")) { - guard.invoke(wrapped, method, args); - } if (method.getName().equals("equals") && method.getParameterTypes().length == 1 && method.getParameterTypes()[0] == Object.class) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisMBeanServerGuard.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisMBeanServerGuard.java index 735cb35210..b7f973ccde 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisMBeanServerGuard.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisMBeanServerGuard.java @@ -32,14 +32,13 @@ import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.security.auth.Subject; import java.io.IOException; -import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.security.AccessControlContext; import java.security.AccessController; import java.security.Principal; import java.util.List; -public class ArtemisMBeanServerGuard implements InvocationHandler { +public class ArtemisMBeanServerGuard implements GuardInvocationHandler { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @@ -124,6 +123,7 @@ public class ArtemisMBeanServerGuard implements InvocationHandler { return jmxAccessControlList.isInAllowList(objectName); } + @Override public boolean canInvoke(String object, String operationName) { ObjectName objectName = null; try { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacInvocationHandler.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacInvocationHandler.java new file mode 100644 index 0000000000..b400433663 --- /dev/null +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacInvocationHandler.java @@ -0,0 +1,368 @@ +/** + * 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.activemq.artemis.core.server.management; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServer; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.security.auth.Subject; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.util.Collection; +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.activemq.artemis.api.core.SimpleString; +import org.apache.activemq.artemis.core.management.impl.ActiveMQServerControlImpl; +import org.apache.activemq.artemis.core.management.impl.ManagementRemotingConnection; +import org.apache.activemq.artemis.core.security.CheckType; +import org.apache.activemq.artemis.core.security.SecurityAuth; +import org.apache.activemq.artemis.core.server.ActivateCallback; +import org.apache.activemq.artemis.core.server.ActiveMQServer; +import org.apache.activemq.artemis.logs.AuditLogger; +import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection; + +public class ArtemisRbacInvocationHandler implements GuardInvocationHandler { + + private final List mBeanServerCheckedMethods = List.of("invoke", "getAttribute", "getAttributes", "setAttribute", "setAttributes", "queryMBeans", "queryNames"); + private final List uncheckedDomains = List.of("hawtio"); + + private final MBeanServer delegate; + private volatile ActiveMQServer activeMQServer; + String brokerDomain; + Pattern viewPermissionMatcher; + SimpleString rbacPrefix; + SimpleString mBeanServerRbacAddressPrefix; + + ArtemisRbacInvocationHandler(MBeanServer mbeanServer) { + delegate = mbeanServer; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + initAuditLoggerContext(); + + if (mBeanServerCheckedMethods.contains(method.getName())) { + + if (activeMQServer != null) { + // happily initialised, do our check + securityCheck(method, args); + + } else { + // initialisation pending registration of broker control with a check operation + + if (method.getName().startsWith("query")) { + // restrict result in favour of an exception + return null; + } + + if (!isUncheckedDomain(args)) { + throw new IllegalStateException("initialisation pending"); + } + } + } else { + initializeFromFirstServerMBeanRegistration(method, args); + } + + Object result; + try { + result = method.invoke(delegate, args); + } catch (InvocationTargetException ite) { + throw ite.getCause(); + } + + // filter query results based on RBAC + if (method.getName().startsWith("query") && result instanceof Collection) { + ((Collection) result).removeIf(this::viewPermissionCheckFails); + } + + return result; + } + + private boolean isUncheckedDomain(Object[] args) { + final ObjectName objectName = objectNameFrom(args); + return isUncheckedDomain(objectName); + } + + private boolean isUncheckedDomain(ObjectName objectName) { + if (objectName != null) { + return uncheckedDomains.contains(objectName.getDomain()); + } + return false; + } + + private ObjectName objectNameFrom(Object[] args) { + return (args != null && args.length > 0 && args[0] instanceof ObjectName) ? (ObjectName) args[0] : null; + } + + @Override + public boolean canInvoke(String name, String operationName) { + boolean okInvoke = false; + try { + final ObjectName objectName = ObjectName.getInstance(name); + if (!isUncheckedDomain(objectName)) { + final SimpleString rbacAddress = addressFrom(objectName, operationName); + securityStoreCheck(rbacAddress, permissionFrom(operationName)); + } + okInvoke = true; + } catch (Throwable expectedOnCheckFailOrInvalidObjectName) { + // denied + } + + return okInvoke; + } + + private void initializeFromFirstServerMBeanRegistration(Method method, Object[] args) { + if (activeMQServer == null && method.getName().equals("registerMBean")) { + if (args != null && args[0] instanceof ActiveMQServerControlImpl) { + activeMQServer = ((ActiveMQServerControlImpl) args[0]).getServer(); + brokerDomain = activeMQServer.getConfiguration().getJMXDomain(); + + viewPermissionMatcher = Pattern.compile(activeMQServer.getConfiguration().getViewPermissionMethodMatchPattern()); + rbacPrefix = SimpleString.toSimpleString(activeMQServer.getConfiguration().getManagementRbacPrefix()); + mBeanServerRbacAddressPrefix = rbacPrefix.concat(".mbeanserver."); + + ((ActiveMQServerControlImpl) args[0]).getServer().registerActivateCallback(new ActivateCallback() { + @Override + public void shutdown(ActiveMQServer server) { + try { + activeMQServer.getManagementService().unregisterHawtioSecurity(); + } catch (Exception bestEffortToTidyOnShutdown) { + } + activeMQServer = null; + } + }); + try { + activeMQServer.getManagementService().registerHawtioSecurity(this); + } catch (Exception bestEffort) { + bestEffort.printStackTrace(); + } + } + } + } + + private void initAuditLoggerContext() { + //if this is invoked via jolokia the address will be set by the filter + //if not we can deduct it from RMI, or it must be internal + if (AuditLogger.isAnyLoggingEnabled() && AuditLogger.getRemoteAddress() == null) { + String url = "internal"; + final String name = Thread.currentThread().getName(); + if (name.startsWith("RMI TCP Connection")) { + url = name.substring(name.indexOf('-') + 1); + } + AuditLogger.setRemoteAddress(url); + } + } + + // derive address to check from the method and args and then check relevant permission + void securityCheck(Method method, Object[] args) { + + if (isUncheckedDomain(args)) { + return; + } + + try { + + final String methodName = method.getName(); + + if ("getAttribute".equals(methodName)) { + handleGetAttribute(delegate, (ObjectName) args[0], (String) args[1]); + } else if ("getAttributes".equals(methodName)) { + handleGetAttributes(delegate, (ObjectName) args[0], (String[]) args[1]); + } else if ("setAttribute".equals(methodName)) { + handleSetAttribute(delegate, (ObjectName) args[0], (Attribute) args[1]); + } else if ("setAttributes".equals(methodName)) { + handleSetAttributes(delegate, (ObjectName) args[0], (AttributeList) args[1]); + } else if ("invoke".equals(methodName)) { + handleInvoke((ObjectName) args[0], (String) args[1]); + } else if (method.getName().startsWith("query")) { + + final SimpleString rbacAddress = mBeanServerRbacAddressPrefix.concat(methodName); + securityStoreCheck(rbacAddress, permissionFrom(methodName)); + } + + } catch (Exception e) { + throw new SecurityException(e.getMessage()); + } + } + + private void handleSetAttributes(MBeanServer delegate, ObjectName objectName, AttributeList attributeList) throws Exception { + for (Attribute attributeName : attributeList.asList()) { + handleSetAttribute(delegate, objectName, attributeName); + } + } + + private void handleSetAttribute(MBeanServer delegate, ObjectName objectName, Attribute attributeName) throws Exception { + handleInvoke(objectName, "set" + attributeName); + } + + private void handleGetAttributes(MBeanServer delegate, ObjectName objectName, String[] attributes) throws Exception { + for (String attribute : attributes) { + handleGetAttribute(delegate, objectName, attribute); + } + } + + private void handleGetAttribute(MBeanServer delegate, ObjectName objectName, String attributeName) throws Exception { + MBeanInfo info = delegate.getMBeanInfo(objectName); + String prefix = "get"; + for (MBeanAttributeInfo attr : info.getAttributes()) { + if (attr.getName().equals(attributeName)) { + prefix = attr.isIs() ? "is" : "get"; + break; + } + } + handleInvoke(objectName, prefix + attributeName); + } + + private void handleInvoke(ObjectName objectName, String operationName) throws Exception { + final SimpleString rbacAddress = addressFrom(objectName, operationName); + final CheckType permission = permissionFrom(operationName); + securityStoreCheck(rbacAddress, permission); + } + + CheckType permissionFrom(String methodName) { + if (methodName != null && viewPermissionMatcher.matcher(methodName).matches()) { + return CheckType.VIEW; + } + return CheckType.EDIT; + } + + String removeQuotes(String key) { + if (key != null && key.endsWith("\"")) { + return key.replace("\"", ""); + } + return key; + } + + SimpleString addressFrom(ObjectName objectName) { + return addressFrom(objectName, null); + } + + // depends on ObjectNameBuilder impl that makes ObjectNames for control objects + // jmx.<.type>[.component][.name][.operation] + SimpleString addressFrom(ObjectName objectName, String methodName) { + + String name = removeQuotes(objectName.getKeyProperty("name")); + String component = removeQuotes(objectName.getKeyProperty("component")); + String type = null; + SimpleString rbacAddress = rbacPrefix; + + if (brokerDomain.equals(objectName.getDomain())) { + if (component != null) { + if ("addresses".equals(component)) { + component = "address"; + + final String subComponent = objectName.getKeyProperty("subcomponent"); + if ("diverts".equals(subComponent)) { + component = "divert"; + } else if ("queues".equals(subComponent)) { + component = "queue"; + } + name = removeQuotes(objectName.getKeyProperty(component)); + } + } else { + // broker component, server control - identified by attribute with no component + final String brokerName = removeQuotes(objectName.getKeyProperty("broker")); + if (brokerName != null) { + component = "broker"; + } + } + } else { + // non artemis broker domain, prefix with domain + rbacAddress = rbacAddress.concat('.').concat(objectName.getDomain()); + type = removeQuotes(objectName.getKeyProperty("type")); + } + + if (type != null) { + rbacAddress = rbacAddress.concat('.').concat(type); + } + if (component != null) { + rbacAddress = rbacAddress.concat('.').concat(component); + } + if (name != null) { + rbacAddress = rbacAddress.concat('.').concat(name); + } + if (methodName != null) { + rbacAddress = rbacAddress.concat('.').concat(methodName); + } + + return rbacAddress; + } + + private boolean viewPermissionCheckFails(Object candidate) { + boolean failed = false; + ObjectName objectName = candidate instanceof ObjectInstance ? ((ObjectInstance) candidate).getObjectName() : (ObjectName) candidate; + if (!isUncheckedDomain(objectName)) { + try { + final SimpleString rbacAddress = addressFrom(objectName); + securityStoreCheck(rbacAddress, CheckType.VIEW); + } catch (Exception checkFailed) { + failed = true; + } + } + return failed; + } + + private void securityStoreCheck(SimpleString rbacAddress, CheckType checkType) throws Exception { + // use accessor as security store can be updated on config reload + activeMQServer.getSecurityStore().check(rbacAddress, checkType, delegateToAccessController); + } + + // sufficiently empty to delegate to use of AccessController + // ideally AccessController should be the source of truth + private final SecurityAuth delegateToAccessController = new SecurityAuth() { + + final ManagementRemotingConnection managementRemotingConnection = new ManagementRemotingConnection() { + @Override + public Subject getSubject() { + AccessControlContext accessControlContext = AccessController.getContext(); + if (accessControlContext != null) { + return Subject.getSubject(accessControlContext); + } + return null; + } + }; + + @Override + public String getUsername() { + return null; + } + + @Override + public String getPassword() { + return null; + } + + @Override + public RemotingConnection getRemotingConnection() { + return managementRemotingConnection; + } + + @Override + public String getSecurityDomain() { + return null; + } + }; +} diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacMBeanServerBuilder.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacMBeanServerBuilder.java new file mode 100644 index 0000000000..a4f6e599b6 --- /dev/null +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacMBeanServerBuilder.java @@ -0,0 +1,32 @@ +/* + * 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.activemq.artemis.core.server.management; + +import javax.management.MBeanServer; +import javax.management.MBeanServerBuilder; +import javax.management.MBeanServerDelegate; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; + +public final class ArtemisRbacMBeanServerBuilder extends MBeanServerBuilder { + + @Override + public MBeanServer newMBeanServer(String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) { + InvocationHandler handler = new ArtemisRbacInvocationHandler(super.newMBeanServer(defaultDomain, outer, delegate)); + return (MBeanServer) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{MBeanServer.class}, handler); + } +} diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/GuardInvocationHandler.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/GuardInvocationHandler.java new file mode 100644 index 0000000000..5773a06bb6 --- /dev/null +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/GuardInvocationHandler.java @@ -0,0 +1,25 @@ +/* + * 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.activemq.artemis.core.server.management; + +import java.lang.reflect.InvocationHandler; + +public interface GuardInvocationHandler extends InvocationHandler { + + boolean canInvoke(String object, String operationName); +} diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementContext.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementContext.java index 5109641838..4586d6994e 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementContext.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementContext.java @@ -17,12 +17,8 @@ package org.apache.activemq.artemis.core.server.management; -import javax.management.NotCompliantMBeanException; - import org.apache.activemq.artemis.core.config.JMXConnectorConfiguration; -import org.apache.activemq.artemis.core.persistence.StorageManager; import org.apache.activemq.artemis.core.server.ServiceComponent; -import org.apache.activemq.artemis.core.server.management.impl.HawtioSecurityControlImpl; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager; public class ManagementContext implements ServiceComponent { @@ -31,16 +27,17 @@ public class ManagementContext implements ServiceComponent { private JMXAccessControlList accessControlList; private JMXConnectorConfiguration jmxConnectorConfiguration; private ManagementConnector mBeanServer; - private ArtemisMBeanServerGuard guardHandler; + private GuardInvocationHandler guard; private ActiveMQSecurityManager securityManager; public void init() { if (accessControlList != null) { //if we are configured then assume we want to use the guard so set the system property System.setProperty("javax.management.builder.initial", ArtemisMBeanServerBuilder.class.getCanonicalName()); - guardHandler = new ArtemisMBeanServerGuard(); + ArtemisMBeanServerGuard guardHandler = new ArtemisMBeanServerGuard(); guardHandler.setJMXAccessControlList(accessControlList); ArtemisMBeanServerBuilder.setGuard(guardHandler); + guard = guardHandler; } } @@ -101,21 +98,8 @@ public class ManagementContext implements ServiceComponent { this.jmxConnectorConfiguration = jmxConnectorConfiguration; } - public JMXConnectorConfiguration getJmxConnectorConfiguration() { - return jmxConnectorConfiguration; - } - - public HawtioSecurityControl getSecurityMBean(StorageManager storageManager) { - try { - return new HawtioSecurityControlImpl(guardHandler, storageManager); - } catch (NotCompliantMBeanException e) { - e.printStackTrace(); - return null; - } - } - - public ArtemisMBeanServerGuard getArtemisMBeanServerGuard() { - return guardHandler; + public GuardInvocationHandler getArtemisMBeanServerGuard() { + return guard; } public void setSecurityManager(ActiveMQSecurityManager securityManager) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementService.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementService.java index 48dcf86c85..4fb88c1858 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementService.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/ManagementService.java @@ -37,6 +37,7 @@ import org.apache.activemq.artemis.core.persistence.StorageManager; import org.apache.activemq.artemis.core.postoffice.PostOffice; import org.apache.activemq.artemis.core.remoting.server.RemotingService; import org.apache.activemq.artemis.core.security.Role; +import org.apache.activemq.artemis.core.security.SecurityAuth; import org.apache.activemq.artemis.core.security.SecurityStore; import org.apache.activemq.artemis.core.server.ActiveMQComponent; import org.apache.activemq.artemis.core.server.ActiveMQServer; @@ -137,13 +138,13 @@ public interface ManagementService extends NotificationService, ActiveMQComponen Object[] getResources(Class resourceType); - ICoreMessage handleMessage(Message message) throws Exception; + ICoreMessage handleMessage(SecurityAuth auth, Message message) throws Exception; - void registerHawtioSecurity(ArtemisMBeanServerGuard securityMBean) throws Exception; + void registerHawtioSecurity(GuardInvocationHandler guardInvocationHandler) throws Exception; void unregisterHawtioSecurity() throws Exception; - Object getAttribute(String resourceName, String attribute); + Object getAttribute(String resourceName, String attribute, SecurityAuth auth); - Object invokeOperation(String resourceName, String operation, Object[] params) throws Exception; + Object invokeOperation(String resourceName, String operation, Object[] params, SecurityAuth auth) throws Exception; } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImpl.java index 1bce41a1de..2a524676af 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImpl.java @@ -19,7 +19,7 @@ package org.apache.activemq.artemis.core.server.management.impl; import org.apache.activemq.artemis.core.management.impl.AbstractControl; import org.apache.activemq.artemis.core.management.impl.MBeanInfoHelper; import org.apache.activemq.artemis.core.persistence.StorageManager; -import org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerGuard; +import org.apache.activemq.artemis.core.server.management.GuardInvocationHandler; import org.apache.activemq.artemis.core.server.management.HawtioSecurityControl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,9 +70,9 @@ public class HawtioSecurityControlImpl extends AbstractControl implements Hawtio * */ static final String[] CAN_INVOKE_RESULT_COLUMNS = SecurityMBeanOpenTypeInitializer.COLUMNS; - private final ArtemisMBeanServerGuard mBeanServerGuard; + private final GuardInvocationHandler mBeanServerGuard; - public HawtioSecurityControlImpl(ArtemisMBeanServerGuard mBeanServerGuard, StorageManager storageManager) throws NotCompliantMBeanException { + public HawtioSecurityControlImpl(GuardInvocationHandler mBeanServerGuard, StorageManager storageManager) throws NotCompliantMBeanException { super(HawtioSecurityControl.class, storageManager); this.mBeanServerGuard = mBeanServerGuard; } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImpl.java index 84b602a419..bd514e61f6 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImpl.java @@ -21,6 +21,7 @@ import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.NotificationBroadcasterSupport; import javax.management.ObjectName; +import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; @@ -31,6 +32,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; +import java.util.regex.Pattern; import org.apache.activemq.artemis.api.core.BroadcastEndpointFactory; import org.apache.activemq.artemis.api.core.BroadcastGroupConfiguration; @@ -48,8 +50,8 @@ import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl; import org.apache.activemq.artemis.api.core.management.AddressControl; import org.apache.activemq.artemis.api.core.management.BaseBroadcastGroupControl; import org.apache.activemq.artemis.api.core.management.BridgeControl; -import org.apache.activemq.artemis.api.core.management.ConnectionRouterControl; import org.apache.activemq.artemis.api.core.management.ClusterConnectionControl; +import org.apache.activemq.artemis.api.core.management.ConnectionRouterControl; import org.apache.activemq.artemis.api.core.management.DivertControl; import org.apache.activemq.artemis.api.core.management.ManagementHelper; import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder; @@ -63,8 +65,8 @@ import org.apache.activemq.artemis.core.management.impl.AddressControlImpl; import org.apache.activemq.artemis.core.management.impl.BaseBroadcastGroupControlImpl; import org.apache.activemq.artemis.core.management.impl.BridgeControlImpl; import org.apache.activemq.artemis.core.management.impl.BroadcastGroupControlImpl; -import org.apache.activemq.artemis.core.management.impl.ConnectionRouterControlImpl; import org.apache.activemq.artemis.core.management.impl.ClusterConnectionControlImpl; +import org.apache.activemq.artemis.core.management.impl.ConnectionRouterControlImpl; import org.apache.activemq.artemis.core.management.impl.DivertControlImpl; import org.apache.activemq.artemis.core.management.impl.JGroupsChannelBroadcastGroupControlImpl; import org.apache.activemq.artemis.core.management.impl.JGroupsFileBroadcastGroupControlImpl; @@ -77,7 +79,9 @@ import org.apache.activemq.artemis.core.paging.PagingManager; import org.apache.activemq.artemis.core.persistence.StorageManager; import org.apache.activemq.artemis.core.postoffice.PostOffice; import org.apache.activemq.artemis.core.remoting.server.RemotingService; +import org.apache.activemq.artemis.core.security.CheckType; import org.apache.activemq.artemis.core.security.Role; +import org.apache.activemq.artemis.core.security.SecurityAuth; import org.apache.activemq.artemis.core.security.SecurityStore; import org.apache.activemq.artemis.core.server.ActiveMQMessageBundle; import org.apache.activemq.artemis.core.server.ActiveMQServer; @@ -85,13 +89,12 @@ import org.apache.activemq.artemis.core.server.ActiveMQServerLogger; import org.apache.activemq.artemis.core.server.Divert; import org.apache.activemq.artemis.core.server.Queue; import org.apache.activemq.artemis.core.server.QueueFactory; -import org.apache.activemq.artemis.core.server.routing.ConnectionRouter; import org.apache.activemq.artemis.core.server.cluster.Bridge; import org.apache.activemq.artemis.core.server.cluster.BroadcastGroup; import org.apache.activemq.artemis.core.server.cluster.ClusterConnection; import org.apache.activemq.artemis.core.server.impl.AddressInfo; import org.apache.activemq.artemis.core.server.impl.CleaningActivateCallback; -import org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerGuard; +import org.apache.activemq.artemis.core.server.management.GuardInvocationHandler; import org.apache.activemq.artemis.core.server.management.HawtioSecurityControl; import org.apache.activemq.artemis.core.server.management.ManagementService; import org.apache.activemq.artemis.core.server.management.Notification; @@ -100,6 +103,7 @@ import org.apache.activemq.artemis.core.server.metrics.AddressMetricNames; import org.apache.activemq.artemis.core.server.metrics.BrokerMetricNames; import org.apache.activemq.artemis.core.server.metrics.MetricsManager; import org.apache.activemq.artemis.core.server.metrics.QueueMetricNames; +import org.apache.activemq.artemis.core.server.routing.ConnectionRouter; import org.apache.activemq.artemis.core.settings.HierarchicalRepository; import org.apache.activemq.artemis.core.settings.impl.AddressSettings; import org.apache.activemq.artemis.core.transaction.ResourceManager; @@ -108,7 +112,6 @@ import org.apache.activemq.artemis.utils.collections.ConcurrentHashSet; import org.apache.activemq.artemis.utils.collections.TypedProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.invoke.MethodHandles; import static org.apache.activemq.artemis.api.core.FilterConstants.NATIVE_MESSAGE_ID; @@ -156,6 +159,10 @@ public class ManagementServiceImpl implements ManagementService { private final ObjectNameBuilder objectNameBuilder; + private final SimpleString managementMessageRbacResourceNamePrefix; + + private final Pattern viewPermissionMatcher; + public ManagementServiceImpl(final MBeanServer mbeanServer, final Configuration configuration) { this.mbeanServer = mbeanServer; @@ -168,6 +175,8 @@ public class ManagementServiceImpl implements ManagementService { broadcaster = new NotificationBroadcasterSupport(); notificationsEnabled = true; objectNameBuilder = ObjectNameBuilder.create(configuration.getJMXDomain(), configuration.getName(), configuration.isJMXUseBrokerName()); + managementMessageRbacResourceNamePrefix = configuration.isManagementMessageRbac() ? SimpleString.toSimpleString(configuration.getManagementRbacPrefix()).concat('.') : null; + viewPermissionMatcher = Pattern.compile(configuration.getViewPermissionMethodMatchPattern()); } @@ -448,11 +457,8 @@ public class ManagementServiceImpl implements ManagementService { } else { control = new BaseBroadcastGroupControlImpl(broadcastGroup, storageManager, configuration); } - //shouldnt ever be null - if (control != null) { - registerInJMX(objectName, control); - registerInRegistry(ResourceNames.BROADCAST_GROUP + configuration.getName(), control); - } + registerInJMX(objectName, control); + registerInRegistry(ResourceNames.BROADCAST_GROUP + configuration.getName(), control); } @Override @@ -512,22 +518,22 @@ public class ManagementServiceImpl implements ManagementService { } @Override - public void registerHawtioSecurity(ArtemisMBeanServerGuard mBeanServerGuard) throws Exception { - ObjectName objectName = objectNameBuilder.getManagementContextObjectName(); - HawtioSecurityControl control = new HawtioSecurityControlImpl(mBeanServerGuard, storageManager); + public void registerHawtioSecurity(GuardInvocationHandler guard) throws Exception { + ObjectName objectName = objectNameBuilder.getSecurityObjectName(); + HawtioSecurityControl control = new HawtioSecurityControlImpl(guard, storageManager); registerInJMX(objectName, control); registerInRegistry(ResourceNames.MANAGEMENT_SECURITY, control); } @Override public void unregisterHawtioSecurity() throws Exception { - ObjectName objectName = objectNameBuilder.getManagementContextObjectName(); + ObjectName objectName = objectNameBuilder.getSecurityObjectName(); unregisterFromJMX(objectName); unregisterFromRegistry(ResourceNames.MANAGEMENT_SECURITY); } @Override - public ICoreMessage handleMessage(Message message) throws Exception { + public ICoreMessage handleMessage(SecurityAuth auth, Message message) throws Exception { message = message.toCore(); // a reply message is sent with the result stored in the message body. CoreMessage reply = new CoreMessage(storageManager.generateID(), 512); @@ -553,7 +559,7 @@ public class ManagementServiceImpl implements ManagementService { } try { - Object result = invokeOperation(resourceName, operation, params); + Object result = invokeOperation(resourceName, operation, params, auth); ManagementHelper.storeResult(reply, result); @@ -574,7 +580,7 @@ public class ManagementServiceImpl implements ManagementService { if (attribute != null) { try { - Object result = getAttribute(resourceName, attribute); + Object result = getAttribute(resourceName, attribute, auth); ManagementHelper.storeResult(reply, result); @@ -596,6 +602,21 @@ public class ManagementServiceImpl implements ManagementService { return reply; } + protected void securityCheck(String controlName, CheckType permission, SecurityAuth auth) throws Exception { + if (managementMessageRbacResourceNamePrefix == null) { + return; + } + final SimpleString address = managementMessageRbacResourceNamePrefix.concat(controlName); + securityStore.check(address, permission, auth); + } + + protected CheckType permissionForInvoke(String method) { + if (viewPermissionMatcher.matcher(method).matches()) { + return CheckType.VIEW; + } + return CheckType.EDIT; + } + @Override public synchronized Object getResource(final String resourceName) { return registry.get(resourceName); @@ -772,8 +793,6 @@ public class ManagementServiceImpl implements ManagementService { storageManager = null; - messagingServer = null; - registeredNames.clear(); started = false; @@ -849,7 +868,7 @@ public class ManagementServiceImpl implements ManagementService { } @Override - public Object getAttribute(final String resourceName, final String attribute) { + public Object getAttribute(final String resourceName, final String attribute, SecurityAuth auth) { try { Object resource = registry.get(resourceName); @@ -869,6 +888,11 @@ public class ManagementServiceImpl implements ManagementService { throw ActiveMQMessageBundle.BUNDLE.noGetterMethod(attribute); } } + + final String methodName = method.getName(); + + securityCheck(resourceName + "." + methodName, permissionForInvoke(methodName), auth); + return method.invoke(resource, new Object[0]); } catch (Throwable t) { throw new IllegalStateException("Problem while retrieving attribute " + attribute, t); @@ -877,14 +901,16 @@ public class ManagementServiceImpl implements ManagementService { @Override public Object invokeOperation(final String resourceName, - final String operation, - final Object[] params) throws Exception { + final String operation, + final Object[] params, + SecurityAuth auth) throws Exception { Object resource = registry.get(resourceName); if (resource == null) { throw ActiveMQMessageBundle.BUNDLE.cannotFindResource(resourceName); } + Method method = null; Method[] methods = resource.getClass().getMethods(); @@ -926,8 +952,10 @@ public class ManagementServiceImpl implements ManagementService { throw ActiveMQMessageBundle.BUNDLE.noOperation(operation, params.length); } - Object result = method.invoke(resource, params); - return result; + final String methodName = method.getName(); + securityCheck(resourceName + "." + methodName, permissionForInvoke(methodName), auth); + + return method.invoke(resource, params); } /** diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/routing/targets/LocalTarget.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/routing/targets/LocalTarget.java index afa13cc95c..cc0ffa4286 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/routing/targets/LocalTarget.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/routing/targets/LocalTarget.java @@ -60,11 +60,11 @@ public class LocalTarget extends AbstractTarget { @Override public T getAttribute(String resourceName, String attributeName, Class attributeClass, int timeout) throws Exception { - return (T)managementService.getAttribute(resourceName, attributeName); + return (T)managementService.getAttribute(resourceName, attributeName, null); } @Override public T invokeOperation(String resourceName, String operationName, Object[] operationParams, Class operationClass, int timeout) throws Exception { - return (T)managementService.invokeOperation(resourceName, operationName, operationParams); + return (T)managementService.invokeOperation(resourceName, operationName, operationParams, null); } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQBasicSecurityManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQBasicSecurityManager.java index 09cfb841d1..101bf66572 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQBasicSecurityManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQBasicSecurityManager.java @@ -56,7 +56,6 @@ public class ActiveMQBasicSecurityManager implements ActiveMQSecurityManager5, U public static final String BOOTSTRAP_ROLE_FILE = "bootstrapRoleFile"; private Map properties; - private String rolePrincipalClass = RolePrincipal.class.getName(); private StorageManager storageManager; @Override @@ -85,7 +84,7 @@ public class ActiveMQBasicSecurityManager implements ActiveMQSecurityManager5, U Subject subject = new Subject(); subject.getPrincipals().add(new UserPrincipal(userToAuthenticate)); for (String role : getRole(userToAuthenticate).getRoles()) { - subject.getPrincipals().add((Principal) SecurityManagerUtil.createGroupPrincipal(role, rolePrincipalClass)); + subject.getPrincipals().add((Principal) SecurityManagerUtil.createGroupPrincipal(role, RolePrincipal.class)); } return subject; } @@ -108,7 +107,7 @@ public class ActiveMQBasicSecurityManager implements ActiveMQSecurityManager5, U final Set roles, final CheckType checkType, final String address) { - boolean authorized = SecurityManagerUtil.authorize(subject, roles, checkType, rolePrincipalClass); + boolean authorized = SecurityManagerUtil.authorize(subject, roles, checkType, RolePrincipal.class); if (authorized) { logger.trace("user is authorized"); } else { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManager.java index e73ebaa6af..db8b606773 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManager.java @@ -20,6 +20,7 @@ import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import java.lang.invoke.MethodHandles; +import java.security.Principal; import java.util.Set; import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration; @@ -29,6 +30,7 @@ import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection; import org.apache.activemq.artemis.spi.core.security.jaas.JaasCallbackHandler; import org.apache.activemq.artemis.spi.core.security.jaas.NoCacheLoginException; import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; import org.apache.activemq.artemis.utils.SecurityManagerUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +51,8 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager5 { private String certificateConfigurationName; private SecurityConfiguration configuration; private SecurityConfiguration certificateConfiguration; - private String rolePrincipalClass = "org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal"; + private Class rolePrincipalClass = RolePrincipal.class; + private Class userPrincipalClass = UserPrincipal.class; public ActiveMQJAASSecurityManager() { } @@ -122,6 +125,11 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager5 { return authorized; } + @Override + public String getUserFromSubject(Subject subject) { + return SecurityManagerUtil.getUserFromSubject(subject, userPrincipalClass); + } + private Subject getAuthenticatedSubject(final String user, final String password, final RemotingConnection remotingConnection, @@ -182,10 +190,20 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager5 { } public String getRolePrincipalClass() { - return rolePrincipalClass; + return rolePrincipalClass.getName(); } - public void setRolePrincipalClass(String rolePrincipalClass) { - this.rolePrincipalClass = rolePrincipalClass; + @SuppressWarnings("unchecked") + public void setRolePrincipalClass(String principalClass) throws ClassNotFoundException { + this.rolePrincipalClass = (Class) Class.forName(principalClass); + } + + public String getUserPrincipalClass() { + return userPrincipalClass.getName(); + } + + @SuppressWarnings("unchecked") + public void setUserPrincipalClass(String principalClass) throws ClassNotFoundException { + this.userPrincipalClass = (Class) Class.forName(principalClass); } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager.java index afde137dfd..40969679bf 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager.java @@ -16,11 +16,14 @@ */ package org.apache.activemq.artemis.spi.core.security; +import javax.security.auth.Subject; import java.util.Map; import java.util.Set; import org.apache.activemq.artemis.core.security.CheckType; import org.apache.activemq.artemis.core.security.Role; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; +import org.apache.activemq.artemis.utils.SecurityManagerUtil; /** * Use to validate whether a user has is valid to connect to the server and perform certain @@ -63,4 +66,8 @@ public interface ActiveMQSecurityManager { default ActiveMQSecurityManager init(Map properties) { return this; } + + default String getUserFromSubject(Subject subject) { + return SecurityManagerUtil.getUserFromSubject(subject, UserPrincipal.class); + } } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager5.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager5.java index 2af3459e2d..af8c8c8234 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager5.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager5.java @@ -60,4 +60,5 @@ public interface ActiveMQSecurityManager5 extends ActiveMQSecurityManager { * @return true if the user is authorized, else false */ boolean authorize(Subject subject, Set roles, CheckType checkType, String address); + } diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/utils/SecurityManagerUtil.java b/artemis-server/src/main/java/org/apache/activemq/artemis/utils/SecurityManagerUtil.java index d3fb9efd03..b0bca64b49 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/utils/SecurityManagerUtil.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/utils/SecurityManagerUtil.java @@ -33,7 +33,7 @@ public class SecurityManagerUtil { private static final String WILDCARD = "*"; - public static Set getPrincipalsInRole(final CheckType checkType, final Set roles, final String rolePrincipalClass) { + public static Set getPrincipalsInRole(final CheckType checkType, final Set roles, final Class rolePrincipalClass) { Set principals = new HashSet<>(); for (Role role : roles) { if (checkType.hasRole(role)) { @@ -47,7 +47,16 @@ public class SecurityManagerUtil { return principals; } - public static Object createGroupPrincipal(String name, String groupClass) throws Exception { + public static String getUserFromSubject(Subject subject, Class principalClass) { + if (subject != null) { + for (Principal candidate : subject.getPrincipals(principalClass)) { + return candidate.getName(); + } + } + return null; + } + + public static Object createGroupPrincipal(String name, Class cls) throws Exception { if (WILDCARD.equals(name)) { // simple match all group principal - match any name and class return new Principal() { @@ -69,8 +78,6 @@ public class SecurityManagerUtil { } Object[] param = new Object[]{name}; - Class cls = Class.forName(groupClass); - Constructor[] constructors = cls.getConstructors(); int i; Object instance; @@ -83,7 +90,7 @@ public class SecurityManagerUtil { if (i < constructors.length) { instance = constructors[i].newInstance(param); } else { - instance = cls.newInstance(); + instance = cls.getDeclaredConstructor().newInstance(); Method[] methods = cls.getMethods(); i = 0; for (i = 0; i < methods.length; i++) { @@ -106,7 +113,7 @@ public class SecurityManagerUtil { /** * This method tries to match the RolePrincipals in the Subject with the provided Set of Roles and CheckType */ - public static boolean authorize(final Subject subject, final Set roles, final CheckType checkType, final String rolePrincipalClass) { + public static boolean authorize(final Subject subject, final Set roles, final CheckType checkType, final Class rolePrincipalClass) { boolean authorized = false; if (subject != null) { @@ -115,7 +122,7 @@ public class SecurityManagerUtil { // Check the caller's roles Set rolesForSubject = new HashSet<>(); try { - rolesForSubject.addAll(subject.getPrincipals(Class.forName(rolePrincipalClass).asSubclass(Principal.class))); + rolesForSubject.addAll(subject.getPrincipals(rolePrincipalClass)); } catch (Exception e) { ActiveMQServerLogger.LOGGER.failedToFindRolesForTheSubject(e); } diff --git a/artemis-server/src/main/resources/schema/artemis-configuration.xsd b/artemis-server/src/main/resources/schema/artemis-configuration.xsd index 7bca911b28..d3779266bd 100644 --- a/artemis-server/src/main/resources/schema/artemis-configuration.xsd +++ b/artemis-server/src/main/resources/schema/artemis-configuration.xsd @@ -935,6 +935,33 @@ + + + + The regular expression pattern to match management or JMX operations that require the 'view' permission + in your security-settings. Operations that don't match will default to the 'update' permission. + + + + + + + + Whether to apply RBAC based on security-settings for management operations when accessed through messages sent to the management address. + When set, the 'view' and 'update' permissions are applied to individual management operations based on the message contents. The `manage` permissions is still required to send the messages. + The security-settings match addresses will use the management-rbac-prefix prefix. + + + + + + + + The prefix for security-settings match addresses that control RBAC for management operations. Only configure a value if the default causes a clash in your security settings match criteria. + + + + diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java index a1d9a7ee53..a0f74aa992 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java @@ -461,6 +461,42 @@ public class FileConfigurationParserTest extends ServerTestBase { Assert.assertEquals("()", configuration.getLiteralMatchMarkers()); } + @Test + public void testViewPermissionMethodMatchPattern() throws Exception { + final String pattern = "^(get|list).+$"; + String configStr = "" + pattern + "\n\n"; + + FileConfigurationParser parser = new FileConfigurationParser(); + ByteArrayInputStream input = new ByteArrayInputStream(configStr.getBytes(StandardCharsets.UTF_8)); + + Configuration configuration = parser.parseMainConfig(input); + Assert.assertEquals(pattern, configuration.getViewPermissionMethodMatchPattern()); + } + + @Test + public void testManagementRbacPrefix() throws Exception { + final String pattern = "j.m.x"; + String configStr = "" + pattern + "\n\n"; + + FileConfigurationParser parser = new FileConfigurationParser(); + ByteArrayInputStream input = new ByteArrayInputStream(configStr.getBytes(StandardCharsets.UTF_8)); + + Configuration configuration = parser.parseMainConfig(input); + Assert.assertEquals(pattern, configuration.getManagementRbacPrefix()); + } + + @Test + public void testManagementRbac() throws Exception { + final boolean enabled = true; + String configStr = "" + enabled + "\n\n"; + + FileConfigurationParser parser = new FileConfigurationParser(); + ByteArrayInputStream input = new ByteArrayInputStream(configStr.getBytes(StandardCharsets.UTF_8)); + + Configuration configuration = parser.parseMainConfig(input); + Assert.assertEquals(enabled, configuration.isManagementMessageRbac()); + } + // you should not use K, M notations on address settings max-size-messages @Test public void testExpectedErrorOverMaxMessageNotation() throws Exception { diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java index 60a6a0e2d9..2b1da86de2 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java @@ -700,35 +700,35 @@ public class FileConfigurationTest extends ConfigurationImplTest { Set roles = securityRoles.get("#"); //cn=mygroup,dc=local,dc=com = amq1 - Role testRole1 = new Role("cn=mygroup,dc=local,dc=com", false, false, false, false, true, false, false, false, false, false); + Role testRole1 = new Role("cn=mygroup,dc=local,dc=com", false, false, false, false, true, false, false, false, false, false, false, false); //myrole1 = amq1 + amq2 - Role testRole2 = new Role("myrole1", false, false, false, false, true, true, false, false, false, false); + Role testRole2 = new Role("myrole1", false, false, false, false, true, true, false, false, false, false, false, false); //myrole3 = amq3 + amq4 - Role testRole3 = new Role("myrole3", false, false, true, true, false, false, false, false, false, false); + Role testRole3 = new Role("myrole3", false, false, true, true, false, false, false, false, false, false, false, false); //myrole4 = amq5 + amq!@#$%^&*() + amq6 - Role testRole4 = new Role("myrole4", true, true, false, false, false, false, false, true, true, true); + Role testRole4 = new Role("myrole4", true, true, false, false, false, false, false, true, true, true, false, false); //myrole5 = amq4 = amq3 + amq4 - Role testRole5 = new Role("myrole5", false, false, true, true, false, false, false, false, false, false); + Role testRole5 = new Role("myrole5", false, false, true, true, false, false, false, false, false, false, false, false); - Role testRole6 = new Role("amq1", false, false, false, false, true, false, false, false, false, false); + Role testRole6 = new Role("amq1", false, false, false, false, true, false, false, false, false, false, false, false); - Role testRole7 = new Role("amq2", false, false, false, false, false, true, false, false, false, false); + Role testRole7 = new Role("amq2", false, false, false, false, false, true, false, false, false, false, false, false); - Role testRole8 = new Role("amq3", false, false, true, false, false, false, false, false, false, false); + Role testRole8 = new Role("amq3", false, false, true, false, false, false, false, false, false, false, false, false); - Role testRole9 = new Role("amq4", false, false, true, true, false, false, false, false, false, false); + Role testRole9 = new Role("amq4", false, false, true, true, false, false, false, false, false, false, false, false); - Role testRole10 = new Role("amq5", false, false, false, false, false, false, false, false, true, true); + Role testRole10 = new Role("amq5", false, false, false, false, false, false, false, false, true, true, false, false); - Role testRole11 = new Role("amq6", false, true, false, false, false, false, false, true, false, false); + Role testRole11 = new Role("amq6", false, true, false, false, false, false, false, true, false, false, false, false); - Role testRole12 = new Role("amq7", false, false, false, false, false, false, true, false, false, false); + Role testRole12 = new Role("amq7", false, false, false, false, false, false, true, false, false, false, false, false); - Role testRole13 = new Role("amq!@#$%^&*()", true, false, false, false, false, false, false, false, false, false); + Role testRole13 = new Role("amq!@#$%^&*()", true, false, false, false, false, false, false, false, false, false, false, false); assertEquals(13, roles.size()); assertTrue(roles.contains(testRole1)); diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/RoleTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/RoleTest.java index 46d038729d..dca133419b 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/RoleTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/RoleTest.java @@ -35,7 +35,7 @@ public class RoleTest extends Assert { @Test public void testWriteRole() throws Exception { - Role role = new Role("testWriteRole", true, false, false, false, false, false, false, false, false, false); + Role role = new Role("testWriteRole", true, false, false, false, false, false, false, false, false, false, false, false); Assert.assertTrue(SEND.hasRole(role)); Assert.assertFalse(CONSUME.hasRole(role)); Assert.assertFalse(CREATE_DURABLE_QUEUE.hasRole(role)); @@ -49,7 +49,7 @@ public class RoleTest extends Assert { @Test public void testReadRole() throws Exception { - Role role = new Role("testReadRole", false, true, false, false, false, false, false, true, false, false); + Role role = new Role("testReadRole", false, true, false, false, false, false, false, true, false, false, false, false); Assert.assertFalse(SEND.hasRole(role)); Assert.assertTrue(CONSUME.hasRole(role)); Assert.assertFalse(CREATE_DURABLE_QUEUE.hasRole(role)); @@ -63,7 +63,7 @@ public class RoleTest extends Assert { @Test public void testCreateRole() throws Exception { - Role role = new Role("testCreateRole", false, false, true, false, false, false, false, false, false, false); + Role role = new Role("testCreateRole", false, false, true, false, false, false, false, false, false, false, false, false); Assert.assertFalse(SEND.hasRole(role)); Assert.assertFalse(CONSUME.hasRole(role)); Assert.assertTrue(CREATE_DURABLE_QUEUE.hasRole(role)); @@ -77,7 +77,7 @@ public class RoleTest extends Assert { @Test public void testManageRole() throws Exception { - Role role = new Role("testManageRole", false, false, false, false, false, false, true, false, false, false); + Role role = new Role("testManageRole", false, false, false, false, false, false, true, false, false, false, false, false); Assert.assertFalse(SEND.hasRole(role)); Assert.assertFalse(CONSUME.hasRole(role)); Assert.assertFalse(CREATE_DURABLE_QUEUE.hasRole(role)); @@ -91,12 +91,15 @@ public class RoleTest extends Assert { @Test public void testEqualsAndHashcode() throws Exception { - Role role = new Role("testEquals", true, true, true, false, false, false, false, false, false, false); - Role sameRole = new Role("testEquals", true, true, true, false, false, false, false, false, false, false); - Role roleWithDifferentName = new Role("notEquals", true, true, true, false, false, false, false, false, false, false); - Role roleWithDifferentRead = new Role("testEquals", false, true, true, false, false, false, false, false, false, false); - Role roleWithDifferentWrite = new Role("testEquals", true, false, true, false, false, false, false, false, false, false); - Role roleWithDifferentCreate = new Role("testEquals", true, true, false, false, false, false, false, false, false, false); + Role role = new Role("testEquals", true, true, true, false, false, false, false, false, false, false, false, false); + Role sameRole = new Role("testEquals", true, true, true, false, false, false, false, false, false, false, false, false); + Role roleWithDifferentName = new Role("notEquals", true, true, true, false, false, false, false, false, false, false, false, false); + Role roleWithDifferentRead = new Role("testEquals", false, true, true, false, false, false, false, false, false, false, false, false); + Role roleWithDifferentWrite = new Role("testEquals", true, false, true, false, false, false, false, false, false, false, false, false); + Role roleWithDifferentCreate = new Role("testEquals", true, true, false, false, false, false, false, false, false, false, false, false); + + Role roleWithDifferentView = new Role("testEquals", true, true, true, false, false, false, false, false, false, false, true, false); + Role roleWithDifferentUpdate = new Role("testEquals", true, true, true, false, false, false, false, false, false, false, false, true); Assert.assertTrue(role.equals(role)); @@ -115,6 +118,12 @@ public class RoleTest extends Assert { Assert.assertFalse(role.equals(roleWithDifferentCreate)); Assert.assertFalse(role.hashCode() == roleWithDifferentCreate.hashCode()); + Assert.assertFalse(role.equals(roleWithDifferentView)); + Assert.assertFalse(role.hashCode() == roleWithDifferentView.hashCode()); + + Assert.assertFalse(role.equals(roleWithDifferentUpdate)); + Assert.assertFalse(role.hashCode() == roleWithDifferentUpdate.hashCode()); + Assert.assertFalse(role.equals(null)); } diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImplTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImplTest.java index ae22d1b812..da3d23bf28 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImplTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImplTest.java @@ -25,7 +25,8 @@ import org.apache.activemq.artemis.core.security.SecurityAuth; import org.apache.activemq.artemis.core.settings.impl.HierarchicalObjectRepository; import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5; -import org.apache.activemq.artemis.spi.core.security.jaas.NoCacheLoginException; +import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; import org.apache.activemq.artemis.utils.RandomUtil; import org.junit.Test; @@ -34,35 +35,39 @@ import static org.junit.Assert.assertNull; public class SecurityStoreImplTest { + final ActiveMQSecurityManager5 securityManager = new ActiveMQSecurityManager5() { + @Override + public Subject authenticate(String user, + String password, + RemotingConnection remotingConnection, + String securityDomain) { + Subject subject = new Subject(); + subject.getPrincipals().add(new UserPrincipal(user)); + return subject; + } + + @Override + public boolean authorize(Subject subject, Set roles, CheckType checkType, String address) { + return true; + } + + @Override + public boolean validateUser(String user, String password) { + return false; + } + + @Override + public boolean validateUserAndRole(String user, String password, Set roles, CheckType checkType) { + return false; + } + }; + @Test public void zeroCacheSizeTest() throws Exception { - ActiveMQSecurityManager5 securityManager = new ActiveMQSecurityManager5() { - @Override - public Subject authenticate(String user, - String password, - RemotingConnection remotingConnection, - String securityDomain) throws NoCacheLoginException { - return new Subject(); - } - - @Override - public boolean authorize(Subject subject, Set roles, CheckType checkType, String address) { - return true; - } - - @Override - public boolean validateUser(String user, String password) { - return false; - } - - @Override - public boolean validateUserAndRole(String user, String password, Set roles, CheckType checkType) { - return false; - } - }; + final String user = RandomUtil.randomString(); SecurityStoreImpl securityStore = new SecurityStoreImpl(new HierarchicalObjectRepository<>(), securityManager, 999, true, "", null, null, 0, 0); assertNull(securityStore.getAuthenticationCache()); - securityStore.authenticate(RandomUtil.randomString(), RandomUtil.randomString(), null); + assertEquals(user, securityStore.authenticate(user, RandomUtil.randomString(), null)); assertEquals(0, securityStore.getAuthenticationCacheSize()); securityStore.invalidateAuthenticationCache(); // ensure this doesn't throw an NPE @@ -91,4 +96,21 @@ public class SecurityStoreImplTest { assertEquals(0, securityStore.getAuthorizationCacheSize()); securityStore.invalidateAuthorizationCache(); // ensure this doesn't throw an NPE } -} \ No newline at end of file + + @Test + public void getCaller() throws Exception { + SecurityStoreImpl securityStore = new SecurityStoreImpl(new HierarchicalObjectRepository<>(), securityManager, 999, true, "", null, null, 0, 0); + + assertNull(securityStore.getCaller(null, null)); + assertEquals("joe", securityStore.getCaller("joe", null)); + Subject subject = new Subject(); + assertEquals("joe", securityStore.getCaller("joe", subject)); + subject.getPrincipals().add(new RolePrincipal("r")); + assertEquals("joe", securityStore.getCaller("joe", subject)); + assertNull(securityStore.getCaller(null, subject)); + subject.getPrincipals().add(new UserPrincipal("u")); + assertEquals("u", securityStore.getCaller(null, subject)); + assertEquals("joe", securityStore.getCaller("joe", subject)); + } + +} diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/JAASSecurityManagerClassLoadingTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/JAASSecurityManagerClassLoadingTest.java index 0482d1d37b..3500e4c4ef 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/JAASSecurityManagerClassLoadingTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/JAASSecurityManagerClassLoadingTest.java @@ -30,7 +30,6 @@ import java.util.Set; import org.apache.activemq.artemis.core.security.CheckType; import org.apache.activemq.artemis.core.security.Role; -import org.apache.activemq.artemis.core.security.impl.SecurityStoreImpl; import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; import org.junit.Rule; import org.junit.Test; @@ -88,9 +87,9 @@ public class JAASSecurityManagerClassLoadingTest { Subject result = securityManager.authenticate("first", "secret", null, null); assertNotNull(result); - assertEquals("first", SecurityStoreImpl.getUserFromSubject(result)); + assertEquals("first", securityManager.getUserFromSubject(result)); - Role role = new Role("programmers", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); boolean authorizationResult = securityManager.authorize(result, roles, CheckType.SEND, "someaddress"); diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/group/impl/ClusteredResetMockTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/group/impl/ClusteredResetMockTest.java index 24539d3926..15483a69ee 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/group/impl/ClusteredResetMockTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/group/impl/ClusteredResetMockTest.java @@ -40,17 +40,18 @@ import org.apache.activemq.artemis.core.persistence.StorageManager; import org.apache.activemq.artemis.core.postoffice.PostOffice; import org.apache.activemq.artemis.core.remoting.server.RemotingService; import org.apache.activemq.artemis.core.security.Role; +import org.apache.activemq.artemis.core.security.SecurityAuth; import org.apache.activemq.artemis.core.security.SecurityStore; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.Divert; import org.apache.activemq.artemis.core.server.Queue; import org.apache.activemq.artemis.core.server.QueueFactory; +import org.apache.activemq.artemis.core.server.management.GuardInvocationHandler; import org.apache.activemq.artemis.core.server.routing.ConnectionRouter; import org.apache.activemq.artemis.core.server.cluster.Bridge; import org.apache.activemq.artemis.core.server.cluster.BroadcastGroup; import org.apache.activemq.artemis.core.server.cluster.ClusterConnection; import org.apache.activemq.artemis.core.server.impl.AddressInfo; -import org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerGuard; import org.apache.activemq.artemis.core.server.management.ManagementService; import org.apache.activemq.artemis.core.server.management.Notification; import org.apache.activemq.artemis.core.server.management.NotificationListener; @@ -351,12 +352,12 @@ public class ClusteredResetMockTest extends ServerTestBase { } @Override - public ICoreMessage handleMessage(Message message) throws Exception { + public ICoreMessage handleMessage(SecurityAuth auth, Message message) throws Exception { return null; } @Override - public void registerHawtioSecurity(ArtemisMBeanServerGuard securityMBean) throws Exception { + public void registerHawtioSecurity(GuardInvocationHandler securityMBean) throws Exception { } @@ -366,12 +367,12 @@ public class ClusteredResetMockTest extends ServerTestBase { } @Override - public Object getAttribute(String resourceName, String attribute) { + public Object getAttribute(String resourceName, String attribute, SecurityAuth auth) { return null; } @Override - public Object invokeOperation(String resourceName, String operation, Object[] params) throws Exception { + public Object invokeOperation(String resourceName, String operation, Object[] params, SecurityAuth auth) throws Exception { return null; } diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacMBeanServerBuilderTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacMBeanServerBuilderTest.java new file mode 100644 index 0000000000..2a50faaa24 --- /dev/null +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/ArtemisRbacMBeanServerBuilderTest.java @@ -0,0 +1,693 @@ +/* + * 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.activemq.artemis.core.server.management; + +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; +import javax.security.auth.Subject; +import java.lang.management.RuntimeMXBean; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; +import java.lang.reflect.UndeclaredThrowableException; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; +import org.apache.activemq.artemis.api.core.RoutingType; +import org.apache.activemq.artemis.api.core.SimpleString; +import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl; +import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder; +import org.apache.activemq.artemis.core.security.CheckType; +import org.apache.activemq.artemis.core.security.Role; +import org.apache.activemq.artemis.core.server.ActiveMQServer; +import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; +import org.apache.activemq.artemis.tests.util.ServerTestBase; +import org.apache.activemq.artemis.utils.RandomUtil; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class ArtemisRbacMBeanServerBuilderTest extends ServerTestBase { + + MBeanServer mbeanServer; + MBeanServerDelegate mBeanServerDelegate; + ArtemisRbacMBeanServerBuilder underTest; + + @Before + public void setUnderTest() throws Exception { + underTest = new ArtemisRbacMBeanServerBuilder(); + mbeanServer = Mockito.mock(MBeanServer.class); + mBeanServerDelegate = Mockito.mock(MBeanServerDelegate.class); + } + + @Test + public void testRbacAddressFrom() throws Exception { + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + ArtemisRbacInvocationHandler handler = (ArtemisRbacInvocationHandler) Proxy.getInvocationHandler(proxy); + handler.brokerDomain = "a.b"; + handler.rbacPrefix = SimpleString.toSimpleString("jmx"); + + try { + handler.addressFrom(null); + fail("expect exception"); + } catch (NullPointerException expected) { + } + + SimpleString rbacAddress = handler.addressFrom(new ObjectName("java.lang", "type", "Runtime")); + assertNotNull(rbacAddress); + assertEquals(0, rbacAddress.compareTo(SimpleString.toSimpleString("jmx.java.lang.Runtime"))); + + rbacAddress = handler.addressFrom(new ObjectName("a.b", "type", "Runtime")); + assertNotNull(rbacAddress); + assertEquals(0, rbacAddress.compareTo(SimpleString.toSimpleString("jmx"))); + + rbacAddress = handler.addressFrom(new ObjectName("a.b", "broker", "bb")); + assertNotNull(rbacAddress); + assertEquals(0, rbacAddress.compareTo(SimpleString.toSimpleString("jmx.broker"))); + + Hashtable attrs = new Hashtable<>(); + attrs.put("broker", "bb"); + attrs.put("type", "t"); + attrs.put("component", "c"); + attrs.put("name", "n"); + rbacAddress = handler.addressFrom(new ObjectName("a.b", attrs)); + assertNotNull(rbacAddress); + assertEquals(0, rbacAddress.compareTo(SimpleString.toSimpleString("jmx.c.n"))); + + + rbacAddress = handler.addressFrom(new ObjectName("a.b", attrs), "doIt"); + assertNotNull(rbacAddress); + assertEquals(0, rbacAddress.compareTo(SimpleString.toSimpleString("jmx.c.n.doIt"))); + + // non broker domain + rbacAddress = handler.addressFrom(new ObjectName("j.l", attrs)); + assertNotNull(rbacAddress); + assertEquals(0, rbacAddress.compareTo(SimpleString.toSimpleString("jmx.j.l.t.c.n"))); + + // address + attrs.clear(); + + attrs.put("broker", "bb"); + attrs.put("address", "a"); + attrs.put("component", "addresses"); + rbacAddress = handler.addressFrom(new ObjectName("a.b", attrs), "opOnA"); + assertNotNull(rbacAddress); + assertEquals(0, rbacAddress.compareTo(SimpleString.toSimpleString("jmx.address.a.opOnA"))); + + // queue + attrs.clear(); + + attrs.put("broker", "bb"); + attrs.put("address", "a"); + attrs.put("queue", "q"); + attrs.put("component", "addresses"); + attrs.put("subcomponent", "queues"); + + rbacAddress = handler.addressFrom(new ObjectName("a.b", attrs), "opOnQ"); + assertNotNull(rbacAddress); + assertEquals(0, rbacAddress.compareTo(SimpleString.toSimpleString("jmx.queue.q.opOnQ"))); + + // divert + attrs.clear(); + + attrs.put("broker", "bb"); + attrs.put("address", "a"); + attrs.put("queue", "q"); + attrs.put("component", "addresses"); + attrs.put("subcomponent", "diverts"); + attrs.put("divert", "d"); + + rbacAddress = handler.addressFrom(new ObjectName("a.b", attrs), "opOnDivert"); + assertNotNull(rbacAddress); + assertEquals(0, rbacAddress.compareTo(SimpleString.toSimpleString("jmx.divert.d.opOnDivert"))); + + } + + @Test + public void testRbacAddressFromWithObjectNameBuilder() throws Exception { + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + ArtemisRbacInvocationHandler handler = + (ArtemisRbacInvocationHandler) Proxy.getInvocationHandler(proxy); + handler.brokerDomain = ActiveMQDefaultConfiguration.getDefaultJmxDomain(); + handler.rbacPrefix = SimpleString.toSimpleString(ActiveMQDefaultConfiguration.getManagementRbacPrefix()); + + for (Method m : ObjectNameBuilder.class.getDeclaredMethods() ) { + if (Modifier.isPublic(m.getModifiers()) && ObjectName.class == m.getReturnType()) { + Object[] args = new Object[m.getParameterCount()]; + for (int i = 0; i < args.length; i++) { + Class type = m.getParameterTypes()[i]; + if (type == String.class) { + args[i] = RandomUtil.randomString(); + } else if (SimpleString.class == type) { + args[i] = RandomUtil.randomSimpleString(); + } else if (RoutingType.class == type) { + args[i] = RoutingType.ANYCAST; + } + } + assertNotNull(handler.addressFrom((ObjectName) m.invoke(ObjectNameBuilder.DEFAULT, args), m.getName())); + } + } + } + + @Test + public void testPermissionsFromDefault() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + ArtemisRbacInvocationHandler handler = (ArtemisRbacInvocationHandler) Proxy.getInvocationHandler(proxy); + + handler.viewPermissionMatcher = Pattern.compile(ActiveMQDefaultConfiguration.getViewPermissionMethodMatchPattern()); + + assertEquals(CheckType.VIEW, handler.permissionFrom("getClass")); + assertEquals(CheckType.VIEW, handler.permissionFrom("listDeliveringMessages")); + assertEquals(CheckType.VIEW, handler.permissionFrom("isEmpty")); + assertEquals(CheckType.EDIT, handler.permissionFrom("quote")); + + assertEquals(CheckType.VIEW, handler.permissionFrom("getA")); + + assertEquals(CheckType.EDIT, handler.permissionFrom("setA")); + } + + @Test + public void testPermissionsFromCustom() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + ArtemisRbacInvocationHandler handler = (ArtemisRbacInvocationHandler) Proxy.getInvocationHandler(proxy); + + handler.viewPermissionMatcher = Pattern.compile("^(is(?!SecurityEnabled)|get|list|query).*$"); + + assertEquals(CheckType.EDIT, handler.permissionFrom("isSecurityEnabled")); + assertEquals(CheckType.VIEW, handler.permissionFrom("isEmpty")); + + assertEquals(CheckType.VIEW, handler.permissionFrom("getClass")); + assertEquals(CheckType.VIEW, handler.permissionFrom("listDeliveringMessages")); + + assertEquals(CheckType.EDIT, handler.permissionFrom("quote")); + + assertEquals(CheckType.VIEW, handler.permissionFrom("getA")); + + assertEquals(CheckType.EDIT, handler.permissionFrom("setA")); + } + + @Test(expected = IllegalStateException.class) + public void testUninitialised() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + ObjectName runtimeName = new ObjectName("java.lang", "type", "Runtime"); + RuntimeMXBean runtime = JMX.newMBeanProxy( + proxy, runtimeName, RuntimeMXBean.class, false); + runtime.getVmVersion(); + } + + @Test(expected = UndeclaredThrowableException.class) + public void testUnCheckedDomain() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + ObjectName unchecked = new ObjectName("hawtio", "type", "Runtime"); + RuntimeMXBean runtime = JMX.newMBeanProxy( + proxy, unchecked, RuntimeMXBean.class, false); + runtime.getVmVersion(); + } + + @Test(expected = SecurityException.class) + public void testNotLoggedIn() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + final ActiveMQServer server = createServer(false); + server.setMBeanServer(proxy); + server.getConfiguration().setJMXManagementEnabled(true).setSecurityEnabled(true); + server.start(); + + ObjectName runtimeName = new ObjectName("java.lang", "type", "Runtime"); + RuntimeMXBean runtime = JMX.newMBeanProxy( + proxy, runtimeName, RuntimeMXBean.class, false); + runtime.getVmVersion(); + } + + @Test(expected = SecurityException.class) + public void testNoPermission() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + final ActiveMQServer server = createServer(false); + server.setMBeanServer(proxy); + server.getConfiguration().setJMXManagementEnabled(true).setSecurityEnabled(true); + server.start(); + + ObjectName runtimeName = new ObjectName("java.lang", "type", "Runtime"); + final RuntimeMXBean runtime = JMX.newMBeanProxy( + proxy, runtimeName, RuntimeMXBean.class, false); + + Subject viewSubject = new Subject(); + viewSubject.getPrincipals().add(new UserPrincipal("v")); + viewSubject.getPrincipals().add(new RolePrincipal("viewers")); + + throw Subject.doAs(viewSubject, (PrivilegedExceptionAction) () -> { + try { + runtime.getVmVersion(); + return null; + } catch (Exception e1) { + return e1; + } + }); + } + + @Test + public void testPermissionGetAttr() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + final ActiveMQServer server = createServer(false); + server.setMBeanServer(proxy); + server.getConfiguration().setJMXManagementEnabled(true).setSecurityEnabled(true); + + Set roles = new HashSet<>(); + roles.add(new Role("viewers", false, false, false, false, false, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("mops.broker.getCurrentTimeMillis", roles); + + server.start(); + + ObjectName objectName = ObjectNameBuilder.DEFAULT.getActiveMQServerObjectName(); + final ActiveMQServerControl serverControl = JMX.newMBeanProxy( + proxy, objectName, ActiveMQServerControl.class, false); + + Subject viewSubject = new Subject(); + viewSubject.getPrincipals().add(new UserPrincipal("v")); + viewSubject.getPrincipals().add(new RolePrincipal("viewers")); + + Object ret = Subject.doAs(viewSubject, (PrivilegedExceptionAction) () -> { + try { + return serverControl.getCurrentTimeMillis(); + } catch (Exception e1) { + return e1; + } + }); + assertNotNull(ret); + assertTrue(ret instanceof Long); + + + // verify failure case + Subject noPermSubject = new Subject(); + noPermSubject.getPrincipals().add(new UserPrincipal("dud")); + noPermSubject.getPrincipals().add(new RolePrincipal("dud")); + + ret = Subject.doAs(noPermSubject, (PrivilegedExceptionAction) () -> { + try { + return serverControl.getCurrentTimeMillis(); + } catch (Exception e1) { + return e1; + } + }); + assertNotNull(ret); + assertTrue(ret instanceof SecurityException); + } + + + @Test + public void testPermissionIsAttr() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + final ActiveMQServer server = createServer(false); + server.setMBeanServer(proxy); + server.getConfiguration().setJMXManagementEnabled(true).setSecurityEnabled(true).setManagementRbacPrefix("jmx"); + + Set roles = new HashSet<>(); + roles.add(new Role("viewers", false, false, false, false, false, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("jmx.broker.isSecurityEnabled", roles); + + server.start(); + + final ActiveMQServerControl serverControl = JMX.newMBeanProxy( + proxy, ObjectNameBuilder.DEFAULT.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); + + Subject viewSubject = new Subject(); + viewSubject.getPrincipals().add(new UserPrincipal("v")); + viewSubject.getPrincipals().add(new RolePrincipal("viewers")); + + Object ret = Subject.doAs(viewSubject, (PrivilegedExceptionAction) () -> { + try { + return serverControl.isSecurityEnabled(); + } catch (Exception e1) { + e1.printStackTrace(); + return e1; + } + }); + assertNotNull(ret); + assertTrue(ret instanceof Boolean); + + + // verify failure case + Subject noPermSubject = new Subject(); + noPermSubject.getPrincipals().add(new UserPrincipal("dud")); + noPermSubject.getPrincipals().add(new RolePrincipal("dud")); + + ret = Subject.doAs(noPermSubject, (PrivilegedExceptionAction) () -> { + try { + return serverControl.isSecurityEnabled(); + } catch (Exception e1) { + return e1; + } + }); + assertNotNull(ret); + assertTrue(ret instanceof SecurityException); + } + + @Test + public void testPermissionWithConfiguredJmxPrefix() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + final ActiveMQServer server = createServer(false); + server.setMBeanServer(proxy); + server.getConfiguration().setJMXManagementEnabled(true).setSecurityEnabled(true).setManagementRbacPrefix("j.m.x"); + + Set roles = new HashSet<>(); + roles.add(new Role("viewers", false, false, false, false, false, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("j.m.x.broker.*", roles); + + server.start(); + + final ActiveMQServerControl serverControl = JMX.newMBeanProxy( + proxy, ObjectNameBuilder.DEFAULT.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); + + Subject viewSubject = new Subject(); + viewSubject.getPrincipals().add(new UserPrincipal("v")); + viewSubject.getPrincipals().add(new RolePrincipal("viewers")); + + Object ret = Subject.doAs(viewSubject, (PrivilegedExceptionAction) () -> { + try { + return serverControl.isSecurityEnabled(); + } catch (Exception e1) { + e1.printStackTrace(); + return e1; + } + }); + assertNotNull(ret); + assertTrue(ret instanceof Boolean); + } + + @Test + public void testConfigViewMethodMatchNoPermission() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + final ActiveMQServer server = createServer(false); + server.setMBeanServer(proxy); + server.getConfiguration().setJMXManagementEnabled(true).setSecurityEnabled(true); + + // isSecurityEnabled will require Update permission + server.getConfiguration().setViewPermissionMethodMatchPattern("^(is(?!SecurityEnabled)|get|list|query).*$"); + + Set roles = new HashSet<>(); + roles.add(new Role("viewers", false, false, false, false, false, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("mops.broker.#", roles); + + server.start(); + + final ActiveMQServerControl serverControl = JMX.newMBeanProxy( + proxy, ObjectNameBuilder.DEFAULT.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); + + + Subject viewSubject = new Subject(); + viewSubject.getPrincipals().add(new UserPrincipal("v")); + viewSubject.getPrincipals().add(new RolePrincipal("viewers")); + + Object ret = Subject.doAs(viewSubject, (PrivilegedExceptionAction) () -> { + try { + return serverControl.isSecurityEnabled(); + } catch (Exception e1) { + e1.printStackTrace(); + return e1; + } + }); + assertNotNull(ret); + assertTrue(ret instanceof SecurityException); + assertTrue(((Exception)ret).getMessage().contains("EDIT")); + + // another `is` op is ok with view + ret = Subject.doAs(viewSubject, (PrivilegedExceptionAction) () -> { + try { + return serverControl.isActive(); + } catch (Exception e1) { + e1.printStackTrace(); + return e1; + } + }); + assertNotNull(ret); + assertTrue(ret instanceof Boolean); + } + + @Test + public void testConfigMethodMatchEmptyNeedsUpdate() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + final ActiveMQServer server = createServer(false); + server.setMBeanServer(proxy); + server.getConfiguration().setJMXManagementEnabled(true).setSecurityEnabled(true).setManagementRbacPrefix("jmx"); + + // all ops will require Update permission + server.getConfiguration().setViewPermissionMethodMatchPattern(""); + + Set viewRoles = new HashSet<>(); + viewRoles.add(new Role("viewers", false, false, false, false, false, false, false, false, false, false, true, false)); + Set editRoles = new HashSet<>(); + editRoles.add(new Role("updaters", false, false, false, false, false, false, false, false, false, false, false, true)); + + server.getConfiguration().putSecurityRoles("jmx.broker.#", viewRoles); + server.getConfiguration().putSecurityRoles("jmx.broker.isSecurityEnabled", editRoles); + + server.start(); + + final ActiveMQServerControl serverControl = JMX.newMBeanProxy( + proxy, ObjectNameBuilder.DEFAULT.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); + + + Subject testSubject = new Subject(); + testSubject.getPrincipals().add(new UserPrincipal("v")); + testSubject.getPrincipals().add(new RolePrincipal("viewers")); + + Object ret = Subject.doAs(testSubject, (PrivilegedExceptionAction) () -> { + try { + return serverControl.getAddressCount(); + } catch (Exception e1) { + e1.printStackTrace(); + return e1; + } + }); + assertNotNull(ret); + assertTrue(ret instanceof SecurityException); + assertTrue(((Exception)ret).getMessage().contains("EDIT")); + + // with updaters role we can access a specific method + testSubject.getPrincipals().add(new RolePrincipal("updaters")); + + ret = Subject.doAs(testSubject, (PrivilegedExceptionAction) () -> { + try { + return serverControl.isSecurityEnabled(); + } catch (Exception e1) { + e1.printStackTrace(); + return e1; + } + }); + assertNotNull(ret); + assertTrue(ret instanceof Boolean); + } + + @Test + public void testQueryWithStar() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + final ActiveMQServer server = createServer(false); + server.setMBeanServer(proxy); + server.getConfiguration().setJMXManagementEnabled(true).setSecurityEnabled(true); + + Set roles = new HashSet<>(); + roles.add(new Role("viewers", false, false, false, false, false, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("mops.mbeanserver.queryNames", roles); + + server.start(); + + Hashtable attrs = new Hashtable<>(); + attrs.put("broker", "bb"); + attrs.put("type", "security"); + attrs.put("area", "jmx"); + attrs.put("name", "*"); + + final ObjectName queryName = new ObjectName("*", attrs); + + Subject viewSubject = new Subject(); + viewSubject.getPrincipals().add(new UserPrincipal("v")); + viewSubject.getPrincipals().add(new RolePrincipal("viewers")); + + Object result = Subject.doAs(viewSubject, (PrivilegedExceptionAction) () -> { + try { + return proxy.queryNames(queryName, null); + } catch (Exception e1) { + return e1; + } + }); + assertNotNull(result); + assertTrue(result instanceof Set); + } + + @Test + public void testQueryAllFiltered() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + final ActiveMQServer server = createServer(false); + server.setMBeanServer(proxy); + server.getConfiguration().setJMXManagementEnabled(true).setSecurityEnabled(true); + + Set viewerRole = new HashSet<>(); + viewerRole.add(new Role("viewers", false, false, false, false, false, false, false, false, false, false, true, false)); + + Set condoleRole = new HashSet<>(); + condoleRole.add(new Role("mbeanServer", false, false, false, false, false, false, false, false, false, false, true, false)); + + server.getConfiguration().putSecurityRoles("mops.mbeanserver.#", condoleRole); + server.getConfiguration().putSecurityRoles("mops.address.activemq.notifications", viewerRole); + + server.start(); + + Subject viewSubject = new Subject(); + viewSubject.getPrincipals().add(new UserPrincipal("v")); + viewSubject.getPrincipals().add(new RolePrincipal("mbeanServer")); + + Object result = Subject.doAs(viewSubject, (PrivilegedExceptionAction) () -> { + try { + return proxy.queryNames(null, null); + } catch (Exception e1) { + return e1; + } + }); + assertNotNull(result); + assertEquals(1, ((Set) result).size()); + + // give view role + viewSubject.getPrincipals().add(new RolePrincipal("viewers")); + result = Subject.doAs(viewSubject, (PrivilegedExceptionAction) () -> { + try { + return proxy.queryNames(null, null); + } catch (Exception e1) { + return e1; + } + }); + + assertNotNull(result); + assertEquals(2, ((Set) result).size()); + + // and they are there, we just don't see them + assertEquals(5, proxy.getMBeanCount().intValue()); + } + + @Test + public void testCanInvoke() throws Exception { + + MBeanServer proxy = underTest.newMBeanServer("d", mbeanServer, mBeanServerDelegate); + + final ActiveMQServer server = createServer(false); + server.setMBeanServer(proxy); + server.getConfiguration().setJMXManagementEnabled(true).setSecurityEnabled(true); + + Set roles = new HashSet<>(); + roles.add(new Role("viewers", false, false, false, false, false, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("mops.java.#", roles); + + server.start(); + + + final HawtioSecurityControl securityControl = JMX.newMBeanProxy( + proxy, ObjectNameBuilder.DEFAULT.getSecurityObjectName(), HawtioSecurityControl.class, false); + + ObjectName runtimeName = new ObjectName("java.lang", "type", "Runtime"); + final RuntimeMXBean runtime = JMX.newMBeanProxy( + proxy, runtimeName, RuntimeMXBean.class, false); + + Subject viewSubject = new Subject(); + viewSubject.getPrincipals().add(new UserPrincipal("v")); + viewSubject.getPrincipals().add(new RolePrincipal("viewers")); + + Object result = Subject.doAs(viewSubject, (PrivilegedAction) () -> { + try { + return securityControl.canInvoke(runtimeName.toString()); + } catch (Exception e1) { + return e1.getCause(); + } + }); + assertNotNull(result); + assertFalse("in the absence of an operation to check, update required", (Boolean) result); + + result = Subject.doAs(viewSubject, (PrivilegedAction) () -> { + try { + return securityControl.canInvoke(runtimeName.toString(), "getVmName"); + } catch (Exception e1) { + return e1.getCause(); + } + }); + assertNotNull(result); + assertTrue((Boolean) result); + + result = Subject.doAs(viewSubject, (PrivilegedAction) () -> { + try { + return securityControl.canInvoke(runtimeName.toString(), "getVmName", new String[]{"args", "are", "ignored"}); + } catch (Exception e1) { + return e1.getCause(); + } + }); + assertNotNull(result); + assertTrue((Boolean) result); + + + Map> bulkQuery = new HashMap<>(); + bulkQuery.put(runtimeName.toString(), List.of("getVmName()", "getVersion()")); + + result = Subject.doAs(viewSubject, (PrivilegedAction) () -> { + try { + return securityControl.canInvoke(bulkQuery); + } catch (Exception e1) { + return e1.getCause(); + } + }); + assertNotNull(result); + assertEquals(2, ((TabularData)result).size()); + + CompositeData cd = ((TabularData)result).get(new Object[]{runtimeName.toString(), "getVmName()"}); + assertEquals(runtimeName.toString(), cd.get("ObjectName")); + assertEquals("getVmName()", cd.get("Method")); + assertEquals(true, cd.get("CanInvoke")); + } +} diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImplSecurityStoreRbacTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImplSecurityStoreRbacTest.java new file mode 100644 index 0000000000..c2b5ab8958 --- /dev/null +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImplSecurityStoreRbacTest.java @@ -0,0 +1,29 @@ +/* + * 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.activemq.artemis.core.server.management.impl; + +import org.apache.activemq.artemis.core.server.management.ArtemisRbacInvocationHandler; +import org.junit.Before; +import org.mockito.Mockito; + +public class HawtioSecurityControlImplSecurityStoreRbacTest extends HawtioSecurityControlImplTest { + + @Override @Before + public void initGuard() { + guard = Mockito.mock(ArtemisRbacInvocationHandler.class); + } +} diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImplTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImplTest.java index feff848453..bff7fc2cf4 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImplTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/HawtioSecurityControlImplTest.java @@ -26,6 +26,8 @@ import java.util.Map; import org.apache.activemq.artemis.core.persistence.StorageManager; import org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerGuard; +import org.apache.activemq.artemis.core.server.management.GuardInvocationHandler; +import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; @@ -36,10 +38,16 @@ import static org.junit.Assert.fail; public class HawtioSecurityControlImplTest { + protected GuardInvocationHandler guard; + + @Before + public void initGuard() { + guard = Mockito.mock(ArtemisMBeanServerGuard.class); + } + @Test public void testCanInvokeMBean() throws Exception { String objectName = "foo.bar.testing:type=SomeMBean"; - ArtemisMBeanServerGuard guard = Mockito.mock(ArtemisMBeanServerGuard.class); StorageManager storageManager = Mockito.mock(StorageManager.class); Mockito.when(guard.canInvoke(objectName, null)).thenReturn(true); @@ -50,7 +58,6 @@ public class HawtioSecurityControlImplTest { @Test public void testCanInvokeMBean2() throws Exception { String objectName = "foo.bar.testing:type=SomeMBean"; - ArtemisMBeanServerGuard guard = Mockito.mock(ArtemisMBeanServerGuard.class); StorageManager storageManager = Mockito.mock(StorageManager.class); Mockito.when(guard.canInvoke(objectName, null)).thenReturn(false); @@ -61,7 +68,6 @@ public class HawtioSecurityControlImplTest { @Test(expected = Exception.class) public void testCanInvokeMBeanThrowsException() throws Exception { String objectName = "foo.bar.testing:type=SomeMBean"; - ArtemisMBeanServerGuard guard = Mockito.mock(ArtemisMBeanServerGuard.class); StorageManager storageManager = Mockito.mock(StorageManager.class); Mockito.when(guard.canInvoke(objectName, null)).thenThrow(new Exception()); @@ -79,7 +85,6 @@ public class HawtioSecurityControlImplTest { @Test public void testCanInvokeMethod() throws Exception { String objectName = "foo.bar.testing:type=SomeMBean"; - ArtemisMBeanServerGuard guard = Mockito.mock(ArtemisMBeanServerGuard.class); StorageManager storageManager = Mockito.mock(StorageManager.class); Mockito.when(guard.canInvoke(objectName, "testMethod")).thenReturn(true); Mockito.when(guard.canInvoke(objectName, "otherMethod")).thenReturn(false); @@ -93,7 +98,6 @@ public class HawtioSecurityControlImplTest { @Test(expected = Exception.class) public void testCanInvokeMethodException() throws Exception { String objectName = "foo.bar.testing:type=SomeMBean"; - ArtemisMBeanServerGuard guard = Mockito.mock(ArtemisMBeanServerGuard.class); StorageManager storageManager = Mockito.mock(StorageManager.class); Mockito.when(guard.canInvoke(objectName, "testMethod")).thenThrow(new Exception()); @@ -110,7 +114,6 @@ public class HawtioSecurityControlImplTest { @Test public void testCanInvokeBulk() throws Exception { - ArtemisMBeanServerGuard guard = Mockito.mock(ArtemisMBeanServerGuard.class); StorageManager storageManager = Mockito.mock(StorageManager.class); String objectName = "foo.bar.testing:type=SomeMBean"; Mockito.when(guard.canInvoke(objectName, "testMethod")).thenReturn(true); @@ -153,7 +156,6 @@ public class HawtioSecurityControlImplTest { @Test public void testCanInvokeBulkWithDuplicateMethods() throws Exception { - ArtemisMBeanServerGuard guard = Mockito.mock(ArtemisMBeanServerGuard.class); StorageManager storageManager = Mockito.mock(StorageManager.class); String objectName = "foo.bar.testing:type=SomeMBean"; Mockito.when(guard.canInvoke(objectName, "duplicateMethod1")).thenReturn(true); diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImplTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImplTest.java new file mode 100644 index 0000000000..dc951506c1 --- /dev/null +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/management/impl/ManagementServiceImplTest.java @@ -0,0 +1,217 @@ +/* + * 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.activemq.artemis.core.server.management.impl; + +import javax.management.MBeanServer; + +import org.apache.activemq.artemis.api.core.RoutingType; +import org.apache.activemq.artemis.api.core.SimpleString; +import org.apache.activemq.artemis.api.core.TransportConfiguration; +import org.apache.activemq.artemis.api.core.management.ResourceNames; +import org.apache.activemq.artemis.core.config.Configuration; +import org.apache.activemq.artemis.core.config.impl.FileConfiguration; +import org.apache.activemq.artemis.core.paging.PagingManager; +import org.apache.activemq.artemis.core.paging.PagingStore; +import org.apache.activemq.artemis.core.persistence.StorageManager; +import org.apache.activemq.artemis.core.postoffice.PostOffice; +import org.apache.activemq.artemis.core.security.CheckType; +import org.apache.activemq.artemis.core.security.SecurityAuth; +import org.apache.activemq.artemis.core.security.SecurityStore; +import org.apache.activemq.artemis.core.server.ActiveMQServer; +import org.apache.activemq.artemis.core.server.Queue; +import org.apache.activemq.artemis.core.server.impl.AddressInfo; +import org.apache.activemq.artemis.spi.core.remoting.Acceptor; +import org.apache.activemq.artemis.utils.ExecutorFactory; +import org.apache.activemq.artemis.utils.actors.ArtemisExecutor; +import org.junit.Test; +import org.mockito.Mockito; + +public class ManagementServiceImplTest { + + MBeanServer mBeanServer = Mockito.mock(MBeanServer.class); + SecurityStore securityStore = Mockito.mock(SecurityStore.class); + ActiveMQServer messagingServer = Mockito.mock(ActiveMQServer.class); + ExecutorFactory executorFactory = Mockito.mock(ExecutorFactory.class); + ArtemisExecutor artemisExecutor = Mockito.mock(ArtemisExecutor.class); + PostOffice postOffice = Mockito.mock(PostOffice.class); + SecurityAuth auth = Mockito.mock(SecurityAuth.class); + PagingManager pagingManager = Mockito.mock(PagingManager.class); + private PagingStore pageStore = Mockito.mock(PagingStore.class); + + @Test + public void testGetAttributeSecurityCheck() throws Exception { + + Configuration configuration = new FileConfiguration(); + configuration.setManagementMessageRbac(true); + configuration.setManagementRbacPrefix("mm"); + configuration.setViewPermissionMethodMatchPattern("^get.*$"); // no match for isPaging + ManagementServiceImpl managementService = new ManagementServiceImpl(mBeanServer, configuration); + + Mockito.when(executorFactory.getExecutor()).thenReturn(artemisExecutor); + Mockito.when(messagingServer.getExecutorFactory()).thenReturn(executorFactory); + Mockito.when(messagingServer.getManagementService()).thenReturn(managementService); + Mockito.when(postOffice.isStarted()).thenReturn(true); + Mockito.when(messagingServer.getPostOffice()).thenReturn(postOffice); + Mockito.when(pagingManager.getPageStore(Mockito.any(SimpleString.class))).thenReturn(pageStore); + Mockito.when(pageStore.isPaging()).thenReturn(true); + + + managementService.registerServer(null, securityStore, null, configuration, null, null, null, null, messagingServer, null, null, pagingManager, false); + + // acceptor + Mockito.clearInvocations(securityStore); + Acceptor acceptor = Mockito.mock(Acceptor.class); + TransportConfiguration transportConfig = Mockito.mock(TransportConfiguration.class); + Mockito.when(transportConfig.getName()).thenReturn("a1"); + + managementService.registerAcceptor(acceptor, transportConfig); + managementService.getAttribute(ResourceNames.ACCEPTOR + transportConfig.getName(), "name", auth); + + SimpleString expected = SimpleString.toSimpleString("mm.acceptor.a1.getName"); + Mockito.verify(securityStore).check(Mockito.eq(expected), Mockito.eq(CheckType.VIEW), Mockito.any(SecurityAuth.class)); + + // address + final String addressName = "addr1"; + Mockito.clearInvocations(securityStore); + + managementService.registerAddress(new AddressInfo(addressName)); + managementService.getAttribute(ResourceNames.ADDRESS + addressName, "address", auth); + + expected = SimpleString.toSimpleString("mm.address." + addressName + ".getAddress"); + Mockito.verify(securityStore).check(Mockito.eq(expected), Mockito.eq(CheckType.VIEW), Mockito.any(SecurityAuth.class)); + + // isX needs UPDATE with view regexp above + Mockito.clearInvocations(securityStore); + managementService.getAttribute(ResourceNames.ADDRESS + addressName, "paging", auth); + + expected = SimpleString.toSimpleString("mm.address." + addressName + ".isPaging"); + Mockito.verify(securityStore).check(Mockito.eq(expected), Mockito.eq(CheckType.EDIT), Mockito.any(SecurityAuth.class)); + + + // queue + final SimpleString queueName = SimpleString.toSimpleString("queueName"); + Mockito.clearInvocations(securityStore); + + Queue queue = Mockito.mock(Queue.class); + Mockito.when(queue.getName()).thenReturn(queueName); + Mockito.when(queue.getRoutingType()).thenReturn(RoutingType.ANYCAST); + + StorageManager storageManager = Mockito.mock(StorageManager.class); + managementService.registerQueue(queue, new AddressInfo(queueName), storageManager); + managementService.getAttribute(ResourceNames.QUEUE + queueName, "ringSize", auth); + + expected = SimpleString.toSimpleString("mm.queue." + queueName + ".getRingSize"); + Mockito.verify(securityStore).check(Mockito.eq(expected), Mockito.eq(CheckType.VIEW), Mockito.any(SecurityAuth.class)); + + Mockito.clearInvocations(securityStore); + managementService.getAttribute(ResourceNames.QUEUE + queueName, "ID", auth); + + expected = SimpleString.toSimpleString("mm.queue." + queueName + ".getID"); + Mockito.verify(securityStore).check(Mockito.eq(expected), Mockito.eq(CheckType.VIEW), Mockito.any(SecurityAuth.class)); + + } + + @Test + public void testInvokeSecurityCheck() throws Exception { + + Configuration configuration = new FileConfiguration(); + configuration.setManagementMessageRbac(true); + configuration.setManagementRbacPrefix("$mm"); + + ManagementServiceImpl managementService = new ManagementServiceImpl(mBeanServer, configuration); + + Mockito.when(executorFactory.getExecutor()).thenReturn(artemisExecutor); + Mockito.when(messagingServer.getExecutorFactory()).thenReturn(executorFactory); + Mockito.when(messagingServer.getManagementService()).thenReturn(managementService); + Mockito.when(postOffice.isStarted()).thenReturn(true); + Mockito.when(messagingServer.getPostOffice()).thenReturn(postOffice); + + managementService.registerServer(null, securityStore, null, configuration, null, null, null, null, messagingServer, null, null, null, false); + + // acceptor + Mockito.clearInvocations(securityStore); + + Acceptor acceptor = Mockito.mock(Acceptor.class); + TransportConfiguration transportConfig = Mockito.mock(TransportConfiguration.class); + Mockito.when(transportConfig.getName()).thenReturn("a1"); + + managementService.registerAcceptor(acceptor, transportConfig); + managementService.invokeOperation(ResourceNames.ACCEPTOR + transportConfig.getName(), "getName", new Object[]{}, auth); + + SimpleString expected = SimpleString.toSimpleString("$mm.acceptor.a1.getName"); + Mockito.verify(securityStore).check(Mockito.eq(expected), Mockito.eq(CheckType.VIEW), Mockito.any(SecurityAuth.class)); + + // address + final String addressName = "addr1"; + Mockito.clearInvocations(securityStore); + + managementService.registerAddress(new AddressInfo(addressName)); + managementService.invokeOperation(ResourceNames.ADDRESS + addressName, "getAddress", new Object[]{}, auth); + + expected = SimpleString.toSimpleString("$mm.address." + addressName + ".getAddress"); + Mockito.verify(securityStore).check(Mockito.eq(expected), Mockito.eq(CheckType.VIEW), Mockito.any(SecurityAuth.class)); + + // queue + final SimpleString queueName = SimpleString.toSimpleString("queueName"); + Mockito.clearInvocations(securityStore); + + Queue queue = Mockito.mock(Queue.class); + Mockito.when(queue.getName()).thenReturn(queueName); + Mockito.when(queue.getRoutingType()).thenReturn(RoutingType.ANYCAST); + + StorageManager storageManager = Mockito.mock(StorageManager.class); + managementService.registerQueue(queue, new AddressInfo(queueName), storageManager); + managementService.invokeOperation(ResourceNames.QUEUE + queueName, "getRingSize", new Object[]{}, auth); + + expected = SimpleString.toSimpleString("$mm.queue." + queueName + ".getRingSize"); + + Mockito.verify(securityStore).check(Mockito.eq(expected), Mockito.eq(CheckType.VIEW), Mockito.any(SecurityAuth.class)); + + // update permission required on pause operation + Mockito.clearInvocations(securityStore); + managementService.invokeOperation(ResourceNames.QUEUE + queueName, "pause", new Object[]{}, auth); + expected = SimpleString.toSimpleString("$mm.queue." + queueName + ".pause"); + Mockito.verify(securityStore).check(Mockito.eq(expected), Mockito.eq(CheckType.EDIT), Mockito.any(SecurityAuth.class)); + + } + + @Test + public void testGetAttributeNoSecurityCheck() throws Exception { + + Configuration configuration = new FileConfiguration(); + ManagementServiceImpl managementService = new ManagementServiceImpl(mBeanServer, configuration); + + Mockito.when(executorFactory.getExecutor()).thenReturn(artemisExecutor); + Mockito.when(messagingServer.getExecutorFactory()).thenReturn(executorFactory); + Mockito.when(messagingServer.getManagementService()).thenReturn(managementService); + Mockito.when(postOffice.isStarted()).thenReturn(true); + Mockito.when(messagingServer.getPostOffice()).thenReturn(postOffice); + + managementService.registerServer(null, securityStore, null, configuration, null, null, null, null, messagingServer, null, null, null, false); + + // acceptor + Mockito.clearInvocations(securityStore); + Acceptor acceptor = Mockito.mock(Acceptor.class); + TransportConfiguration transportConfig = Mockito.mock(TransportConfiguration.class); + Mockito.when(transportConfig.getName()).thenReturn("a1"); + + managementService.registerAcceptor(acceptor, transportConfig); + managementService.getAttribute(ResourceNames.ACCEPTOR + transportConfig.getName(), "name", auth); + + Mockito.verifyNoInteractions(securityStore); + } +} \ No newline at end of file diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/RepositoryTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/RepositoryTest.java index 1e41ab9fe1..c0d51bd6ce 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/RepositoryTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/RepositoryTest.java @@ -181,13 +181,13 @@ public class RepositoryTest extends ServerTestBase { public void testSingletwo() { securityRepository.addMatch("queues.another.aq.*", new HashSet()); HashSet roles = new HashSet<>(2); - roles.add(new Role("test1", true, true, true, true, true, true, true, true, true, true)); - roles.add(new Role("test2", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("test1", true, true, true, true, true, true, true, true, true, true, false, false)); + roles.add(new Role("test2", true, true, true, true, true, true, true, true, true, true, false, false)); securityRepository.addMatch("queues.aq", roles); HashSet roles2 = new HashSet<>(2); - roles2.add(new Role("test1", true, true, true, true, true, true, true, true, true, true)); - roles2.add(new Role("test2", true, true, true, true, true, true, true, true, true, true)); - roles2.add(new Role("test3", true, true, true, true, true, true, true, true, true, true)); + roles2.add(new Role("test1", true, true, true, true, true, true, true, true, true, true, false, false)); + roles2.add(new Role("test2", true, true, true, true, true, true, true, true, true, true, false, false)); + roles2.add(new Role("test3", true, true, true, true, true, true, true, true, true, true, false, false)); securityRepository.addMatch("queues.another.andanother", roles2); HashSet hashSet = securityRepository.getMatch("queues.another.andanother"); @@ -198,8 +198,8 @@ public class RepositoryTest extends ServerTestBase { public void testWithoutWildcard() { securityRepository.addMatch("queues.1.*", new HashSet()); HashSet roles = new HashSet<>(2); - roles.add(new Role("test1", true, true, true, true, true, true, true, true, true, true)); - roles.add(new Role("test2", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("test1", true, true, true, true, true, true, true, true, true, true, false, false)); + roles.add(new Role("test2", true, true, true, true, true, true, true, true, true, true, false, false)); securityRepository.addMatch("queues.2.aq", roles); HashSet hashSet = securityRepository.getMatch("queues.2.aq"); Assert.assertEquals(hashSet.size(), 2); diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManagerTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManagerTest.java new file mode 100644 index 0000000000..99d96a548b --- /dev/null +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManagerTest.java @@ -0,0 +1,56 @@ +/* + * 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.activemq.artemis.spi.core.security; + +import javax.security.auth.Subject; +import java.security.Principal; + +import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class ActiveMQJAASSecurityManagerTest { + + final String user = "P"; + class UserFromOtherDomainPrincipal implements Principal { + @Override + public String getName() { + return user; + } + } + + @Test + public void getUserFromSubjectWithExternalPrinciple() throws Exception { + + ActiveMQJAASSecurityManager underTest = new ActiveMQJAASSecurityManager(); + assertEquals(UserPrincipal.class.getName(), underTest.getUserPrincipalClass()); + assertEquals(RolePrincipal.class.getName(), underTest.getRolePrincipalClass()); + + Subject subject = new Subject(); + subject.getPrincipals().add(new ActiveMQJAASSecurityManagerTest.UserFromOtherDomainPrincipal()); + assertNull(underTest.getUserFromSubject(subject)); + + underTest.setUserPrincipalClass(ActiveMQJAASSecurityManagerTest.UserFromOtherDomainPrincipal.class.getName()); + + assertEquals(user, underTest.getUserFromSubject(subject)); + } + +} \ No newline at end of file diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/utils/SecurityManagerUtilTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/utils/SecurityManagerUtilTest.java new file mode 100644 index 0000000000..97d93221ee --- /dev/null +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/utils/SecurityManagerUtilTest.java @@ -0,0 +1,54 @@ +/* + * 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.activemq.artemis.utils; + +import javax.security.auth.Subject; +import java.security.Principal; + +import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; +import org.junit.Assert; +import org.junit.Test; + +public class SecurityManagerUtilTest { + + @Test + public void getUserFromSubject() throws Exception { + Assert.assertNull(SecurityManagerUtil.getUserFromSubject(null, null)); + Subject subject = new Subject(); + Assert.assertNull(SecurityManagerUtil.getUserFromSubject(subject, UserPrincipal.class)); + subject.getPrincipals().add(new RolePrincipal("r")); + Assert.assertNull(SecurityManagerUtil.getUserFromSubject(subject, UserPrincipal.class)); + subject.getPrincipals().add(new UserPrincipal("u")); + Assert.assertEquals("u", SecurityManagerUtil.getUserFromSubject(subject, UserPrincipal.class)); + } + + class UserFromOtherDomainPrincipal implements Principal { + @Override + public String getName() { + return "P"; + } + } + + @Test + public void getUserFromForeignPrincipalInSubject() throws Exception { + Subject subject = new Subject(); + subject.getPrincipals().add(new UserFromOtherDomainPrincipal()); + Assert.assertNull(SecurityManagerUtil.getUserFromSubject(subject, UserPrincipal.class)); + } +} \ No newline at end of file diff --git a/artemis-unit-test-support/src/main/java/org/apache/activemq/artemis/utils/SubjectDotDoAsRule.java b/artemis-unit-test-support/src/main/java/org/apache/activemq/artemis/utils/SubjectDotDoAsRule.java new file mode 100644 index 0000000000..bdcde17e7b --- /dev/null +++ b/artemis-unit-test-support/src/main/java/org/apache/activemq/artemis/utils/SubjectDotDoAsRule.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.activemq.artemis.utils; + +import javax.security.auth.Subject; + +import java.security.PrivilegedExceptionAction; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class SubjectDotDoAsRule implements TestRule { + + final Subject subject; + + public SubjectDotDoAsRule(Subject subject) { + this.subject = subject; + } + + @Override + public Statement apply(final Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + Exception e = Subject.doAs(subject, (PrivilegedExceptionAction) () -> { + try { + base.evaluate(); + } catch (Throwable e1) { + return new Exception(e1); + } + return null; + }); + if (e != null) { + throw e; + } + } + }; + } +} diff --git a/docs/user-manual/configuration-index.adoc b/docs/user-manual/configuration-index.adoc index 16d8c92b75..d46bdc5448 100644 --- a/docs/user-manual/configuration-index.adoc +++ b/docs/user-manual/configuration-index.adoc @@ -591,6 +591,19 @@ In most cases this should be set to '1'. | xref:wildcard-syntax.adoc#wildcard-syntax[wildcard-addresses] | parameters to configure wildcard address matching format. | n/a + +| [[view-permission-method-match-pattern]] view-permission-method-match-pattern +| parameter to configure the regular expression pattern to match xref:management.adoc#fine-grained-rbac-on-management-messages[management] or xref:management.adoc#jmx-authorization-in-broker-xml[JMX] operations that require the 'view' permission +in your security-settings. +| ``^(get\|is\|count\|list\|browse\|query).*$`` + +| [[management-message-rbac]] management-message-rbac +| parameter to enable security-settings RBAC on xref:management.adoc#fine-grained-rbac-on-management-messages[management messages] sent to the management address. +| false + +| [[management-rbac-prefix]] management-rbac-prefix +| parameter to configure the prefix for security-settings match addresses to control RBAC on xref:management.adoc#jmx-authorization-in-broker-xml[JMX MBean operations] and optionally on xref:management.adoc#fine-grained-rbac-on-management-messages[management messages] +| mops (shorthand for management operations) |=== == address-setting type diff --git a/docs/user-manual/management.adoc b/docs/user-manual/management.adoc index f71a95b0c2..2b6568f1db 100644 --- a/docs/user-manual/management.adoc +++ b/docs/user-manual/management.adoc @@ -75,6 +75,7 @@ diverts) can be created or destroyed using the management operations `createBrid + Diverts can be updated using the management operation `updateDivert()`. +[#force_failover] * It is possible to stop the server and force failover to occur with any currently attached clients. + To do this use the `forceFailover()` operation. @@ -189,7 +190,7 @@ The acceptors parameters can be retrieved using the `AcceptorControl` attributes * Diverts + They can be started or stopped using the `start()` or `stop()` method on the `DivertControl` interface. -Diverts parameters can be retrieved using the `DivertControl` attributes (see xref:diverts.adoc#diverting-and-splitting-message-flows[Diverting and Splitting Message Flows)]) +Diverts parameters can be retrieved using the `DivertControl` attributes (see xref:diverts.adoc#diverting-and-splitting-message-flows[Diverting and Splitting Message Flows]) * Bridges + @@ -250,11 +251,14 @@ It can be disabled by setting `jmx-management-enabled` to `false` in `broker.xml ==== Role Based Authorisation for JMX -Although by default Artemis uses the Java Virtual Machine's `Platform MBeanServer` this is guarded using role based authorisation that leverages the broker's JAAS plugin support. -This is configured via the `authorisation` element in the `management.xml` configuration file and can be used to restrict access to attributes and methods on MBeans. +Artemis uses the Java Virtual Machine's `Platform MBeanServer` by default. This is guarded using role based authorisation that leverages the broker's JAAS plugin support. + +The RBAC used to restrict access to Mbeans and their operations can be configured in `one` of two ways. Via security-settings in broker.xml, described in xref:management.adoc#jmx-authorization-in-broker-xml[JMX authorization in broker.xml], or via the `authorization` element in the `management.xml` that is described below. + +===== JMX authorisation in management.xml There are 3 elements within the `authorisation` element, `allowlist`, `default-access` and `role-access`. -Lets discuss each in turn. +Let's discuss each in turn. Allowlist contains a list of MBeans that will bypass the authorisation, this is typically used for any MBeans that are needed by the console to run etc. The default configuration is: @@ -301,7 +305,7 @@ The default configuration looks like: This contains 1 match and will be applied to any MBean that has the domain `org.apache.activemq.artemis`. Any access to any MBeans that have this domain are controlled by the `access` elements which contain a method and a set of roles. The method being invoked will be used to pick the closest matching method and the roles for this will be applied for access. -For instance if you try the invoke a method called `listMessages` on an MBean with the `org.apache.activemq.artemis` domain then this would match the `access` with the method of `list*`. +For instance if you try to invoke a method called `listMessages` on an MBean with the `org.apache.activemq.artemis` domain then this would match the `access` with the method of `list*`. You could also explicitly configure this by using the full method name, like so: [,xml] @@ -357,11 +361,66 @@ You can also use wildcards for the MBean properties so the following would also In case of multiple matches, the exact matches have higher priority than the wildcard matches and the longer wildcard matches have higher priority than the shorter wildcard matches. Access to JMX MBean attributes are converted to method calls so these are controlled via the `set*`, `get*` and `is*`. -The `*` access is the catch all for everything other method that isn't specifically matched. +The `*` access is the catch-all for everything other method that isn't specifically matched. -The `default-access` element is basically the catch all for every method call that isn't handled via the `role-access` configuration. +The `default-access` element is basically the catch-all for every method call that isn't handled via the `role-access` configuration. This has the same semantics as a `match` element. + +==== JMX authorization in broker.xml +The existing xref:security.adoc#role-based-security-for-addresses[security-settings] in broker.xml can be used for JMX RBAC. + +Using the `view` and `edit` permissions on matches in security-settings provides an alternative to the authorization section in management.xml. +Using a single security model based on addresses, with reloadable configuration, simplifies operation. + +An xref:management.adoc#artemis_rbac_mbean_server_guard[MBeanServer interceptor] that delegates to the broker security manager must be configured with a JVM system property that allows it to be added to all MBeanServers in the JVM. + +This is configured via a system property as follows: + +[,sh] +---- + java -Djavax.management.builder.initial=org.apache.activemq.artemis.core.server.management.ArtemisRbacMBeanServerBuilder +---- +IMPORTANT: When this property is provided, the authorization section of management.xml should be omitted as that depends on an alternative MBeanServer interceptor. + +The security-settings match addresses used for JMX RBAC use the `mops.` (shorthand for management operations) xref:configuration-index.adoc#management-rbac-prefix[prefix]. This allows independent RBAC between messaging operations and management operations. + +The MBeanServer guard maps JMX MBean ObjectNames to a hierarchical address of the general form: + + mops<.jmx domain><.type><.component><.name>[.operation] + +NOTE: for the broker domain, the domain is omitted. + + +For example, to give the `admin` role `view` and `edit` permissions on all MBeans, use the following security-setting: + +[,xml] +---- + + + + +---- + +To grant the `managerRole` role `view` permission to just the `activemq.management` address, target the `address` component with name `activemq.management` and with `.*` to include all operations. + +[,xml] +---- + + + +---- + + +To ensure no user has permission to xref:management.adoc#force_failover[force a failover] using the broker (server control) MBean, use the following that defines the empty roles set for a particular mutating operation on the `broker` component: +[,xml] +---- + + + +---- + + ==== Local JMX Access with JConsole Due to the authorisation which is enabled by default Apache ActiveMQ Artemis can _not_ be managed locally using JConsole when connecting as a _local process_. @@ -370,7 +429,7 @@ In order to use JConsole the user will either have to disable authorisation by c ==== Remote JMX Access -By default remote JMX access to Artemis is disabled for security reasons. +By default, remote JMX access to Artemis is disabled for security reasons. Artemis has a JMX agent which allows access to JMX MBeans remotely. This is configured via the `connector` element in the `management.xml` configuration file. @@ -505,14 +564,24 @@ Such a `curl` command would give you back something like the following (after fo === JMX and the Web Console The web console that ships with Artemis uses Jolokia under the covers which in turn uses JMX. -This will use the authentication configuration in the `management.xml` file as described in the previous section. +This will use the authentication configuration as described in the xref:management.adoc#role-based-authorisation-for-jmx[Role Based Authorisation for JMX section]. This means that when MBeans are accessed via the console the credentials used to log into the console and the roles associated with them. -By default access to the console is only allow via users with the `amq` role. +By default, access to the console is only allow via users with the `amq` role. This is configured in the `artemis.profile` via the system property `-Dhawtio.role=amq`. You can configure multiple roles by changing this to `-Dhawtio.roles=amq,view,update`. If a user doesn't have the correct role to invoke a specific operation then this will display an authorisation exception in the console. + +[#artemis_rbac_mbean_server_guard] +==== ArtemisRbacMBeanServerBuilder and ArtemisRbacInvocationHandler +The ArtemisRbacMBeanServerBuilder class, when configured as value for the system property `javax.management.builder.initial` will cause the ArtemisRbacInvocationHandler to be installed on every JMX MBeanServer in the JVM. +The ArtemisRbacInvocationHandler intercepts all operations on the MBeanServer and chooses to guard a subsection of those operations. + +For guarded operations the `view` or `edit` permissions are required to make an invocation. If the current authenticated subject does not have the required roles to grant those permissions, a security exception is thrown. + +For query operations on the MBeanServer, the results of the query are limited to entries that have the required `view` permission. + == Using Management Message API The management message API in ActiveMQ Artemis is accessed by sending Core Client messages to a special address, the _management address_. @@ -585,7 +654,43 @@ This is also configured in broker.xml: ---- -=== Example +=== Fine grained RBAC on management messages +There is optional RBAC on the content of management messages sent to the management address. +RBAC is enabled through configuration by setting the attribute xref:configuration-index.adoc#management-message-rbac[management-message-rbac] to `true`. + +NOTE: The `manage` permission is required to execute management operations via messages. The `view` and `edit` permissions must be used in conjunction with the `manage` permission. + +When enabled, more fine-grained permissions on the content of management messages sent to the management address can be configured through the security-settings. + +The security-settings match addresses used for RBAC follow the general hierarchical form of: xref:configuration-index.adoc#management-rbac-prefix[management-rbac-prefix], component type, component name, operation. Where the values are extracted from the management message headers. + + ... + +xref:configuration-index.adoc#view-permission-method-match-pattern[Immutable operations and attribute access] will require the `view` permission, all other operations will require the `edit` permission. + + +In the following example the `dataImport` role can only access the id attribute of queues, which is the only management operation that is required by the xref:using-cli.adoc#command-line-interface[data import] command line tool. + +[,xml] +---- + + + + +---- + +If you want the `admin` role to have full access, use a wildcard after the management-rbac-prefix and grant both the `view` and `edit` permissions: + +[,xml] +---- + + + + + +---- + +=== Management Example See the xref:examples.adoc#management[Management Example] which shows how to use JMS messages to manage the Apache ActiveMQ Artemis server. diff --git a/docs/user-manual/security.adoc b/docs/user-manual/security.adoc index f090d92b99..ebf34f1c6f 100644 --- a/docs/user-manual/security.adoc +++ b/docs/user-manual/security.adoc @@ -68,6 +68,14 @@ This permission allows the user to browse a queue bound to the matching address. manage:: This permission allows the user to invoke management operations by sending management messages to the management address. +The following two permissions pertain to operations on the xref:management.adoc#management[management apis] of the broker. They split management operations into two sets, read only for `view`, and `edit` for mutating operations. The split is controlled by a regular expression. Methods that match will require the `view` permission, all others require `edit`. The regular expression can be modified through the configuration attribute xref:configuration-index.adoc#view-permission-method-match-pattern[`view-permission-method-match-pattern`]. These permissions are applicable to the xref:management.adoc#fine-grained-rbac-on-management-messages[management address] and to xref:management.adoc#jmx-authorization-in-broker-xml[MBean access]. They are granted to match addresses prefixed with the xref:configuration-index.adoc#management-rbac-prefix[management prefix]. + +view:: +This permission allows access to a read-only subset of management operations. + +update:: +This permission allows access to the mutating management operations, any operation not in the `view` set. + For each permission, a list of roles who are granted that permission is specified. If the user has any of those roles, he/she will be granted that permission for that set of addresses. @@ -153,9 +161,18 @@ You can do this using the fully qualified queue name (i.e. FQQN) in the `match` ---- -NOTE: Wildcard matching doesn't work in conjuction with FQQN. +NOTE: Wildcard matching doesn't work in conjunction with FQQN. The explicit goal of using FQQN here is to be _exact_. +=== Applying `view` and `edit` permissions to the management api +The `view` and `edit` permissions are optionally applied to the management apis of the broker. + +For RBAC on JMX MBean access they can replace the authorization section in management.xml as described at xref:management.adoc#jmx-authorization-in-broker-xml[JMX authorization in broker.xml] + +For RBAC on management resources accessed via messages sent to the management address, the additional permissions are enabled by configuring xref:configuration-index.adoc#management-message-rbac[`management-message-rbac`] as described at xref:management.adoc#fine-grained-rbac-on-management-messages[Fine grained RBAC on management messages] + +The split between operations that require the `view` and `edit` permissions can be controlled via xref:configuration-index.adoc#view-permission-method-match-pattern[view-permission-method-match-pattern] + == Security Setting Plugin Aside from configuring sets of permissions via XML these permissions can alternatively be configured via a plugin which implements `org.apache.activemq.artemis.core.server.SecuritySettingPlugin` e.g.: diff --git a/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/amqp/JMSSaslExternalLDAPTest.java b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/amqp/JMSSaslExternalLDAPTest.java index 99acf6faf5..2138305e9b 100644 --- a/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/amqp/JMSSaslExternalLDAPTest.java +++ b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/amqp/JMSSaslExternalLDAPTest.java @@ -133,7 +133,7 @@ public class JMSSaslExternalLDAPTest extends AbstractLdapTestUnit { // role mapping via CertLogin - TextFileCertificateLoginModule final String roleName = "widgets"; - Role role = new Role(roleName, true, true, true, true, true, true, true, true, true, true); + Role role = new Role(roleName, true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch("TEST", roles); diff --git a/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/amqp/SaslKrb5LDAPSecurityTest.java b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/amqp/SaslKrb5LDAPSecurityTest.java index d7fea9fbc7..5aeb4d469f 100644 --- a/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/amqp/SaslKrb5LDAPSecurityTest.java +++ b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/amqp/SaslKrb5LDAPSecurityTest.java @@ -400,7 +400,7 @@ public class SaslKrb5LDAPSecurityTest extends AbstractLdapTestUnit { createArtemisServer(jaasConfigScope); Set roles = new HashSet<>(); - roles.add(new Role(artemisRoleName, true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role(artemisRoleName, true, true, true, true, true, true, true, true, true, true, false, false)); server.getConfiguration().putSecurityRoles(QUEUE_NAME, roles); server.start(); diff --git a/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/JmxSecurityMultipleSubjectTest.java b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/JmxSecurityMultipleSubjectTest.java new file mode 100644 index 0000000000..021af20436 --- /dev/null +++ b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/JmxSecurityMultipleSubjectTest.java @@ -0,0 +1,139 @@ +/* + * 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.activemq.artemis.tests.integration.isolated.security; + +import javax.management.JMX; +import javax.security.auth.Subject; +import java.lang.management.ManagementFactory; +import java.security.PrivilegedExceptionAction; +import java.util.HashSet; +import java.util.Set; + +import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; +import org.apache.activemq.artemis.api.core.TransportConfiguration; +import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl; +import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder; +import org.apache.activemq.artemis.core.config.Configuration; +import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl; +import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory; +import org.apache.activemq.artemis.core.security.Role; +import org.apache.activemq.artemis.core.server.ActiveMQServer; +import org.apache.activemq.artemis.core.server.ActiveMQServers; +import org.apache.activemq.artemis.core.server.management.ArtemisRbacMBeanServerBuilder; +import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; +import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class JmxSecurityMultipleSubjectTest { + + public static Subject viewSubject = new Subject(); + public static Subject updateSubject = new Subject(); + + static { + System.setProperty("javax.management.builder.initial", ArtemisRbacMBeanServerBuilder.class.getCanonicalName()); + + viewSubject.getPrincipals().add(new UserPrincipal("v")); + viewSubject.getPrincipals().add(new RolePrincipal("viewers")); + + updateSubject.getPrincipals().add(new UserPrincipal("u")); + updateSubject.getPrincipals().add(new RolePrincipal("updaters")); + } + + ActiveMQServer server; + + + @Before + public void setUp() throws Exception { + ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLogin"); + Configuration configuration = new ConfigurationImpl().addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getCanonicalName())); + configuration.setManagementRbacPrefix("jmx"); + server = ActiveMQServers.newActiveMQServer(configuration, ManagementFactory.getPlatformMBeanServer(), securityManager, false); + } + + @After + public void tearDown() throws Exception { + server.stop(); + } + + @Test + public void testJmxAuthBrokerNotCached() throws Exception { + + Set roles = new HashSet<>(); + roles.add(new Role("viewers", false, false, false, false, false, false, false, false, false, false, true, false)); + roles.add(new Role("updaters", false, false, false, false, false, false, false, false, false, false, true, true)); + + server.getConfiguration().putSecurityRoles("jmx.broker.addConnector", roles); + server.getConfiguration().putSecurityRoles("jmx.broker.getActivationSequence", roles); + server.getConfiguration().putSecurityRoles("jmx.broker.forceFailover", new HashSet<>()); + server.start(); + + + ObjectNameBuilder objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), server.getConfiguration().getName(), true); + final ActiveMQServerControl activeMQServerControl = JMX.newMBeanProxy(ManagementFactory.getPlatformMBeanServer(), objectNameBuilder.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); + + try { + activeMQServerControl.getActivationSequence(); + fail("not logged in"); + } catch (Exception expectedOnNotLoggedIn) { + assertTrue(expectedOnNotLoggedIn.getMessage().contains("management")); + } + + // requiring update + Exception e = Subject.doAs(updateSubject, (PrivilegedExceptionAction) () -> { + try { + // update first + activeMQServerControl.addConnector("c", "tcp://localhost:89"); + // also exercise view + activeMQServerControl.getActivationSequence(); + return null; + } catch (Exception e1) { + e1.printStackTrace(); + return e1; + } + }); + assertNull(e); + + e = Subject.doAs(viewSubject, (PrivilegedExceptionAction) () -> { + try { + activeMQServerControl.addConnector("d", "tcp://localhost:89"); + return null; + } catch (Exception e1) { + return e1; + } + }); + assertNotNull("view permission is not sufficient", e); + + e = Subject.doAs(updateSubject, (PrivilegedExceptionAction) () -> { + try { + activeMQServerControl.forceFailover(); + return null; + } catch (Exception e1) { + return e1; + } + }); + assertNotNull("no permission is sufficient", e); + + } +} \ No newline at end of file diff --git a/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/JmxSecurityTest.java b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/JmxSecurityTest.java new file mode 100644 index 0000000000..67a7d2e1b3 --- /dev/null +++ b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/JmxSecurityTest.java @@ -0,0 +1,355 @@ +/* + * 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.activemq.artemis.tests.integration.isolated.security; + +import javax.management.JMX; +import javax.management.ObjectName; +import javax.security.auth.Subject; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.security.PrivilegedExceptionAction; +import java.util.HashSet; +import java.util.Set; + +import jdk.management.jfr.FlightRecorderMXBean; +import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; +import org.apache.activemq.artemis.api.core.QueueConfiguration; +import org.apache.activemq.artemis.api.core.RoutingType; +import org.apache.activemq.artemis.api.core.SimpleString; +import org.apache.activemq.artemis.api.core.TransportConfiguration; +import org.apache.activemq.artemis.api.core.management.AcceptorControl; +import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl; +import org.apache.activemq.artemis.api.core.management.AddressControl; +import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder; +import org.apache.activemq.artemis.api.core.management.QueueControl; +import org.apache.activemq.artemis.core.config.Configuration; +import org.apache.activemq.artemis.core.config.CoreAddressConfiguration; +import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl; +import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory; +import org.apache.activemq.artemis.core.security.Role; +import org.apache.activemq.artemis.core.server.ActiveMQServer; +import org.apache.activemq.artemis.core.server.ActiveMQServers; +import org.apache.activemq.artemis.core.server.impl.AddressInfo; +import org.apache.activemq.artemis.core.server.management.ArtemisRbacMBeanServerBuilder; +import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; +import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; +import org.apache.activemq.artemis.utils.SubjectDotDoAsRule; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class JmxSecurityTest { + + public static Subject subject = new Subject(); + static { + // before any call to ManagementFactory.getPlatformMBeanServer() + System.setProperty("javax.management.builder.initial", ArtemisRbacMBeanServerBuilder.class.getCanonicalName()); + subject.getPrincipals().add(new UserPrincipal("first")); + subject.getPrincipals().add(new RolePrincipal("programmers")); + } + + @Rule + public SubjectDotDoAsRule doAs = new SubjectDotDoAsRule(subject); + + ActiveMQServer server; + + @Before + public void setUp() { + ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLogin"); + Configuration configuration = new ConfigurationImpl().addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getCanonicalName())); + configuration.setManagementRbacPrefix("jmx"); + server = ActiveMQServers.newActiveMQServer(configuration, ManagementFactory.getPlatformMBeanServer(), securityManager, false); + } + + @After + public void tearDown() throws Exception { + server.stop(); + } + + @Test + public void testJmxAuthBroker() throws Exception { + + Set roles = new HashSet<>(); + roles.add(new Role("programmers", false, false, false, false, true, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("jmx.broker.getActivationSequence", roles); + server.start(); + + ObjectNameBuilder objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), server.getConfiguration().getName(), true); + ActiveMQServerControl activeMQServerControl = JMX.newMBeanProxy(ManagementFactory.getPlatformMBeanServer(), objectNameBuilder.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); + + activeMQServerControl.getActivationSequence(); + } + + @Test + public void testJxmAuthUpdateAddressNegative() throws Exception { + + Set roles = new HashSet<>(); + roles.add(new Role("programmers", false, false, false, false, true, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("activemq.notifications", roles); + server.start(); + + AddressControl addressControl = JMX.newMBeanProxy( + ManagementFactory.getPlatformMBeanServer(), + ObjectNameBuilder.DEFAULT.getAddressObjectName(SimpleString.toSimpleString("activemq.notifications")), AddressControl.class, false); + + try { + addressControl.sendMessage(null, 1, "hi", false, null, null); + fail("need Update permission"); + } catch (Exception expected) { + assertTrue(expected.getMessage().contains("first")); + assertTrue(expected.getMessage().contains("EDIT")); + } + } + + @Test + public void testJxmAuthUpdateAddress() throws Exception { + + Set roles = new HashSet<>(); + roles.add(new Role("programmers", true, false, false, false, true, false, false, false, false, false, true, true)); + server.getConfiguration().putSecurityRoles("jmx.address.activemq.notifications.getUnRoutedMessageCount", roles); + server.getConfiguration().putSecurityRoles("jmx.address.activemq.notifications.sendMessage", roles); + server.getConfiguration().putSecurityRoles("activemq.notifications", roles); // the real address Send permission + server.getConfiguration().putSecurityRoles("jmx.address.activemq.notifications.pause", roles); + server.getConfiguration().putSecurityRoles("jmx.address.activemq.notifications.resume", roles); + server.getConfiguration().putSecurityRoles("jmx.address.activemq.notifications.isPaging", roles); + server.start(); + + AddressControl addressControl = JMX.newMBeanProxy( + ManagementFactory.getPlatformMBeanServer(), + ObjectNameBuilder.DEFAULT.getAddressObjectName(SimpleString.toSimpleString("activemq.notifications")), AddressControl.class, false); + + long unRoutedMessageCount = addressControl.getUnRoutedMessageCount(); + assertEquals(0L, unRoutedMessageCount); + + addressControl.sendMessage(null, 1, "hi", false, null, null); + + long unRoutedMessageCountAfter = addressControl.getUnRoutedMessageCount(); + assertEquals(3L, unRoutedMessageCountAfter); + + assertFalse(addressControl.isPaging()); + + addressControl.pause(); + addressControl.resume(); + } + + @Test + public void testJmxAuthQueue() throws Exception { + + Set roles = new HashSet<>(); + roles.add(new Role("programmers", false, false, false, false, true, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("jmx.queue.Q1.*", roles); + + CoreAddressConfiguration address = new CoreAddressConfiguration(); + address.setName("Q1").addQueueConfig(new QueueConfiguration("Q1").setRoutingType(RoutingType.ANYCAST)); + server.getConfiguration().getAddressConfigurations().add(address); + + server.start(); + + QueueControl queueControl = JMX.newMBeanProxy( + ManagementFactory.getPlatformMBeanServer(), + ObjectNameBuilder.DEFAULT.getQueueObjectName(SimpleString.toSimpleString("Q1"), SimpleString.toSimpleString("Q1"), RoutingType.ANYCAST), QueueControl.class, false); + queueControl.getDurableMessageCount(); + + queueControl.browse(); + queueControl.countMessages(); + queueControl.listGroupsAsJSON(); + + try { + queueControl.sendMessage(null, 1, "hi", false, null, null); + fail("need Update permission"); + } catch (Exception expected) { + assertTrue(expected.getMessage().contains("first")); + assertTrue(expected.getMessage().contains("EDIT")); + } + + try { + queueControl.disable(); + fail("need Update permission"); + } catch (Exception expected) { + assertTrue(expected.getMessage().contains("first")); + assertTrue(expected.getMessage().contains("EDIT")); + } + + try { + queueControl.enable(); + fail("need Update permission"); + } catch (Exception expected) { + assertTrue(expected.getMessage().contains("first")); + assertTrue(expected.getMessage().contains("EDIT")); + } + + try { + queueControl.pause(true); + fail("need Update permission"); + } catch (Exception expected) { + assertTrue(expected.getMessage().contains("first")); + assertTrue(expected.getMessage().contains("EDIT")); + } + + try { + queueControl.flushExecutor(); + fail("need Update permission"); + } catch (Exception expected) { + assertTrue(expected.getMessage().contains("first")); + assertTrue(expected.getMessage().contains("EDIT")); + } + } + + @Test + public void testJxmAuthAcceptor() throws Exception { + + Set roles = new HashSet<>(); + roles.add(new Role("programmers", false, false, false, false, true, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("jmx.acceptors.*.isStarted", roles); + server.getConfiguration().putSecurityRoles("jmx.acceptors.*.getParameters", roles); + + server.start(); + + AcceptorControl control = JMX.newMBeanProxy( + ManagementFactory.getPlatformMBeanServer(), + ObjectNameBuilder.DEFAULT.getAcceptorObjectName(server.getConfiguration().getAcceptorConfigurations().stream().findFirst().get().getName()), AcceptorControl.class, false); + + control.isStarted(); + control.getParameters(); + + try { + control.stop(); + fail("need Update permission"); + } catch (Exception expected) { + assertTrue(expected.getMessage().contains("first")); + assertTrue(expected.getMessage().contains("EDIT")); + } + } + + @Test + public void testJxmAuthJvmRuntime() throws Exception { + + Set roles = new HashSet<>(); + roles.add(new Role("programmers", false, false, false, false, true, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("jmx.java.lang.Runtime.*", roles); + + server.start(); + + ObjectName runtimeName = new ObjectName("java.lang", "type", "Runtime"); + RuntimeMXBean runtime = JMX.newMBeanProxy( + ManagementFactory.getPlatformMBeanServer(), runtimeName, RuntimeMXBean.class, false); + runtime.getVmVersion(); + } + + @Test + public void testJxmAuthFlightRecorder() throws Exception { + + Set roles = new HashSet<>(); + roles.add(new Role("programmers", false, false, false, false, true, false, false, false, false, false, true, false)); + server.getConfiguration().putSecurityRoles("jmx.jdk.management.#", roles); + + server.start(); + + ObjectName runtimeName = new ObjectName("jdk.management.jfr", "type", "FlightRecorder"); + FlightRecorderMXBean fr = JMX.newMXBeanProxy(ManagementFactory.getPlatformMBeanServer(), runtimeName, FlightRecorderMXBean.class, false); + fr.getConfigurations(); + } + + @Test + public void testQueueAuthorization() throws Exception { + final SimpleString ADDRESS = new SimpleString("address"); + final SimpleString QUEUE_A = new SimpleString("a"); + final SimpleString QUEUE_B = new SimpleString("b"); + + Set aRoles = new HashSet<>(); + aRoles.add(new Role(QUEUE_A.toString(), false, true, true, false, false, false, false, false, true, false, true, false)); + server.getConfiguration().putSecurityRoles("jmx.queue." + QUEUE_A + ".countMessages", aRoles); + + Set bRoles = new HashSet<>(); + bRoles.add(new Role(QUEUE_B.toString(), false, true, true, false, false, false, false, false, true, false, true, false)); + server.getConfiguration().putSecurityRoles("jmx.queue." + QUEUE_B + ".countMessages", bRoles); + + server.start(); + + server.addAddressInfo(new AddressInfo(ADDRESS, RoutingType.ANYCAST)); + server.createQueue(new QueueConfiguration(QUEUE_A).setAddress(ADDRESS).setRoutingType(RoutingType.ANYCAST)); + server.createQueue(new QueueConfiguration(QUEUE_B).setAddress(ADDRESS).setRoutingType(RoutingType.ANYCAST)); + + QueueControl queueControlA = JMX.newMBeanProxy( + ManagementFactory.getPlatformMBeanServer(), + ObjectNameBuilder.DEFAULT.getQueueObjectName(ADDRESS, QUEUE_A, RoutingType.ANYCAST), QueueControl.class, false); + + QueueControl queueControlB = JMX.newMBeanProxy( + ManagementFactory.getPlatformMBeanServer(), + ObjectNameBuilder.DEFAULT.getQueueObjectName(ADDRESS, QUEUE_B, RoutingType.ANYCAST), QueueControl.class, false); + + Subject subjectA = new Subject(); + subjectA.getPrincipals().add(new UserPrincipal("a")); + subjectA.getPrincipals().add(new RolePrincipal("a")); + + Subject subjectB = new Subject(); + subjectB.getPrincipals().add(new UserPrincipal("b")); + subjectB.getPrincipals().add(new RolePrincipal("b")); + + // client A View queue A + assertEquals(Long.valueOf(0), Subject.doAs(subjectA, new PrivilegedExceptionAction() { + @Override + public Long run() throws Exception { + return queueControlA.countMessages(); + } + })); + + // client B view queue A + try { + assertEquals(Long.valueOf(0), Subject.doAs(subjectB, new PrivilegedExceptionAction() { + @Override + public Long run() throws Exception { + return queueControlA.countMessages(); + } + })); + Assert.fail("should throw exception here"); + } catch (Exception e) { + assertTrue(e instanceof SecurityException); + } + + // client B View queue B + assertEquals(Long.valueOf(0), Subject.doAs(subjectB, new PrivilegedExceptionAction() { + @Override + public Long run() throws Exception { + return queueControlB.countMessages(); + } + })); + + + // client A View queue B + try { + assertEquals(Long.valueOf(0), Subject.doAs(subjectA, new PrivilegedExceptionAction() { + @Override + public Long run() throws Exception { + return queueControlB.countMessages(); + } + })); + Assert.fail("should throw exception here"); + } catch (Exception e) { + assertTrue(e instanceof SecurityException); + } + } + +} diff --git a/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/LDAPSecurityTest.java b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/LDAPSecurityTest.java index face4455de..c76ceaa0f5 100644 --- a/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/LDAPSecurityTest.java +++ b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/security/LDAPSecurityTest.java @@ -175,7 +175,7 @@ public class LDAPSecurityTest extends AbstractLdapTestUnit { final SimpleString NON_DURABLE_QUEUE = new SimpleString("nonDurableQueue"); Set roles = new HashSet<>(); - roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false)); + roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); server.createQueue(new QueueConfiguration(DURABLE_QUEUE).setAddress(ADDRESS)); @@ -261,7 +261,7 @@ public class LDAPSecurityTest extends AbstractLdapTestUnit { final SimpleString NON_DURABLE_QUEUE = new SimpleString("nonDurableQueue"); Set roles = new HashSet<>(); - roles.add(new Role("admins", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("admins", true, true, true, true, true, true, true, true, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/MultiThreadedAuditLoggingTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/MultiThreadedAuditLoggingTest.java index 49c497f3ab..6ba3312a30 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/MultiThreadedAuditLoggingTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/MultiThreadedAuditLoggingTest.java @@ -59,10 +59,10 @@ public class MultiThreadedAuditLoggingTest extends ActiveMQTestBase { server.setSecurityManager(new ActiveMQBasicSecurityManager()); server.start(); Set roles = new HashSet<>(); - roles.add(new Role("queue1", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("queue1", true, true, true, true, true, true, true, true, true, true, false, false)); server.getSecurityRepository().addMatch("queue1", roles); roles = new HashSet<>(); - roles.add(new Role("queue2", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("queue2", true, true, true, true, true, true, true, true, true, true, false, false)); server.getSecurityRepository().addMatch("queue2", roles); server.getActiveMQServerControl().addUser("queue1", "queue1", "queue1", true); server.getActiveMQServerControl().addUser("queue2", "queue2", "queue2", true); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/AmqpClientTestSupport.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/AmqpClientTestSupport.java index 7eb4c5221a..e562203df9 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/AmqpClientTestSupport.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/AmqpClientTestSupport.java @@ -218,10 +218,10 @@ public class AmqpClientTestSupport extends AmqpTestSupport { // Configure roles HierarchicalRepository> securityRepository = server.getSecurityRepository(); HashSet value = new HashSet<>(); - value.add(new Role("nothing", false, false, false, false, false, false, false, false, false, false)); - value.add(new Role("browser", false, false, false, false, false, false, false, true, false, false)); - value.add(new Role("guest", false, true, false, false, false, false, false, true, false, false)); - value.add(new Role("full", true, true, true, true, true, true, true, true, true, true)); + value.add(new Role("nothing", false, false, false, false, false, false, false, false, false, false, false, false)); + value.add(new Role("browser", false, false, false, false, false, false, false, true, false, false, false, false)); + value.add(new Role("guest", false, true, false, false, false, false, false, true, false, false, false, false)); + value.add(new Role("full", true, true, true, true, true, true, true, true, true, true, false, false)); securityRepository.addMatch(getQueueName(), value); for (String match : securityMatches) { diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslExternalTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslExternalTest.java index 078d39f8af..ddcf0b3e4c 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslExternalTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslExternalTest.java @@ -114,7 +114,7 @@ public class JMSSaslExternalTest extends ActiveMQTestBase { // role mapping via CertLogin - TextFileCertificateLoginModule final String roleName = "widgets"; - Role role = new Role(roleName, true, true, true, true, true, true, true, true, true, true); + Role role = new Role(roleName, true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch("TEST", roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslGssapiTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslGssapiTest.java index 1408a8cde3..888f3b9899 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslGssapiTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslGssapiTest.java @@ -161,7 +161,7 @@ public class JMSSaslGssapiTest extends JMSClientTestSupport { securityManager.setConfiguration(null); final String roleName = "ALLOW_ALL"; - Role role = new Role(roleName, true, true, true, true, true, true, true, true, true, true); + Role role = new Role(roleName, true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch(getQueueName().toString(), roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/AutoCreateJmsDestinationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/AutoCreateJmsDestinationTest.java index 8016ff57b4..fe659c8c9e 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/AutoCreateJmsDestinationTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/AutoCreateJmsDestinationTest.java @@ -207,7 +207,7 @@ public class AutoCreateJmsDestinationTest extends JMSTestBase { ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().addUser("guest", "guest"); ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().setDefaultUser("guest"); ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().addRole("guest", "rejectAll"); - Role role = new Role("rejectAll", false, false, false, false, false, false, false, false, false, false); + Role role = new Role("rejectAll", false, false, false, false, false, false, false, false, false, false, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch("#", roles); @@ -481,7 +481,7 @@ public class AutoCreateJmsDestinationTest extends JMSTestBase { ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().addUser("guest", "guest"); ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().setDefaultUser("guest"); ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().addRole("guest", "allowAll"); - Role role = new Role("allowAll", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("allowAll", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch("#", roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/CoreClientTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/CoreClientTest.java index 4d31c7a0f1..2aaaa0bd9d 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/CoreClientTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/CoreClientTest.java @@ -214,7 +214,7 @@ public class CoreClientTest extends ActiveMQTestBase { server.start(); - Role myRole = new Role("myrole", true, true, true, true, true, true, true, true, true, true); + Role myRole = new Role("myrole", true, true, true, true, true, true, true, true, true, true, false, false); Set anySet = new HashSet<>(); anySet.add(myRole); server.getSecurityRepository().addMatch(baseAddress, anySet); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/SecurityFailoverTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/SecurityFailoverTest.java index c73689c7b5..a87789a3c7 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/SecurityFailoverTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/cluster/failover/SecurityFailoverTest.java @@ -103,7 +103,7 @@ public class SecurityFailoverTest extends FailoverTest { protected ActiveMQJAASSecurityManager installSecurity(TestableServer server) { ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getServer().getSecurityManager(); securityManager.getConfiguration().addUser("a", "b"); - Role role = new Role("arole", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("arole", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getServer().getSecurityRepository().addMatch("#", roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/RedeployTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/RedeployTest.java index 7f3d7493f4..d0b8379635 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/RedeployTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/RedeployTest.java @@ -48,6 +48,7 @@ import org.apache.activemq.artemis.core.postoffice.QueueBinding; import org.apache.activemq.artemis.core.postoffice.impl.DivertBinding; import org.apache.activemq.artemis.core.postoffice.impl.LocalQueueBinding; import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants; +import org.apache.activemq.artemis.core.security.CheckType; import org.apache.activemq.artemis.core.security.Role; import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType; import org.apache.activemq.artemis.core.server.cluster.impl.RemoteQueueBindingImpl; @@ -265,7 +266,7 @@ public class RedeployTest extends ActiveMQTestBase { roles = embeddedActiveMQ.getActiveMQServer().getSecurityRepository().getMatch("foo"); found = false; for (Role role : roles) { - if (role.getName().equals("b")) { + if (role.getName().equals("b") && CheckType.VIEW.hasRole(role)) { found = true; } } @@ -307,7 +308,7 @@ public class RedeployTest extends ActiveMQTestBase { assertTrue(found); - embeddedActiveMQ.getActiveMQServer().getActiveMQServerControl().addSecuritySettings("bar", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c"); + embeddedActiveMQ.getActiveMQServer().getActiveMQServerControl().addSecuritySettings("bar", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "", ""); roles = embeddedActiveMQ.getActiveMQServer().getSecurityRepository().getMatch("bar"); for (Role role : roles) { if (role.getName().equals("c")) { @@ -1055,9 +1056,9 @@ public class RedeployTest extends ActiveMQTestBase { @Test public void testRedeployWithFailover() throws Exception { Set original = new HashSet<>(); - original.add(new Role("a", false, true, false, false, false, false, false, false, false, false)); + original.add(new Role("a", false, true, false, false, false, false, false, false, false, false, false, false)); Set changed = new HashSet<>(); - changed.add(new Role("b", false, true, false, false, false, false, false, false, false, false)); + changed.add(new Role("b", false, true, false, false, false, false, false, false, false, false, false, false)); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/SimpleJNDIClientTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/SimpleJNDIClientTest.java index 8399f57a44..f58ca935a6 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/SimpleJNDIClientTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/SimpleJNDIClientTest.java @@ -575,7 +575,7 @@ public class SimpleJNDIClientTest extends ActiveMQTestBase { //setup user and role on broker ((ActiveMQJAASSecurityManager) liveService.getSecurityManager()).getConfiguration().addUser("myUser", "myPassword"); ((ActiveMQJAASSecurityManager) liveService.getSecurityManager()).getConfiguration().addRole("myUser", "consumeCreateRole"); - Role consumeCreateRole = new Role("consumeCreateRole", false, true, true, true, true, true, true, true, true, true); + Role consumeCreateRole = new Role("consumeCreateRole", false, true, true, true, true, true, true, true, true, true, false, false); Set consumerCreateRoles = new HashSet<>(); consumerCreateRoles.add(consumeCreateRole); liveService.getSecurityRepository().addMatch("test.queue", consumerCreateRoles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/TemporaryDestinationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/TemporaryDestinationTest.java index 463ad29743..0774fa5d70 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/TemporaryDestinationTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/TemporaryDestinationTest.java @@ -329,7 +329,7 @@ public class TemporaryDestinationTest extends JMSTestBase { ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("IDo", "Exist"); securityManager.getConfiguration().addRole("IDo", "myrole"); - Role myRole = new Role("myrole", true, true, true, true, true, true, true, true, true, true); + Role myRole = new Role("myrole", true, true, true, true, true, true, true, true, true, true, false, false); Set anySet = new HashSet<>(); anySet.add(myRole); server.getSecurityRepository().addMatch("#", anySet); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/multiprotocol/MultiprotocolJMSClientTestSupport.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/multiprotocol/MultiprotocolJMSClientTestSupport.java index 8088d67e8d..e4652a31ab 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/multiprotocol/MultiprotocolJMSClientTestSupport.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/multiprotocol/MultiprotocolJMSClientTestSupport.java @@ -238,10 +238,10 @@ public abstract class MultiprotocolJMSClientTestSupport extends ActiveMQTestBase // Configure roles HierarchicalRepository> securityRepository = server.getSecurityRepository(); HashSet value = new HashSet<>(); - value.add(new Role("nothing", false, false, false, false, false, false, false, false, false, false)); - value.add(new Role("browser", false, false, false, false, false, false, false, true, false, false)); - value.add(new Role("guest", false, true, false, false, false, false, false, true, false, false)); - value.add(new Role("full", true, true, true, true, true, true, true, true, true, true)); + value.add(new Role("nothing", false, false, false, false, false, false, false, false, false, false, false, false)); + value.add(new Role("browser", false, false, false, false, false, false, false, true, false, false, false, false)); + value.add(new Role("guest", false, true, false, false, false, false, false, true, false, false, false, false)); + value.add(new Role("full", true, true, true, true, true, true, true, true, true, true, false, false)); securityRepository.addMatch("#", value); for (String match : securityMatches) { diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/largemessage/ServerLargeMessageTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/largemessage/ServerLargeMessageTest.java index 0c58db73e7..75ea047802 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/largemessage/ServerLargeMessageTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/largemessage/ServerLargeMessageTest.java @@ -153,7 +153,7 @@ public class ServerLargeMessageTest extends ActiveMQTestBase { ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); server.getConfiguration().setPopulateValidatedUser(true); - Role role = new Role("programmers", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch("#", roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java index 5c7d34c7a3..a30cc03a32 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlTest.java @@ -238,7 +238,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase { ActiveMQServerControl serverControl = createManagementControl(); Wait.assertEquals(usingCore() ? 1 : 0, serverControl::getAuthenticationCacheSize); - Wait.assertEquals(usingCore() ? 7 : 0, serverControl::getAuthorizationCacheSize); + Wait.assertEquals(0, serverControl::getAuthorizationCacheSize); ServerLocator loc = createInVMNonHALocator(); ClientSessionFactory csf = createSessionFactory(loc); @@ -256,7 +256,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase { producer.send(m); Assert.assertEquals(usingCore() ? 2 : 1, serverControl.getAuthenticationCacheSize()); - Wait.assertEquals(usingCore() ? 8 : 1, () -> serverControl.getAuthorizationCacheSize()); + Wait.assertEquals(1, () -> serverControl.getAuthorizationCacheSize()); } @Test @@ -289,7 +289,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase { serverControl.clearAuthorizationCache(); Assert.assertEquals(usingCore() ? 1 : 0, serverControl.getAuthenticationCacheSize()); - Assert.assertEquals(usingCore() ? 7 : 0, serverControl.getAuthorizationCacheSize()); + Assert.assertEquals(0, serverControl.getAuthorizationCacheSize()); } @Test @@ -1061,7 +1061,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase { String exactAddress = "test.whatever"; assertEquals(1, serverControl.getRoles(addressMatch).length); - serverControl.addSecuritySettings(addressMatch, "foo", "foo, bar", null, "bar", "foo, bar", "", "", "bar", "foo", "foo"); + serverControl.addSecuritySettings(addressMatch, "foo", "foo, bar", null, "bar", "foo, bar", "", "", "bar", "foo", "foo", "", ""); // Restart the server. Those settings should be persisted @@ -6143,7 +6143,7 @@ public class ActiveMQServerControlTest extends ManagementTestBase { server.start(); HashSet role = new HashSet<>(); - role.add(new Role("guest", true, true, true, true, true, true, true, true, true, true)); + role.add(new Role("guest", true, true, true, true, true, true, true, true, true, true, false, false)); server.getSecurityRepository().addMatch("#", role); } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java index 9ef4b6755f..44c72ed32f 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java @@ -938,6 +938,22 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes proxy.invokeOperation("addSecuritySettings", addressMatch, sendRoles, consumeRoles, createDurableQueueRoles, deleteDurableQueueRoles, createNonDurableQueueRoles, deleteNonDurableQueueRoles, manageRoles, browseRoles); } + @Override + public void addSecuritySettings(String addressMatch, + String sendRoles, + String consumeRoles, + String createDurableQueueRoles, + String deleteDurableQueueRoles, + String createNonDurableQueueRoles, + String deleteNonDurableQueueRoles, + String manageRoles, + String browseRoles, + String createAddressRoles, + String deleteAddressRoles) throws Exception { + + proxy.invokeOperation("addSecuritySettings", addressMatch, sendRoles, consumeRoles, createDurableQueueRoles, deleteDurableQueueRoles, createNonDurableQueueRoles, deleteNonDurableQueueRoles, manageRoles, browseRoles, createAddressRoles, deleteAddressRoles); + } + @Override public void addSecuritySettings(String addressMatch, String sendRoles, @@ -949,8 +965,8 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes String manageRoles, String browseRoles, String createAddress, - String deleteAddress) throws Exception { - proxy.invokeOperation("addSecuritySettings", addressMatch, sendRoles, consumeRoles, createDurableQueueRoles, deleteDurableQueueRoles, createNonDurableQueueRoles, deleteNonDurableQueueRoles, manageRoles, browseRoles, createAddress, deleteAddress); + String deleteAddress, String viewRoles, String editRoles) throws Exception { + proxy.invokeOperation("addSecuritySettings", addressMatch, sendRoles, consumeRoles, createDurableQueueRoles, deleteDurableQueueRoles, createNonDurableQueueRoles, deleteNonDurableQueueRoles, manageRoles, browseRoles, createAddress, deleteAddress, viewRoles, editRoles); } @Override diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/AddressControlTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/AddressControlTest.java index 576d5499ba..7ef3cbf1a5 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/AddressControlTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/AddressControlTest.java @@ -224,7 +224,7 @@ public class AddressControlTest extends ManagementTestBase { public void testGetRoles() throws Exception { SimpleString address = RandomUtil.randomSimpleString(); SimpleString queue = RandomUtil.randomSimpleString(); - Role role = new Role(RandomUtil.randomString(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean()); + Role role = new Role(RandomUtil.randomString(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), false, false); session.createQueue(new QueueConfiguration(queue).setAddress(address)); @@ -260,7 +260,7 @@ public class AddressControlTest extends ManagementTestBase { public void testGetRolesAsJSON() throws Exception { SimpleString address = RandomUtil.randomSimpleString(); SimpleString queue = RandomUtil.randomSimpleString(); - Role role = new Role(RandomUtil.randomString(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean()); + Role role = new Role(RandomUtil.randomString(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), RandomUtil.randomBoolean(), false, false); session.createQueue(new QueueConfiguration(queue).setAddress(address)); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ManagementServiceImplTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ManagementServiceImplTest.java index 83a284cfa1..b721342053 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ManagementServiceImplTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ManagementServiceImplTest.java @@ -57,7 +57,7 @@ public class ManagementServiceImplTest extends ActiveMQTestBase { CoreMessage message = new CoreMessage(1, 100); ManagementHelper.putOperationInvocation(message, ResourceNames.BROKER, "createQueue", queue, address); - Message reply = server.getManagementService().handleMessage(message); + Message reply = server.getManagementService().handleMessage(null, message); Assert.assertTrue(ManagementHelper.hasOperationSucceeded(reply)); } @@ -73,7 +73,7 @@ public class ManagementServiceImplTest extends ActiveMQTestBase { CoreMessage message = new CoreMessage(1, 100); ManagementHelper.putOperationInvocation(message, ResourceNames.BROKER, "thereIsNoSuchOperation"); - ICoreMessage reply = server.getManagementService().handleMessage(message); + ICoreMessage reply = server.getManagementService().handleMessage(null, message); Assert.assertFalse(ManagementHelper.hasOperationSucceeded(reply)); Assert.assertNotNull(ManagementHelper.getResult(reply)); @@ -90,7 +90,7 @@ public class ManagementServiceImplTest extends ActiveMQTestBase { ICoreMessage message = new CoreMessage(1, 100); ManagementHelper.putOperationInvocation(message, "Resouce.Does.Not.Exist", "toString"); - ICoreMessage reply = server.getManagementService().handleMessage(message); + ICoreMessage reply = server.getManagementService().handleMessage(null, message); Assert.assertFalse(ManagementHelper.hasOperationSucceeded(reply)); Assert.assertNotNull(ManagementHelper.getResult(reply)); @@ -108,7 +108,7 @@ public class ManagementServiceImplTest extends ActiveMQTestBase { ManagementHelper.putAttribute(message, ResourceNames.BROKER, "started"); - ICoreMessage reply = server.getManagementService().handleMessage(message); + ICoreMessage reply = server.getManagementService().handleMessage(null, message); Assert.assertTrue(ManagementHelper.hasOperationSucceeded(reply)); Assert.assertTrue((Boolean) ManagementHelper.getResult(reply)); @@ -126,7 +126,7 @@ public class ManagementServiceImplTest extends ActiveMQTestBase { ManagementHelper.putAttribute(message, ResourceNames.BROKER, "attribute.Does.Not.Exist"); - ICoreMessage reply = server.getManagementService().handleMessage(message); + ICoreMessage reply = server.getManagementService().handleMessage(null, message); Assert.assertFalse(ManagementHelper.hasOperationSucceeded(reply)); Assert.assertNotNull(ManagementHelper.getResult(reply)); @@ -172,7 +172,7 @@ public class ManagementServiceImplTest extends ActiveMQTestBase { MessageUtil.setJMSCorrelationID(message, correlationID); ManagementHelper.putOperationInvocation(message, ResourceNames.BROKER, "createQueue", queue, address); - Message reply = server.getManagementService().handleMessage(message); + Message reply = server.getManagementService().handleMessage(null, message); Assert.assertTrue(ManagementHelper.hasOperationSucceeded(reply)); Assert.assertEquals(correlationID, MessageUtil.getJMSCorrelationID(reply)); } @@ -193,7 +193,7 @@ public class ManagementServiceImplTest extends ActiveMQTestBase { message.setUserID(messageId); ManagementHelper.putOperationInvocation(message, ResourceNames.BROKER, "createQueue", queue, address); - Message reply = server.getManagementService().handleMessage(message); + Message reply = server.getManagementService().handleMessage(null, message); Assert.assertTrue(ManagementHelper.hasOperationSucceeded(reply)); Assert.assertEquals(messageId.toString(), MessageUtil.getJMSCorrelationID(reply)); } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/MessageAuthorizationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/MessageAuthorizationTest.java index f06ac8f771..b4cd563eb3 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/MessageAuthorizationTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/MessageAuthorizationTest.java @@ -68,9 +68,9 @@ public class MessageAuthorizationTest extends ActiveMQTestBase { server = addServer(ActiveMQServers.newActiveMQServer(createDefaultNettyConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, true)); server.getConfiguration().setPopulateValidatedUser(true); Set roles = new HashSet<>(); - roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true)); - roles.add(new Role("a", false, true, true, true, true, false, false, false, true, true)); - roles.add(new Role("b", false, true, true, true, true, false, false, false, true, true)); + roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false)); + roles.add(new Role("a", false, true, true, true, true, false, false, false, true, true, false, false)); + roles.add(new Role("b", false, true, true, true, true, false, false, false, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", roles); BrokerMessageAuthorizationPlugin plugin = new BrokerMessageAuthorizationPlugin(); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SSLSecurityNotificationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SSLSecurityNotificationTest.java index 6987ad4a37..23f7f9e75a 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SSLSecurityNotificationTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SSLSecurityNotificationTest.java @@ -114,7 +114,7 @@ public class SSLSecurityNotificationTest extends ActiveMQTestBase { SimpleString queue = RandomUtil.randomSimpleString(); SimpleString address = RandomUtil.randomSimpleString(); - Role role = new Role("notif", true, true, true, true, false, true, true, true, true, true); + Role role = new Role("notif", true, true, true, true, false, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); @@ -153,7 +153,7 @@ public class SSLSecurityNotificationTest extends ActiveMQTestBase { @Test public void testCONNECTION_CREATED() throws Exception { - Role role = new Role("notif", true, true, true, true, false, true, true, true, true, true); + Role role = new Role("notif", true, true, true, true, false, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch("#", roles); @@ -208,7 +208,7 @@ public class SSLSecurityNotificationTest extends ActiveMQTestBase { notifQueue = RandomUtil.randomSimpleString(); - Role role = new Role("notif", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("notif", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch(ActiveMQDefaultConfiguration.getDefaultManagementNotificationAddress().toString(), roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementMessageRbacTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementMessageRbacTest.java new file mode 100644 index 0000000000..23ea30a089 --- /dev/null +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementMessageRbacTest.java @@ -0,0 +1,114 @@ +/* + * 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.activemq.artemis.tests.integration.management; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; +import org.apache.activemq.artemis.core.config.Configuration; +import org.apache.activemq.artemis.core.security.Role; +import org.apache.activemq.artemis.core.server.ActiveMQServer; +import org.apache.activemq.artemis.core.server.ActiveMQServers; +import org.apache.activemq.artemis.core.settings.HierarchicalRepository; +import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; +import org.junit.Test; + +public class SecurityManagementMessageRbacTest extends SecurityManagementTestBase { + + private final String password = "bla"; + + private final String guest = "guest"; + private final String view = "view"; + private final String updater = "updaterUser"; + private final String admin = "validAdminUser"; + + @Test + public void testSendManagementMessageWithAdminRole() throws Exception { + doSendBrokerManagementMessage(admin, password, true); + } + + @Test + public void testSendManagementMessageAsGuest() throws Exception { + doSendBrokerManagementMessage(guest, password, false); + } + + @Test + public void testSendManagementMessageAsView() throws Exception { + doSendBrokerManagementMessage(view, password, true); + } + + @Test + public void testSendManagementOpWithView() throws Exception { + doSendBrokerManagementMessageFor(false, view, password, false); + } + + @Test + public void testSendManagementOpWithGuest() throws Exception { + doSendBrokerManagementMessageFor(false, guest, password, false); + } + + @Test + public void testSendManagementOpWithUpdateRole() throws Exception { + doSendBrokerManagementMessageFor(false, updater, password, true); + } + + @Override + protected ActiveMQServer setupAndStartActiveMQServer() throws Exception { + Configuration config = createDefaultInVMConfig().setSecurityEnabled(true); + config.setManagementMessageRbac(true); // enable rbac view/update perms check + config.setManagementRbacPrefix("mm"); + ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(config, false)); + server.start(); + HierarchicalRepository> securityRepository = server.getSecurityRepository(); + ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); + securityManager.getConfiguration().addUser(admin, password); + securityManager.getConfiguration().addUser(guest, password); + securityManager.getConfiguration().addUser(updater, password); + securityManager.getConfiguration().addUser(view, password); + + securityManager.getConfiguration().addRole(admin, "manageRole"); + securityManager.getConfiguration().addRole(admin, "updateRole"); + securityManager.getConfiguration().addRole(guest, "guestRole"); + securityManager.getConfiguration().addRole(view, "viewRole"); + securityManager.getConfiguration().addRole(view, "manageRole"); + securityManager.getConfiguration().addRole(updater, "updateRole"); + securityManager.getConfiguration().addRole(updater, "manageRole"); + + Set permissionsOnManagementAddress = new HashSet<>(); + permissionsOnManagementAddress.add(new Role("manageRole", true, true, false, false, true, true, true, true, true, true, false, false)); + securityRepository.addMatch(ActiveMQDefaultConfiguration.getDefaultManagementAddress().toString() + ".*", permissionsOnManagementAddress); // for create reply queue + securityRepository.addMatch(ActiveMQDefaultConfiguration.getDefaultManagementAddress().toString(), permissionsOnManagementAddress); // for send to manage address + + + Set catchAllPermissions = new HashSet<>(); + catchAllPermissions.add(new Role("guestRole", false, false, false, false, false, false, false, false, false, false, false, false)); + securityRepository.addMatch("#", catchAllPermissions); + + final String brokerControlRbacAttributeKey = "mm.broker.isStarted"; + Set brokerControlRoles = new HashSet<>(); + brokerControlRoles.add(new Role("viewRole", true, true, true, true, true, true, true, true, true, true, true, false)); + brokerControlRoles.add(new Role("updateRole", true, true, true, true, true, true, true, true, true, true, true, true)); + + securityRepository.addMatch(brokerControlRbacAttributeKey, brokerControlRoles); + + final String brokerControlRbacOpKey = "mm.broker.enableMessageCounters"; + securityRepository.addMatch(brokerControlRbacOpKey, brokerControlRoles); + + return server; + } +} diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementTestBase.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementTestBase.java index 499aa68a47..1cac15ef19 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementTestBase.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementTestBase.java @@ -16,7 +16,12 @@ */ package org.apache.activemq.artemis.tests.integration.management; +import java.util.Arrays; +import java.util.Collection; + import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; +import org.apache.activemq.artemis.api.core.ActiveMQClusterSecurityException; +import org.apache.activemq.artemis.api.core.ActiveMQSecurityException; import org.apache.activemq.artemis.api.core.client.ClientMessage; import org.apache.activemq.artemis.api.core.client.ClientRequestor; import org.apache.activemq.artemis.api.core.client.ClientSession; @@ -24,18 +29,24 @@ import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; import org.apache.activemq.artemis.api.core.client.ServerLocator; import org.apache.activemq.artemis.api.core.management.ManagementHelper; import org.apache.activemq.artemis.api.core.management.ResourceNames; +import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.Assert; import org.junit.Before; +import org.junit.runners.Parameterized; public abstract class SecurityManagementTestBase extends ActiveMQTestBase { - private ActiveMQServer server; + @Parameterized.Parameter(0) + public boolean managementRbac = false; - + @Parameterized.Parameters(name = "managementRbac={0}") + public static Collection getParams() { + return Arrays.asList(new Object[][]{{true}, {false}}); + } @Override @@ -48,9 +59,31 @@ public abstract class SecurityManagementTestBase extends ActiveMQTestBase { protected abstract ActiveMQServer setupAndStartActiveMQServer() throws Exception; - protected void doSendManagementMessage(final String user, - final String password, - final boolean expectSuccess) throws Exception { + @Override + protected Configuration createDefaultInVMConfig() throws Exception { + Configuration configuration = super.createDefaultInVMConfig(); + if (managementRbac) { + configuration.setManagementMessageRbac(true); // enable rbac view/update perms check + } + return configuration; + } + + protected void doSendBrokerManagementMessage(final String user, + final String password, + final boolean expectSuccess) throws Exception { + doSendBrokerManagementMessageForAttribute(user, password, expectSuccess); + } + + protected void doSendBrokerManagementMessageForAttribute(final String user, + final String password, + final boolean expectSuccess) throws Exception { + doSendBrokerManagementMessageFor(true, user, password, expectSuccess); + } + + protected void doSendBrokerManagementMessageFor(final boolean attribute, final String user, + final String password, + final boolean expectSuccess) throws Exception { + ServerLocator locator = createInVMNonHALocator(); ClientSessionFactory sf = locator.createSessionFactory(); try { @@ -66,26 +99,40 @@ public abstract class SecurityManagementTestBase extends ActiveMQTestBase { ClientRequestor requestor = new ClientRequestor(session, ActiveMQDefaultConfiguration.getDefaultManagementAddress()); ClientMessage mngmntMessage = session.createMessage(false); - ManagementHelper.putAttribute(mngmntMessage, ResourceNames.BROKER, "started"); + if (attribute) { + ManagementHelper.putAttribute(mngmntMessage, ResourceNames.BROKER, "started"); + } else { + ManagementHelper.putOperationInvocation(mngmntMessage, ResourceNames.BROKER, "enableMessageCounters"); + } ClientMessage reply = requestor.request(mngmntMessage, 500); if (expectSuccess) { Assert.assertNotNull(reply); - Assert.assertTrue((Boolean) ManagementHelper.getResult(reply)); + Assert.assertTrue("" + ManagementHelper.getResult(reply), (Boolean) ManagementHelper.hasOperationSucceeded(reply)); + if (attribute) { + Assert.assertTrue("" + ManagementHelper.getResult(reply), (Boolean) ManagementHelper.getResult(reply)); + } } else { - Assert.assertNull(reply); + if (attribute) { + Assert.assertNull(reply); + } else { + Assert.assertNotNull(reply); + Assert.assertFalse("" + ManagementHelper.getResult(reply), (Boolean) ManagementHelper.hasOperationSucceeded(reply)); + } } requestor.close(); - } catch (Exception e) { + } catch (ActiveMQSecurityException possiblyExpected) { if (expectSuccess) { - Assert.fail("got unexpected exception " + e.getClass() + ": " + e.getMessage()); - e.printStackTrace(); + Assert.fail("got unexpected security exception " + possiblyExpected.getClass() + ": " + possiblyExpected.getMessage()); } + } catch (ActiveMQClusterSecurityException possiblyExpected) { + if (expectSuccess) { + Assert.fail("got unexpected security exception " + possiblyExpected.getClass() + ": " + possiblyExpected.getMessage()); + } + } catch (Exception e) { + Assert.fail("got unexpected exception " + e.getClass() + ": " + e.getMessage()); } finally { sf.close(); } } - - - } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithConfiguredAdminUserTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithConfiguredAdminUserTest.java index 83e748bf9f..a5ee8954a9 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithConfiguredAdminUserTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithConfiguredAdminUserTest.java @@ -26,7 +26,10 @@ import org.apache.activemq.artemis.core.server.ActiveMQServers; import org.apache.activemq.artemis.core.settings.HierarchicalRepository; import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class SecurityManagementWithConfiguredAdminUserTest extends SecurityManagementTestBase { @@ -48,22 +51,22 @@ public class SecurityManagementWithConfiguredAdminUserTest extends SecurityManag */ @Test public void testSendManagementMessageWithClusterAdminUser() throws Exception { - doSendManagementMessage(ActiveMQDefaultConfiguration.getDefaultClusterUser(), CLUSTER_PASSWORD, true); + doSendBrokerManagementMessage(ActiveMQDefaultConfiguration.getDefaultClusterUser(), CLUSTER_PASSWORD, true); } @Test public void testSendManagementMessageWithAdminRole() throws Exception { - doSendManagementMessage(validAdminUser, validAdminPassword, true); + doSendBrokerManagementMessage(validAdminUser, validAdminPassword, true); } @Test public void testSendManagementMessageWithoutAdminRole() throws Exception { - doSendManagementMessage(invalidAdminUser, invalidAdminPassword, false); + doSendBrokerManagementMessage(invalidAdminUser, invalidAdminPassword, false); } @Test public void testSendManagementMessageWithoutUserCredentials() throws Exception { - doSendManagementMessage(null, null, false); + doSendBrokerManagementMessage(null, null, false); } @@ -83,10 +86,10 @@ public class SecurityManagementWithConfiguredAdminUserTest extends SecurityManag securityManager.getConfiguration().addRole(invalidAdminUser, "guest"); Set adminRole = securityRepository.getMatch(ActiveMQDefaultConfiguration.getDefaultManagementAddress().toString()); - adminRole.add(new Role("admin", true, true, true, true, true, true, true, true, true, true)); + adminRole.add(new Role("admin", true, true, true, true, true, true, true, true, true, true, managementRbac, managementRbac)); securityRepository.addMatch(ActiveMQDefaultConfiguration.getDefaultManagementAddress().toString(), adminRole); Set guestRole = securityRepository.getMatch("*"); - guestRole.add(new Role("guest", true, true, true, true, true, true, false, true, true, true)); + guestRole.add(new Role("guest", true, true, true, true, true, true, false, true, true, true, false, false)); securityRepository.addMatch("*", guestRole); return server; diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithDefaultConfigurationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithDefaultConfigurationTest.java index 171072a427..0b44a02aed 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithDefaultConfigurationTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithDefaultConfigurationTest.java @@ -21,22 +21,25 @@ import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.ActiveMQServers; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class SecurityManagementWithDefaultConfigurationTest extends SecurityManagementTestBase { @Test public void testSendManagementMessageWithDefaultClusterAdminUser() throws Exception { - doSendManagementMessage(ActiveMQDefaultConfiguration.getDefaultClusterUser(), ActiveMQDefaultConfiguration.getDefaultClusterPassword(), true); + doSendBrokerManagementMessage(ActiveMQDefaultConfiguration.getDefaultClusterUser(), ActiveMQDefaultConfiguration.getDefaultClusterPassword(), true); } @Test public void testSendManagementMessageWithGuest() throws Exception { - doSendManagementMessage("guest", "guest", false); + doSendBrokerManagementMessage("guest", "guest", false); } @Test public void testSendManagementMessageWithoutUserCredentials() throws Exception { - doSendManagementMessage(null, null, false); + doSendBrokerManagementMessage(null, null, false); } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithModifiedConfigurationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithModifiedConfigurationTest.java index 91c6f5b644..06e65ff927 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithModifiedConfigurationTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityManagementWithModifiedConfigurationTest.java @@ -21,7 +21,10 @@ import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.ActiveMQServers; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class SecurityManagementWithModifiedConfigurationTest extends SecurityManagementTestBase { @@ -31,22 +34,22 @@ public class SecurityManagementWithModifiedConfigurationTest extends SecurityMan @Test public void testSendManagementMessageWithModifiedClusterAdminUser() throws Exception { - doSendManagementMessage(ActiveMQDefaultConfiguration.getDefaultClusterUser(), configuredClusterPassword, true); + doSendBrokerManagementMessage(ActiveMQDefaultConfiguration.getDefaultClusterUser(), configuredClusterPassword, true); } @Test public void testSendManagementMessageWithDefaultClusterAdminUser() throws Exception { - doSendManagementMessage(ActiveMQDefaultConfiguration.getDefaultClusterUser(), ActiveMQDefaultConfiguration.getDefaultClusterPassword(), false); + doSendBrokerManagementMessage(ActiveMQDefaultConfiguration.getDefaultClusterUser(), ActiveMQDefaultConfiguration.getDefaultClusterPassword(), false); } @Test public void testSendManagementMessageWithGuest() throws Exception { - doSendManagementMessage("guest", "guest", false); + doSendBrokerManagementMessage("guest", "guest", false); } @Test public void testSendManagementMessageWithoutUserCredentials() throws Exception { - doSendManagementMessage(null, null, false); + doSendBrokerManagementMessage(null, null, false); } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityNotificationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityNotificationTest.java index 1e9e55de62..c636d18a2f 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityNotificationTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityNotificationTest.java @@ -16,6 +16,10 @@ */ package org.apache.activemq.artemis.tests.integration.management; +import javax.management.JMX; +import javax.security.auth.Subject; +import java.lang.management.ManagementFactory; +import java.security.PrivilegedExceptionAction; import java.util.HashSet; import java.util.Set; @@ -29,13 +33,16 @@ import org.apache.activemq.artemis.api.core.client.ClientMessage; import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; import org.apache.activemq.artemis.api.core.client.ServerLocator; +import org.apache.activemq.artemis.api.core.management.AddressControl; import org.apache.activemq.artemis.api.core.management.ManagementHelper; +import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder; import org.apache.activemq.artemis.core.config.Configuration; import org.apache.activemq.artemis.core.security.CheckType; import org.apache.activemq.artemis.core.security.Role; import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.ActiveMQServers; import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.apache.activemq.artemis.utils.RandomUtil; import org.junit.Assert; @@ -91,7 +98,7 @@ public class SecurityNotificationTest extends ActiveMQTestBase { SimpleString address = RandomUtil.randomSimpleString(); // guest can not create queue - Role role = new Role("roleCanNotCreateQueue", true, true, false, true, false, true, true, true, true, true); + Role role = new Role("roleCanNotCreateQueue", true, true, false, true, false, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch(address.toString(), roles); @@ -131,12 +138,54 @@ public class SecurityNotificationTest extends ActiveMQTestBase { guestSession.close(); } + @Test + public void testSubjectSECURITY_PERMISSION_VIOLATION() throws Exception { + + SecurityNotificationTest.flush(notifConsumer); + + Subject guestSubject = new Subject(); + guestSubject.getPrincipals().add(new UserPrincipal("guest")); + + final AddressControl addressControl = JMX.newMBeanProxy( + ManagementFactory.getPlatformMBeanServer(), + ObjectNameBuilder.DEFAULT.getAddressObjectName(ActiveMQDefaultConfiguration.getDefaultManagementNotificationAddress()), AddressControl.class, false); + + Exception e = Subject.doAs(guestSubject, new PrivilegedExceptionAction() { + @Override + public Exception run() throws Exception { + try { + addressControl.sendMessage(null, 1, "hi", false, null, null); + fail("need Send permission"); + } catch (Exception expected) { + assertTrue(expected.getMessage().contains("guest")); + assertTrue(expected.getMessage().contains("SEND")); + return expected; + } + return null; + } + }); + assertNotNull("expect exception", e); + + ClientMessage[] notifications = SecurityNotificationTest.consumeMessages(3, notifConsumer); + int i = 0; + for (i = 0; i < notifications.length; i++) { + if (SECURITY_PERMISSION_VIOLATION.toString().equals(notifications[i].getObjectProperty(ManagementHelper.HDR_NOTIFICATION_TYPE).toString())) { + break; + } + } + Assert.assertTrue(i < notifications.length); + Assert.assertEquals(SECURITY_PERMISSION_VIOLATION.toString(), notifications[i].getObjectProperty(ManagementHelper.HDR_NOTIFICATION_TYPE).toString()); + Assert.assertEquals("guest", notifications[i].getObjectProperty(ManagementHelper.HDR_USER).toString()); + Assert.assertEquals(ActiveMQDefaultConfiguration.getDefaultManagementNotificationAddress().toString(), notifications[i].getObjectProperty(ManagementHelper.HDR_ADDRESS).toString()); + Assert.assertEquals(CheckType.SEND.toString(), notifications[i].getObjectProperty(ManagementHelper.HDR_CHECK_TYPE).toString()); + } + @Test public void testCONSUMER_CREATED() throws Exception { SimpleString queue = RandomUtil.randomSimpleString(); SimpleString address = RandomUtil.randomSimpleString(); - Role role = new Role("role", true, true, true, true, false, true, true, true, true, true); + Role role = new Role("role", true, true, true, true, false, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch(address.toString(), roles); @@ -173,7 +222,7 @@ public class SecurityNotificationTest extends ActiveMQTestBase { public void setUp() throws Exception { super.setUp(); - Configuration config = createDefaultInVMConfig().setSecurityEnabled(true); + Configuration config = createDefaultInVMConfig().setSecurityEnabled(true).setJMXManagementEnabled(true); server = addServer(ActiveMQServers.newActiveMQServer(config, false)); server.start(); @@ -184,7 +233,7 @@ public class SecurityNotificationTest extends ActiveMQTestBase { securityManager.getConfiguration().addUser("guest", "guest"); securityManager.getConfiguration().setDefaultUser("guest"); - Role role = new Role("notif", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("notif", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch(ActiveMQDefaultConfiguration.getDefaultManagementNotificationAddress().toString(), roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTSecurityManagerTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTSecurityManagerTest.java index 802af06186..f8ed0ea4fc 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTSecurityManagerTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTSecurityManagerTest.java @@ -30,6 +30,7 @@ import org.apache.activemq.artemis.spi.core.protocol.ProtocolManager; import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection; import org.apache.activemq.artemis.spi.core.remoting.Acceptor; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; import org.apache.activemq.artemis.tests.util.RandomUtil; import org.apache.activemq.artemis.tests.util.Wait; import org.fusesource.mqtt.client.BlockingConnection; @@ -61,7 +62,9 @@ public class MQTTSecurityManagerTest extends MQTTTestSupport { throw new InvalidClientIdException(); } remotingConnection.setClientID(clientID); - return new Subject(); + Subject subject = new Subject(); + subject.getPrincipals().add(new UserPrincipal(user)); + return subject; } @Override diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTTestSupport.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTTestSupport.java index a15360f115..42655b81aa 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTTestSupport.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/MQTTTestSupport.java @@ -198,10 +198,10 @@ public class MQTTTestSupport extends ActiveMQTestBase { // Configure roles HierarchicalRepository> securityRepository = server.getSecurityRepository(); HashSet value = new HashSet<>(); - value.add(new Role("nothing", false, false, false, false, false, false, false, false, false, false)); - value.add(new Role("browser", false, false, false, false, false, false, false, true, false, false)); - value.add(new Role("guest", false, true, false, false, false, false, false, true, false, false)); - value.add(new Role("full", true, true, true, true, true, true, true, true, true, true)); + value.add(new Role("nothing", false, false, false, false, false, false, false, false, false, false, false, false)); + value.add(new Role("browser", false, false, false, false, false, false, false, true, false, false, false, false)); + value.add(new Role("guest", false, true, false, false, false, false, false, true, false, false, false, false)); + value.add(new Role("full", true, true, true, true, true, true, true, true, true, true, false, false)); securityRepository.addMatch(MQTTUtil.getCoreAddressFromMqttTopic(getQueueName(), server.getConfiguration().getWildcardConfiguration()), value); server.getConfiguration().setSecurityEnabled(true); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/PahoMQTTQOS2SecurityTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/PahoMQTTQOS2SecurityTest.java index 0af994e89c..fe84ba1d97 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/PahoMQTTQOS2SecurityTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt/PahoMQTTQOS2SecurityTest.java @@ -52,7 +52,7 @@ public class PahoMQTTQOS2SecurityTest extends MQTTTestSupport { // Configure roles HierarchicalRepository> securityRepository = server.getSecurityRepository(); HashSet value = new HashSet<>(); - value.add(new Role("addressOnly", true, true, true, true, false, false, false, false, true, true)); + value.add(new Role("addressOnly", true, true, true, true, false, false, false, false, true, true, false, false)); securityRepository.addMatch(MQTTUtil.getCoreAddressFromMqttTopic(getQueueName(), server.getConfiguration().getWildcardConfiguration()), value); } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/MQTT5TestSupport.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/MQTT5TestSupport.java index e2cd5e66b9..42eb40002c 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/MQTT5TestSupport.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/MQTT5TestSupport.java @@ -217,12 +217,12 @@ public class MQTT5TestSupport extends ActiveMQTestBase { // Configure roles HierarchicalRepository> securityRepository = server.getSecurityRepository(); HashSet value = new HashSet<>(); - value.add(new Role("nothing", false, false, false, false, false, false, false, false, false, false)); - value.add(new Role("browser", false, false, false, false, false, false, false, true, false, false)); - value.add(new Role("guest", false, true, false, false, false, false, false, true, false, false)); - value.add(new Role("full", true, true, true, true, true, true, true, true, true, true)); - value.add(new Role("createAddress", false, false, false, false, false, false, false, false, true, false)); - value.add(new Role("noDelete", true, true, true, false, true, false, true, true, true, true)); + value.add(new Role("nothing", false, false, false, false, false, false, false, false, false, false, false, false)); + value.add(new Role("browser", false, false, false, false, false, false, false, true, false, false, false, false)); + value.add(new Role("guest", false, true, false, false, false, false, false, true, false, false, false, false)); + value.add(new Role("full", true, true, true, true, true, true, true, true, true, true, false, false)); + value.add(new Role("createAddress", false, false, false, false, false, false, false, false, true, false, false, false)); + value.add(new Role("noDelete", true, true, true, false, true, false, true, true, true, true, false, false)); securityRepository.addMatch("#", value); server.getConfiguration().setSecurityEnabled(true); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/ssl/CertificateAuthenticationSslTests.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/ssl/CertificateAuthenticationSslTests.java index 2f06512d2d..a09f041684 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/ssl/CertificateAuthenticationSslTests.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/mqtt5/ssl/CertificateAuthenticationSslTests.java @@ -83,7 +83,7 @@ public class CertificateAuthenticationSslTests extends MQTT5TestSupport { server.setSecurityManager(new ActiveMQJAASSecurityManager("CertLogin")); server.getConfiguration().setSecurityEnabled(true); HashSet roles = new HashSet<>(); - roles.add(new Role("programmers", true, true, true, false, false, false, false, false, true, true)); + roles.add(new Role("programmers", true, true, true, false, false, false, false, false, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", roles); } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/OpenWireTestBase.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/OpenWireTestBase.java index a8d2cdf6c8..086ac4bb12 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/OpenWireTestBase.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/OpenWireTestBase.java @@ -73,23 +73,23 @@ public class OpenWireTestBase extends ActiveMQTestBase { securityManager.getConfiguration().addRole("openwireSender", "sender"); securityManager.getConfiguration().addUser("openwireSender", "SeNdEr"); //sender cannot receive - Role senderRole = new Role("sender", true, false, false, false, true, true, false, false, true, true); + Role senderRole = new Role("sender", true, false, false, false, true, true, false, false, true, true, false, false); securityManager.getConfiguration().addRole("openwireReceiver", "receiver"); securityManager.getConfiguration().addUser("openwireReceiver", "ReCeIvEr"); //receiver cannot send - Role receiverRole = new Role("receiver", false, true, false, false, true, true, false, true, false, false); + Role receiverRole = new Role("receiver", false, true, false, false, true, true, false, true, false, false, false, false); securityManager.getConfiguration().addRole("openwireGuest", "guest"); securityManager.getConfiguration().addUser("openwireGuest", "GuEsT"); //guest cannot do anything - Role guestRole = new Role("guest", false, false, false, false, false, false, false, false, false, false); + Role guestRole = new Role("guest", false, false, false, false, false, false, false, false, false, false, false, false); securityManager.getConfiguration().addRole("openwireDestinationManager", "manager"); securityManager.getConfiguration().addUser("openwireDestinationManager", "DeStInAtIoN"); - Role destRole = new Role("manager", false, false, false, false, true, true, false, false, true, false); + Role destRole = new Role("manager", false, false, false, false, true, true, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(senderRole); @@ -101,7 +101,7 @@ public class OpenWireTestBase extends ActiveMQTestBase { // advisory addresses, anyone can create/consume // broker can produce - Role advisoryReceiverRole = new Role("advisoryReceiver", false, true, false, false, true, true, false, true, true, false); + Role advisoryReceiverRole = new Role("advisoryReceiver", false, true, false, false, true, true, false, true, true, false, false, false); roles = new HashSet<>(); roles.add(advisoryReceiverRole); 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 9b4e2beb8a..1e8bd859ee 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 @@ -62,7 +62,7 @@ public class SecurityOpenWireTest extends BasicOpenWireTest { @Test public void testSendNoAuth() throws Exception { Set roles = new HashSet<>(); - roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false)); + roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false, false, false)); server.getSecurityRepository().addMatch("denyQ", roles); SimpleString denyQ = new SimpleString("denyQ"); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/RolesConfigurationStorageTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/RolesConfigurationStorageTest.java index 8e4a86a745..0653de8891 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/RolesConfigurationStorageTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/RolesConfigurationStorageTest.java @@ -50,9 +50,9 @@ public class RolesConfigurationStorageTest extends StorageManagerTestBase { public void testStoreSecuritySettings() throws Exception { createStorage(); - addSetting(new PersistedSecuritySetting("a#", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1")); + addSetting(new PersistedSecuritySetting("a#", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", null, null)); - addSetting(new PersistedSecuritySetting("a2", "a1", null, "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1")); + addSetting(new PersistedSecuritySetting("a2", "a1", null, "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", null, null)); journal.stop(); @@ -62,9 +62,9 @@ public class RolesConfigurationStorageTest extends StorageManagerTestBase { checkSettings(); - addSetting(new PersistedSecuritySetting("a2", "a1", null, "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1")); + addSetting(new PersistedSecuritySetting("a2", "a1", null, "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", null, null)); - addSetting(new PersistedSecuritySetting("a3", "a1", null, "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1")); + addSetting(new PersistedSecuritySetting("a3", "a1", null, "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", null, null)); checkSettings(); @@ -92,7 +92,7 @@ public class RolesConfigurationStorageTest extends StorageManagerTestBase { checkSettings(); - addSetting(new PersistedSecuritySetting("a#", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1")); + addSetting(new PersistedSecuritySetting("a#", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", "a1", null, null)); journal.stop(); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/XmlImportExportRbacTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/XmlImportExportRbacTest.java new file mode 100644 index 0000000000..63e171bd94 --- /dev/null +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/XmlImportExportRbacTest.java @@ -0,0 +1,172 @@ +/* + * 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.activemq.artemis.tests.integration.persistence; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.lang.invoke.MethodHandles; +import java.lang.management.ManagementFactory; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; + +import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; +import org.apache.activemq.artemis.api.core.QueueConfiguration; +import org.apache.activemq.artemis.api.core.SimpleString; +import org.apache.activemq.artemis.api.core.client.ClientConsumer; +import org.apache.activemq.artemis.api.core.client.ClientMessage; +import org.apache.activemq.artemis.api.core.client.ClientProducer; +import org.apache.activemq.artemis.api.core.client.ClientSession; +import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; +import org.apache.activemq.artemis.api.core.client.ServerLocator; +import org.apache.activemq.artemis.cli.commands.tools.xml.XmlDataExporter; +import org.apache.activemq.artemis.cli.commands.tools.xml.XmlDataImporter; +import org.apache.activemq.artemis.core.config.Configuration; +import org.apache.activemq.artemis.core.security.Role; +import org.apache.activemq.artemis.core.server.ActiveMQServer; +import org.apache.activemq.artemis.core.server.ActiveMQServers; +import org.apache.activemq.artemis.core.server.Queue; +import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; +import org.apache.activemq.artemis.tests.integration.security.SecurityTest; +import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class XmlImportExportRbacTest extends ActiveMQTestBase { + + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + + static { + String path = System.getProperty("java.security.auth.login.config"); + if (path == null) { + URL resource = SecurityTest.class.getClassLoader().getResource("login.config"); + if (resource != null) { + path = resource.getFile(); + System.setProperty("java.security.auth.login.config", path); + } + } + } + + + public static final int CONSUMER_TIMEOUT = 5000; + private static final String QUEUE_NAME = "A1"; + private ServerLocator locator; + private ActiveMQServer server; + private ClientSessionFactory factory; + + Set permissionsOnManagementAddress = new HashSet<>(); + + private ClientSession basicSetUp() throws Exception { + + ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLogin"); + Configuration configuration = createDefaultInVMConfig(); + configuration.setSecurityEnabled(true); + configuration.setManagementMessageRbac(true); + + server = addServer(ActiveMQServers.newActiveMQServer(configuration, ManagementFactory.getPlatformMBeanServer(), securityManager, true)); + + // our 'first' user is in the 'programmers' role, grant minimal necessary permissions + Set permissionToProduceAnyMessage = new HashSet<>(); + permissionToProduceAnyMessage.add(new Role("programmers", true, true, true, false, false, false, false, false, true, false, false, false)); + server.getSecurityRepository().addMatch("A1", permissionToProduceAnyMessage); + + permissionsOnManagementAddress.add(new Role("programmers", true, true, true, false, true, true, true, false, true, true, true, false)); + + server.getSecurityRepository().addMatch(ActiveMQDefaultConfiguration.getDefaultManagementAddress().toString() + ".*", permissionsOnManagementAddress); // for create reply queue + server.getSecurityRepository().addMatch(ActiveMQDefaultConfiguration.getDefaultManagementAddress().toString(), permissionsOnManagementAddress); // for send to manage address + + + server.start(); + locator = createInVMNonHALocator(); + factory = createSessionFactory(locator); + return addClientSession(factory.createSession("first", "secret", false, true, true, false, 100)); + } + + + @Test + public void testExportWithOutAndWithQueueControlPerms() throws Exception { + ClientSession session = basicSetUp(); + + session.createQueue(new QueueConfiguration(QUEUE_NAME)); + + ClientProducer producer = session.createProducer(QUEUE_NAME); + + StringBuilder international = new StringBuilder(); + for (char x = 800; x < 1200; x++) { + international.append(x); + } + + String special = "\"<>'&"; + + for (int i = 0; i < 5; i++) { + ClientMessage msg = session.createMessage(true); + msg.getBodyBuffer().writeString("Bob the giant pig " + i); + producer.send(msg); + } + + session.close(); + locator.close(); + server.stop(); + + ByteArrayOutputStream xmlOutputStream = new ByteArrayOutputStream(); + XmlDataExporter xmlDataExporter = new XmlDataExporter(); + xmlDataExporter.process(xmlOutputStream, server.getConfiguration().getBindingsDirectory(), server.getConfiguration().getJournalDirectory(), server.getConfiguration().getPagingDirectory(), server.getConfiguration().getLargeMessagesDirectory()); + if (logger.isDebugEnabled()) { + logger.debug(new String(xmlOutputStream.toByteArray())); + } + + clearDataRecreateServerDirs(); + server.start(); + locator = createInVMNonHALocator(); + factory = createSessionFactory(locator); + session = factory.createSession("first", "secret", false, true, true, false, 100); + + + ByteArrayInputStream xmlInputStream = new ByteArrayInputStream(xmlOutputStream.toByteArray()); + XmlDataImporter xmlDataImporter = new XmlDataImporter(); + xmlDataImporter.validate(xmlInputStream); + xmlInputStream.reset(); + xmlDataImporter.process(xmlInputStream, session); + + // assert messages not present due to no permission + Queue queue = server.locateQueue(QUEUE_NAME); + assertEquals(0L, queue.getMessageCount()); + + // try again with permission + server.getSecurityRepository().addMatch(SimpleString.toSimpleString(server.getConfiguration().getManagementRbacPrefix()).concat(".queue." + QUEUE_NAME + ".getID").toString(), permissionsOnManagementAddress); // for send to manage address + + xmlInputStream = new ByteArrayInputStream(xmlOutputStream.toByteArray()); + xmlDataImporter = new XmlDataImporter(); + xmlDataImporter.validate(xmlInputStream); + xmlInputStream.reset(); + xmlDataImporter.process(xmlInputStream, session); + + + // should be able to consume and verify with the queue control getAttribute view permission + ClientConsumer consumer = session.createConsumer(QUEUE_NAME); + session.start(); + + for (int i = 0; i < 5; i++) { + ClientMessage msg = consumer.receive(CONSUMER_TIMEOUT); + byte[] body = new byte[msg.getBodySize()]; + msg.getBodyBuffer().readBytes(body); + assertTrue(new String(body).contains("Bob the giant pig " + i)); + } + } +} diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/ActiveMQMessageHandlerSecurityTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/ActiveMQMessageHandlerSecurityTest.java index 143ec27a43..4f4c6c70ae 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/ActiveMQMessageHandlerSecurityTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/ActiveMQMessageHandlerSecurityTest.java @@ -67,7 +67,7 @@ public class ActiveMQMessageHandlerSecurityTest extends ActiveMQRATestBase { ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("testuser", "testpassword"); securityManager.getConfiguration().addRole("testuser", "arole"); - Role role = new Role("arole", false, true, false, false, false, false, false, false, false, false); + Role role = new Role("arole", false, true, false, false, false, false, false, false, false, false, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch(MDBQUEUEPREFIXED, roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/JMSContextTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/JMSContextTest.java index 463fe863a4..8a1c9079a0 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/JMSContextTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/JMSContextTest.java @@ -57,7 +57,7 @@ public class JMSContextTest extends ActiveMQRATestBase { securityManager.getConfiguration().setDefaultUser("guest"); securityManager.getConfiguration().addRole("testuser", "arole"); securityManager.getConfiguration().addRole("guest", "arole"); - Role role = new Role("arole", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("arole", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch(MDBQUEUEPREFIXED, roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionJTATest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionJTATest.java index 11f61f50b4..957b3e187d 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionJTATest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionJTATest.java @@ -71,7 +71,7 @@ public class OutgoingConnectionJTATest extends ActiveMQRATestBase { ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().setDefaultUser("guest"); ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().addRole("testuser", "arole"); ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().addRole("guest", "arole"); - Role role = new Role("arole", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("arole", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch(MDBQUEUEPREFIXED, roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionNoJTATest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionNoJTATest.java index 430c0f3fda..c8dd4965bf 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionNoJTATest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionNoJTATest.java @@ -71,7 +71,7 @@ public class OutgoingConnectionNoJTATest extends ActiveMQRATestBase { ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().setDefaultUser("guest"); ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().addRole("testuser", "arole"); ((ActiveMQJAASSecurityManager) server.getSecurityManager()).getConfiguration().addRole("guest", "arole"); - Role role = new Role("arole", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("arole", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch(MDBQUEUEPREFIXED, roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionTest.java index feed83c97c..0d80c01f89 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/OutgoingConnectionTest.java @@ -82,7 +82,7 @@ public class OutgoingConnectionTest extends ActiveMQRATestBase { securityManager.getConfiguration().setDefaultUser("guest"); securityManager.getConfiguration().addRole("testuser", "arole"); securityManager.getConfiguration().addRole("guest", "arole"); - Role role = new Role("arole", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("arole", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch(MDBQUEUEPREFIXED, roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/routing/KeyTypeTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/routing/KeyTypeTest.java index 729b7d661c..7102015647 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/routing/KeyTypeTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/routing/KeyTypeTest.java @@ -241,7 +241,7 @@ public class KeyTypeTest extends RoutingTestBase { // ensure advisory permission is present for openwire connection creation by 'b' HierarchicalRepository> securityRepository = servers[0].getSecurityRepository(); - Role role = new Role("b", true, true, true, true, true, true, false, false, true, true); + Role role = new Role("b", true, true, true, true, true, true, false, false, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch("ActiveMQ.Advisory.#", roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/BasicSecurityManagerTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/BasicSecurityManagerTest.java index 6a15cebc40..3a1f495c92 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/BasicSecurityManagerTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/BasicSecurityManagerTest.java @@ -131,7 +131,7 @@ public class BasicSecurityManagerTest extends ActiveMQTestBase { ActiveMQServer server = initializeServer(); server.getConfiguration().setPopulateValidatedUser(true); server.start(); - Role role = new Role("programmers", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch("#", roles); @@ -178,7 +178,7 @@ public class BasicSecurityManagerTest extends ActiveMQTestBase { ActiveMQServer server = initializeServer(); Set roles = new HashSet<>(); - roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false)); + roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); server.addAddressInfo(new AddressInfo(ADDRESS, RoutingType.ANYCAST)); @@ -263,7 +263,7 @@ public class BasicSecurityManagerTest extends ActiveMQTestBase { ActiveMQServer server = initializeServer(); Set roles = new HashSet<>(); - roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/FQQNSendSecurityTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/FQQNSendSecurityTest.java index a1db3e9b31..5e512d3a72 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/FQQNSendSecurityTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/FQQNSendSecurityTest.java @@ -54,8 +54,8 @@ public class FQQNSendSecurityTest extends ActiveMQTestBase { super.setUp(); Configuration configuration = createDefaultInVMConfig().setSecurityEnabled(true); RoleSet roles = new RoleSet(); - roles.add(new Role(ALLOWED_ROLE, true, false, false, false, false, false, false, false, false, false)); - roles.add(new Role(DENIED_ROLE, false, false, false, false, false, false, false, false, false, false)); + roles.add(new Role(ALLOWED_ROLE, true, false, false, false, false, false, false, false, false, false, false, false)); + roles.add(new Role(DENIED_ROLE, false, false, false, false, false, false, false, false, false, false, false, false)); configuration.putSecurityRoles(CompositeAddress.toFullyQualified(ADDRESS, QUEUE), roles); ActiveMQServer server = createServer(false, configuration); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/PersistedSecuritySettingTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/PersistedSecuritySettingTest.java index 1b60425bfe..3d82b592cc 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/PersistedSecuritySettingTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/PersistedSecuritySettingTest.java @@ -40,5 +40,7 @@ public class PersistedSecuritySettingTest { persistedSecuritySetting.getDeleteNonDurableQueueRoles(); persistedSecuritySetting.getManageRoles(); persistedSecuritySetting.getSendRoles(); + persistedSecuritySetting.getViewRoles(); + persistedSecuritySetting.getEditRoles(); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/RecursiveNettySecurityTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/RecursiveNettySecurityTest.java index aa925e177f..891a353f34 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/RecursiveNettySecurityTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/RecursiveNettySecurityTest.java @@ -34,6 +34,7 @@ import org.apache.activemq.artemis.core.server.ActiveMQServers; import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5; import org.apache.activemq.artemis.spi.core.security.jaas.NoCacheLoginException; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.apache.activemq.artemis.tests.util.CFUtil; import org.junit.Assert; @@ -105,7 +106,9 @@ public class RecursiveNettySecurityTest extends ActiveMQTestBase { logger.warn(e.getMessage(), e); throw new NoCacheLoginException(e.getMessage()); } - return new Subject(); + Subject authenticatedSubject = new Subject(); + authenticatedSubject.getPrincipals().add(new UserPrincipal(user)); + return authenticatedSubject; } @Override diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorJmsTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorJmsTest.java index 64c84c4945..7a2ab059fd 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorJmsTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorJmsTest.java @@ -115,12 +115,12 @@ public class SecurityPerAcceptorJmsTest extends ActiveMQTestBase { ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager(); ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setResolveProtocols(true).addAcceptorConfiguration("netty", "tcp://127.0.0.1:61616?securityDomain=PropertiesLogin").setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); Set roles = new HashSet<>(); - roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false)); + roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false, false, false)); server.getConfiguration().putSecurityRoles("#", roles); // ensure advisory permission is still set for openwire to allow connection to succeed, alternative is url param jms.watchTopicAdvisories=false on the client connection factory roles = new HashSet<>(); - roles.add(new Role("programmers", false, true, false, false, true, true, false, false, true, false)); + roles.add(new Role("programmers", false, true, false, false, true, true, false, false, true, false, false, false)); server.getConfiguration().putSecurityRoles("ActiveMQ.Advisory.#", roles); server.start(); @@ -165,7 +165,7 @@ public class SecurityPerAcceptorJmsTest extends ActiveMQTestBase { ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true).setResolveProtocols(true).addAcceptorConfiguration("netty", "tcp://127.0.0.1:61616?securityDomain=PropertiesLogin"), ManagementFactory.getPlatformMBeanServer(), new ActiveMQJAASSecurityManager(), false)); Set roles = new HashSet<>(); - roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorTest.java index 43a840af0b..d7032b477a 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorTest.java @@ -108,7 +108,7 @@ public class SecurityPerAcceptorTest extends ActiveMQTestBase { ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager(); ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().addAcceptorConfiguration("acceptor", acceptorUrl).setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); Set roles = new HashSet<>(); - roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false)); + roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); server.addAddressInfo(new AddressInfo(ADDRESS, RoutingType.ANYCAST)); @@ -194,7 +194,7 @@ public class SecurityPerAcceptorTest extends ActiveMQTestBase { ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager(); ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true).addAcceptorConfiguration("acceptor", acceptorUrl), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); Set roles = new HashSet<>(); - roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java index 863005bf41..19fbec3dcb 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java @@ -72,6 +72,7 @@ import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager4; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5; import org.apache.activemq.artemis.spi.core.security.jaas.NoCacheLoginException; +import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.apache.activemq.artemis.utils.CompositeAddress; import org.apache.activemq.artemis.utils.SensitiveDataCodec; @@ -145,7 +146,9 @@ public class SecurityTest extends ActiveMQTestBase { String securityDomain) throws NoCacheLoginException { flipper = !flipper; if (flipper) { - return new Subject(); + Subject validatedSubject = new Subject(); + validatedSubject.getPrincipals().add(new UserPrincipal(user)); + return validatedSubject; } else { throw new NoCacheLoginException(); } @@ -236,7 +239,7 @@ public class SecurityTest extends ActiveMQTestBase { ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); server.getConfiguration().setPopulateValidatedUser(true); server.start(); - Role role = new Role("programmers", true, true, true, true, true, true, true, true, true, true); + Role role = new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch("#", roles); @@ -332,7 +335,7 @@ public class SecurityTest extends ActiveMQTestBase { // ensure advisory permission is still set for openwire to allow connection to succeed, alternative is url param jms.watchTopicAdvisories=false on the client connection factory HashSet roles = new HashSet<>(); - roles.add(new Role("programmers", false, true, false, false, true, true, false, false, true, false)); + roles.add(new Role("programmers", false, true, false, false, true, true, false, false, true, false, false, false)); server.getConfiguration().putSecurityRoles("ActiveMQ.Advisory.#", roles); server.start(); @@ -363,7 +366,7 @@ public class SecurityTest extends ActiveMQTestBase { ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); Set roles = new HashSet<>(); - roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false)); + roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false, false, false)); server.getConfiguration().putSecurityRoles("#", roles); Map params = new HashMap<>(); @@ -378,7 +381,7 @@ public class SecurityTest extends ActiveMQTestBase { server.start(); ActiveMQSslConnectionFactory factory = new ActiveMQSslConnectionFactory("ssl://localhost:61616?verifyHostName=false"); - factory.setUserName("test-user"); + // factory.setUserName("test-user"); factory.setTrustStore("server-ca-truststore.jks"); factory.setTrustStorePassword("securepass"); factory.setKeyStore("client-keystore.jks"); @@ -399,7 +402,8 @@ public class SecurityTest extends ActiveMQTestBase { session.createConsumer(session.createQueue("test.queue")); Assert.fail("should throw exception here"); } catch (Exception e) { - assertTrue(e.getMessage().contains("User: test-user does not have permission='CREATE_DURABLE_QUEUE' for queue test.queue on address test.queue")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='CREATE_DURABLE_QUEUE' for queue test.queue on address test.queue")); } //Test non durable create permission @@ -407,7 +411,8 @@ public class SecurityTest extends ActiveMQTestBase { session.createConsumer(session.createTopic("test.topic")); Assert.fail("should throw exception here"); } catch (Exception e) { - assertTrue(e.getMessage().contains("User: test-user does not have permission='CREATE_NON_DURABLE_QUEUE'")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='CREATE_NON_DURABLE_QUEUE'")); } //Add a test queue to the server @@ -419,7 +424,8 @@ public class SecurityTest extends ActiveMQTestBase { producer.send(session.createMessage()); Assert.fail("should throw exception here"); } catch (Exception e) { - assertTrue(e.getMessage().contains("User: test-user does not have permission='SEND'")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='SEND'")); } //Test queue consume permission @@ -427,7 +433,8 @@ public class SecurityTest extends ActiveMQTestBase { session.createConsumer(session.createQueue("test.queue")); Assert.fail("should throw exception here"); } catch (Exception e) { - assertTrue(e.getMessage().contains("User: test-user does not have permission='CONSUME' for queue test.queue on address test.queue")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='CONSUME' for queue test.queue on address test.queue")); } //Test queue browse permission @@ -436,7 +443,8 @@ public class SecurityTest extends ActiveMQTestBase { browser.getEnumeration(); Assert.fail("should throw exception here"); } catch (Exception e) { - assertTrue(e.getMessage().contains("User: test-user does not have permission='BROWSE' for queue test.queue on address test.queue")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='BROWSE' for queue test.queue on address test.queue")); } //Test queue deletion permission @@ -444,7 +452,8 @@ public class SecurityTest extends ActiveMQTestBase { connection.destroyDestination(new ActiveMQQueue("test.queue")); Assert.fail("should throw exception here"); } catch (Exception e) { - assertTrue(e.getMessage().contains("User: test-user does not have permission='DELETE_DURABLE_QUEUE' for queue test.queue on address test.queue")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='DELETE_DURABLE_QUEUE' for queue test.queue on address test.queue")); } //Test temp queue @@ -452,7 +461,8 @@ public class SecurityTest extends ActiveMQTestBase { session.createTemporaryQueue(); Assert.fail("should throw exception here"); } catch (Exception e) { - assertTrue(e.getMessage().contains("User: test-user does not have permission='CREATE_ADDRESS'")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='CREATE_ADDRESS'")); } //Test temp topic @@ -460,7 +470,8 @@ public class SecurityTest extends ActiveMQTestBase { session.createTemporaryTopic(); Assert.fail("should throw exception here"); } catch (Exception e) { - assertTrue(e.getMessage().contains("User: test-user does not have permission='CREATE_ADDRESS'")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='CREATE_ADDRESS'")); } session.close(); @@ -549,7 +560,7 @@ public class SecurityTest extends ActiveMQTestBase { ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLogin"); ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); Set roles = new HashSet<>(); - roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false)); + roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); server.addAddressInfo(new AddressInfo(ADDRESS, RoutingType.ANYCAST)); @@ -564,7 +575,8 @@ public class SecurityTest extends ActiveMQTestBase { session.createQueue(new QueueConfiguration(DURABLE_QUEUE).setAddress(ADDRESS)); Assert.fail("should throw exception here"); } catch (ActiveMQException e) { - assertTrue(e.getMessage().contains("User: first does not have permission='CREATE_DURABLE_QUEUE' for queue durableQueue on address address")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='CREATE_DURABLE_QUEUE' for queue durableQueue on address address")); } // DELETE_DURABLE_QUEUE @@ -572,7 +584,8 @@ public class SecurityTest extends ActiveMQTestBase { session.deleteQueue(DURABLE_QUEUE); Assert.fail("should throw exception here"); } catch (ActiveMQException e) { - assertTrue(e.getMessage().contains("User: first does not have permission='DELETE_DURABLE_QUEUE' for queue durableQueue on address address")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='DELETE_DURABLE_QUEUE' for queue durableQueue on address address")); } // CREATE_NON_DURABLE_QUEUE @@ -580,7 +593,8 @@ public class SecurityTest extends ActiveMQTestBase { session.createQueue(new QueueConfiguration(NON_DURABLE_QUEUE).setAddress(ADDRESS).setDurable(false)); Assert.fail("should throw exception here"); } catch (ActiveMQException e) { - assertTrue(e.getMessage().contains("User: first does not have permission='CREATE_NON_DURABLE_QUEUE' for queue nonDurableQueue on address address")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='CREATE_NON_DURABLE_QUEUE' for queue nonDurableQueue on address address")); } // DELETE_NON_DURABLE_QUEUE @@ -588,7 +602,8 @@ public class SecurityTest extends ActiveMQTestBase { session.deleteQueue(NON_DURABLE_QUEUE); Assert.fail("should throw exception here"); } catch (ActiveMQException e) { - assertTrue(e.getMessage().contains("User: first does not have permission='DELETE_NON_DURABLE_QUEUE' for queue nonDurableQueue on address address")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='DELETE_NON_DURABLE_QUEUE' for queue nonDurableQueue on address address")); } // PRODUCE @@ -597,7 +612,8 @@ public class SecurityTest extends ActiveMQTestBase { producer.send(session.createMessage(true)); Assert.fail("should throw exception here"); } catch (ActiveMQException e) { - assertTrue(e.getMessage().contains("User: first does not have permission='SEND' on address address")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='SEND' on address address")); } // CONSUME @@ -605,7 +621,8 @@ public class SecurityTest extends ActiveMQTestBase { ClientConsumer consumer = session.createConsumer(DURABLE_QUEUE); Assert.fail("should throw exception here"); } catch (ActiveMQException e) { - assertTrue(e.getMessage().contains("User: first does not have permission='CONSUME' for queue durableQueue on address address")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='CONSUME' for queue durableQueue on address address")); } // MANAGE @@ -614,7 +631,8 @@ public class SecurityTest extends ActiveMQTestBase { producer.send(session.createMessage(true)); Assert.fail("should throw exception here"); } catch (ActiveMQException e) { - assertTrue(e.getMessage().contains("User: first does not have permission='MANAGE' on address activemq.management")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='MANAGE' on address activemq.management")); } // BROWSE @@ -622,7 +640,8 @@ public class SecurityTest extends ActiveMQTestBase { ClientConsumer browser = session.createConsumer(DURABLE_QUEUE, true); Assert.fail("should throw exception here"); } catch (ActiveMQException e) { - assertTrue(e.getMessage().contains("User: first does not have permission='BROWSE' for queue durableQueue on address address")); + assertTrue(e.getMessage().contains("User: first")); + assertTrue(e.getMessage().contains("does not have permission='BROWSE' for queue durableQueue on address address")); } } @@ -645,14 +664,14 @@ public class SecurityTest extends ActiveMQTestBase { ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLogin"); ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); Set aRoles = new HashSet<>(); - aRoles.add(new Role(QUEUE_A.toString(), false, true, false, false, false, false, false, false, false, false)); + aRoles.add(new Role(QUEUE_A.toString(), false, true, false, false, false, false, false, false, false, false, false, false)); if (fqqnSyntax) { server.getConfiguration().putSecurityRoles(CompositeAddress.toFullyQualified(ADDRESS, QUEUE_A).toString(), aRoles); } else { server.getConfiguration().putSecurityRoles(ADDRESS.concat(".").concat(QUEUE_A).toString(), aRoles); } Set bRoles = new HashSet<>(); - bRoles.add(new Role(QUEUE_B.toString(), false, true, false, false, false, false, false, false, false, false)); + bRoles.add(new Role(QUEUE_B.toString(), false, true, false, false, false, false, false, false, false, false, false, false)); if (fqqnSyntax) { server.getConfiguration().putSecurityRoles(CompositeAddress.toFullyQualified(ADDRESS, QUEUE_B).toString(), bRoles); } else { @@ -709,11 +728,11 @@ public class SecurityTest extends ActiveMQTestBase { ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); Set aRoles = new HashSet<>(); - aRoles.add(new Role("xyz", true, true, true, true, true, true, true, true, true, true)); + aRoles.add(new Role("xyz", true, true, true, true, true, true, true, true, true, true, false, false)); server.getConfiguration().putSecurityRoles("a.*.b", aRoles); Set bRoles = new HashSet<>(); - bRoles.add(new Role("amq", true, true, true, true, true, true, true, true, true, true)); + bRoles.add(new Role("amq", true, true, true, true, true, true, true, true, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", bRoles); server.start(); @@ -741,11 +760,11 @@ public class SecurityTest extends ActiveMQTestBase { ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); Set aRoles = new HashSet<>(); - aRoles.add(new Role(QUEUE_A.toString(), false, true, true, false, false, false, false, false, true, false)); + aRoles.add(new Role(QUEUE_A.toString(), false, true, true, false, false, false, false, false, true, false, false, false)); server.getConfiguration().putSecurityRoles(CompositeAddress.toFullyQualified(ADDRESS, QUEUE_A).toString(), aRoles); Set bRoles = new HashSet<>(); - bRoles.add(new Role(QUEUE_B.toString(), false, true, true, false, false, false, false, false, true, false)); + bRoles.add(new Role(QUEUE_B.toString(), false, true, true, false, false, false, false, false, true, false, false, false)); server.getConfiguration().putSecurityRoles(CompositeAddress.toFullyQualified(ADDRESS, QUEUE_B).toString(), bRoles); server.start(); @@ -815,7 +834,7 @@ public class SecurityTest extends ActiveMQTestBase { server.getConfiguration().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params)); Set roles = new HashSet<>(); - roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false)); + roles.add(new Role("programmers", false, false, false, false, false, false, false, false, false, false, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); @@ -911,7 +930,7 @@ public class SecurityTest extends ActiveMQTestBase { ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLogin"); ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); Set roles = new HashSet<>(); - roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); @@ -1008,7 +1027,7 @@ public class SecurityTest extends ActiveMQTestBase { server.getConfiguration().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params)); Set roles = new HashSet<>(); - roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); @@ -1092,7 +1111,7 @@ public class SecurityTest extends ActiveMQTestBase { ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("GuestLogin"); ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false)); Set roles = new HashSet<>(); - roles.add(new Role("bar", true, true, true, true, true, true, true, false, true, true)); + roles.add(new Role("bar", true, true, true, true, true, true, true, false, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); @@ -1239,7 +1258,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false); + Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); @@ -1258,7 +1277,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false); + Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); @@ -1283,7 +1302,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, true, true, false, false, false, false, true, true); + Role role = new Role("arole", false, false, true, true, false, false, false, false, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); @@ -1302,7 +1321,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false); + Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); @@ -1329,7 +1348,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, false, false, true, false, false, false, true, false); + Role role = new Role("arole", false, false, false, false, true, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); @@ -1348,7 +1367,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false); + Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); @@ -1373,7 +1392,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, false, false, true, true, false, false, true, true); + Role role = new Role("arole", false, false, false, false, true, true, false, false, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); @@ -1392,7 +1411,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, false, false, true, false, false, false, true, false); + Role role = new Role("arole", false, false, false, false, true, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); @@ -1423,7 +1442,7 @@ public class SecurityTest extends ActiveMQTestBase { securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", true, true, true, false, false, false, false, false, true, false); + Role role = new Role("arole", true, true, true, false, false, false, false, false, true, false, false, false); Set roles = new HashSet<>(); @@ -1455,7 +1474,7 @@ public class SecurityTest extends ActiveMQTestBase { receivedMessage.acknowledge(); - role = new Role("arole", false, false, true, false, false, false, false, false, false, false); + role = new Role("arole", false, false, true, false, false, false, false, false, false, false, false, false); roles = new HashSet<>(); @@ -1482,7 +1501,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false); + Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); @@ -1510,7 +1529,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false); + Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); @@ -1536,8 +1555,8 @@ public class SecurityTest extends ActiveMQTestBase { securityManager.getConfiguration().addUser("guest", "guest"); securityManager.getConfiguration().addRole("guest", "guest"); securityManager.getConfiguration().setDefaultUser("guest"); - Role role = new Role("arole", false, true, false, false, false, false, false, false, false, false); - Role sendRole = new Role("guest", true, false, true, false, false, false, false, false, true, false); + Role role = new Role("arole", false, true, false, false, false, false, false, false, false, false, false, false); + Role sendRole = new Role("guest", true, false, true, false, false, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(sendRole); roles.add(role); @@ -1564,8 +1583,8 @@ public class SecurityTest extends ActiveMQTestBase { securityManager.getConfiguration().addUser("guest", "guest"); securityManager.getConfiguration().addRole("guest", "guest"); securityManager.getConfiguration().setDefaultUser("guest"); - Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false); - Role sendRole = new Role("guest", true, false, true, false, false, false, false, false, true, false); + Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false, false, false); + Role sendRole = new Role("guest", true, false, true, false, false, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(sendRole); roles.add(role); @@ -1599,9 +1618,9 @@ public class SecurityTest extends ActiveMQTestBase { securityManager.getConfiguration().addUser("guest", "guest"); securityManager.getConfiguration().addRole("guest", "guest"); securityManager.getConfiguration().setDefaultUser("guest"); - Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false); - Role sendRole = new Role("guest", true, false, true, false, false, false, false, false, true, false); - Role receiveRole = new Role("receiver", false, true, false, false, false, false, false, false, false, false); + Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false, false, false); + Role sendRole = new Role("guest", true, false, true, false, false, false, false, false, true, false, false, false); + Role receiveRole = new Role("receiver", false, true, false, false, false, false, false, false, false, false, false, false); Set roles = new HashSet<>(); roles.add(sendRole); roles.add(role); @@ -1651,9 +1670,9 @@ public class SecurityTest extends ActiveMQTestBase { securityManager.getConfiguration().addUser("guest", "guest"); securityManager.getConfiguration().addRole("guest", "guest"); securityManager.getConfiguration().setDefaultUser("guest"); - Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false); - Role sendRole = new Role("guest", true, false, true, false, false, false, false, false, true, false); - Role receiveRole = new Role("receiver", false, true, false, false, false, false, false, false, false, false); + Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false, false, false); + Role sendRole = new Role("guest", true, false, true, false, false, false, false, false, true, false, false, false); + Role receiveRole = new Role("receiver", false, true, false, false, false, false, false, false, false, false, false, false); Set roles = new HashSet<>(); roles.add(sendRole); roles.add(role); @@ -1707,9 +1726,9 @@ public class SecurityTest extends ActiveMQTestBase { securityManager.getConfiguration().addUser("guest", "guest"); securityManager.getConfiguration().addRole("guest", "guest"); securityManager.getConfiguration().setDefaultUser("guest"); - Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false); - Role sendRole = new Role("guest", true, false, true, false, false, false, false, false, true, false); - Role receiveRole = new Role("receiver", false, true, false, false, false, false, false, false, false, false); + Role role = new Role("arole", false, false, false, false, false, false, false, false, false, false, false, false); + Role sendRole = new Role("guest", true, false, true, false, false, false, false, false, true, false, false, false); + Role receiveRole = new Role("receiver", false, true, false, false, false, false, false, false, false, false, false, false); Set roles = new HashSet<>(); roles.add(sendRole); roles.add(role); @@ -1802,7 +1821,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, false, false, false, false, true, false, false, false); + Role role = new Role("arole", false, false, false, false, false, false, true, false, false, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(configuration.getManagementAddress().toString(), roles); @@ -1823,7 +1842,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false); + Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(configuration.getManagementAddress().toString(), roles); @@ -1852,7 +1871,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false); + Role role = new Role("arole", false, false, true, false, false, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(configuration.getManagementAddress().toString(), roles); @@ -1888,23 +1907,23 @@ public class SecurityTest extends ActiveMQTestBase { securityManager.getConfiguration().addRole("frank", "user"); securityManager.getConfiguration().addRole("sam", "news-user"); securityManager.getConfiguration().addRole("sam", "user"); - Role all = new Role("all", true, true, true, true, true, true, true, true, true, true); + Role all = new Role("all", true, true, true, true, true, true, true, true, true, true, false, false); HierarchicalRepository> repository = server.getSecurityRepository(); Set add = new HashSet<>(); - add.add(new Role("user", true, true, true, true, true, true, false, true, true, true)); + add.add(new Role("user", true, true, true, true, true, true, false, true, true, true, false, false)); add.add(all); repository.addMatch("#", add); Set add1 = new HashSet<>(); add1.add(all); - add1.add(new Role("user", false, false, true, true, true, true, false, true, true, true)); - add1.add(new Role("europe-user", true, false, false, false, false, false, false, true, true, true)); - add1.add(new Role("news-user", false, true, false, false, false, false, false, true, true, true)); + add1.add(new Role("user", false, false, true, true, true, true, false, true, true, true, false, false)); + add1.add(new Role("europe-user", true, false, false, false, false, false, false, true, true, true, false, false)); + add1.add(new Role("news-user", false, true, false, false, false, false, false, true, true, true, false, false)); repository.addMatch("news.europe.#", add1); Set add2 = new HashSet<>(); add2.add(all); - add2.add(new Role("user", false, false, true, true, true, true, false, true, true, true)); - add2.add(new Role("us-user", true, false, false, false, false, false, false, true, true, true)); - add2.add(new Role("news-user", false, true, false, false, false, false, false, true, true, true)); + add2.add(new Role("user", false, false, true, true, true, true, false, true, true, true, false, false)); + add2.add(new Role("us-user", true, false, false, false, false, false, false, true, true, true, false, false)); + add2.add(new Role("news-user", false, true, false, false, false, false, false, true, true, true, false, false)); repository.addMatch("news.us.#", add2); ClientSession billConnection = null; ClientSession andrewConnection = null; @@ -2017,23 +2036,23 @@ public class SecurityTest extends ActiveMQTestBase { securityManager.getConfiguration().addRole("frank", "user"); securityManager.getConfiguration().addRole("sam", "news-user"); securityManager.getConfiguration().addRole("sam", "user"); - Role all = new Role("all", true, true, true, true, true, true, true, true, true, true); + Role all = new Role("all", true, true, true, true, true, true, true, true, true, true, false, false); HierarchicalRepository> repository = server.getSecurityRepository(); Set add = new HashSet<>(); - add.add(new Role("user", true, true, true, true, true, true, false, true, true, true)); + add.add(new Role("user", true, true, true, true, true, true, false, true, true, true, false, false)); add.add(all); repository.addMatch("#", add); Set add1 = new HashSet<>(); add1.add(all); - add1.add(new Role("user", false, false, true, true, true, true, false, true, true, true)); - add1.add(new Role("europe-user", true, false, false, false, false, false, false, true, true, true)); - add1.add(new Role("news-user", false, true, false, false, false, false, false, true, true, true)); + add1.add(new Role("user", false, false, true, true, true, true, false, true, true, true, false, false)); + add1.add(new Role("europe-user", true, false, false, false, false, false, false, true, true, true, false, false)); + add1.add(new Role("news-user", false, true, false, false, false, false, false, true, true, true, false, false)); repository.addMatch("news.europe.#", add1); Set add2 = new HashSet<>(); add2.add(all); - add2.add(new Role("user", false, false, true, true, true, true, false, true, true, true)); - add2.add(new Role("us-user", true, false, false, false, false, false, false, true, true, true)); - add2.add(new Role("news-user", false, true, false, false, false, false, false, true, true, true)); + add2.add(new Role("user", false, false, true, true, true, true, false, true, true, true, false, false)); + add2.add(new Role("us-user", true, false, false, false, false, false, false, true, true, true, false, false)); + add2.add(new Role("news-user", false, true, false, false, false, false, false, true, true, true, false, false)); repository.addMatch("news.us.#", add2); ClientSession billConnection = null; ClientSession andrewConnection = null; @@ -2594,7 +2613,7 @@ public class SecurityTest extends ActiveMQTestBase { HierarchicalRepository> securityRepository = server.getSecurityRepository(); ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("auser", "pass"); - Role role = new Role("arole", true, false, false, false, false, false, false, false, true, false); + Role role = new Role("arole", true, false, false, false, false, false, false, false, true, false, false, false); Set roles = new HashSet<>(); roles.add(role); securityRepository.addMatch(SecurityTest.addressA, roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ResourceLimitTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ResourceLimitTest.java index cb5766e26b..4aa24e0241 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ResourceLimitTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ResourceLimitTest.java @@ -62,7 +62,7 @@ public class ResourceLimitTest extends ActiveMQTestBase { ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager(); securityManager.getConfiguration().addUser("myUser", "password"); securityManager.getConfiguration().addRole("myUser", "arole"); - Role role = new Role("arole", false, false, false, false, true, true, false, true, true, true); + Role role = new Role("arole", false, false, false, false, true, true, false, true, true, true, false, false); Set roles = new HashSet<>(); roles.add(role); server.getSecurityRepository().addMatch("#", roles); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ResourceLimitTestWithCerts.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ResourceLimitTestWithCerts.java index 14a383c9e5..9d7b8d7495 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ResourceLimitTestWithCerts.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ResourceLimitTestWithCerts.java @@ -81,7 +81,7 @@ public class ResourceLimitTestWithCerts extends ActiveMQTestBase { server.getConfiguration().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params)); Set roles = new HashSet<>(); - roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("programmers", true, true, true, true, true, true, true, true, true, true, false, false)); server.getConfiguration().putSecurityRoles("#", roles); server.start(); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/DualAuthenticationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/DualAuthenticationTest.java index d87b20a80b..9070554c92 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/DualAuthenticationTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/DualAuthenticationTest.java @@ -129,8 +129,8 @@ public class DualAuthenticationTest extends ActiveMQTestBase { server = addServer(ActiveMQServers.newActiveMQServer(config, ManagementFactory.getPlatformMBeanServer(), securityManager, false)); HierarchicalRepository> securityRepository = server.getSecurityRepository(); - Role sendRole = new Role("producers", true, false, true, false, true, false, false, false, true, false); - Role receiveRole = new Role("consumers", false, true, false, false, false, false, false, false, false, false); + Role sendRole = new Role("producers", true, false, true, false, true, false, false, false, true, false, false, false); + Role receiveRole = new Role("consumers", false, true, false, false, false, false, false, false, false, false, false, false); Set roles = new HashSet<>(); roles.add(sendRole); roles.add(receiveRole); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/SslPEMTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/SslPEMTest.java index d5286b8c30..642279df5d 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/SslPEMTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/SslPEMTest.java @@ -136,8 +136,8 @@ public class SslPEMTest extends ActiveMQTestBase { ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(config, ManagementFactory.getPlatformMBeanServer(), securityManager, false)); HierarchicalRepository> securityRepository = server.getSecurityRepository(); - Role sendRole = new Role("producers", true, false, true, false, true, false, false, false, true, false); - Role receiveRole = new Role("consumers", false, true, false, false, false, false, false, false, false, false); + Role sendRole = new Role("producers", true, false, true, false, true, false, false, false, true, false, false, false); + Role receiveRole = new Role("consumers", false, true, false, false, false, false, false, false, false, false, false, false); Set roles = new HashSet<>(); roles.add(sendRole); roles.add(receiveRole); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompAuditLoggingTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompAuditLoggingTest.java index fdc390ae08..2ea276fad3 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompAuditLoggingTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompAuditLoggingTest.java @@ -59,7 +59,7 @@ public class StompAuditLoggingTest extends StompTestBase { securityManager.getConfiguration().addUser(user, pass); securityManager.getConfiguration().addRole(user, role); - server.getConfiguration().getSecurityRoles().put("#", new HashSet<>(Set.of(new Role(role, false, false, false, false, false, false, false, false, false, false)))); + server.getConfiguration().getSecurityRoles().put("#", new HashSet<>(Set.of(new Role(role, false, false, false, false, false, false, false, false, false, false, false, false)))); return server; } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompTestBase.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompTestBase.java index 80e28e974f..045e94cc6e 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompTestBase.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompTestBase.java @@ -214,7 +214,7 @@ public abstract class StompTestBase extends ActiveMQTestBase { final String role = "testRole"; securityManager.getConfiguration().addRole(defUser, role); - config.getSecurityRoles().put("#", new HashSet(Set.of(new Role(role, true, true, true, true, true, true, true, true, true, true)))); + config.getSecurityRoles().put("#", new HashSet(Set.of(new Role(role, true, true, true, true, true, true, true, true, true, true, false, false)))); } return activeMQServer; diff --git a/tests/integration-tests/src/test/resources/reload-security-settings-updated.xml b/tests/integration-tests/src/test/resources/reload-security-settings-updated.xml index 47d94b16d3..14e82c9d1c 100644 --- a/tests/integration-tests/src/test/resources/reload-security-settings-updated.xml +++ b/tests/integration-tests/src/test/resources/reload-security-settings-updated.xml @@ -56,6 +56,8 @@ under the License. + + diff --git a/tests/smoke-tests/src/main/resources/servers/jmx-rbac-broker-security/broker.xml b/tests/smoke-tests/src/main/resources/servers/jmx-rbac-broker-security/broker.xml new file mode 100644 index 0000000000..39671a393a --- /dev/null +++ b/tests/smoke-tests/src/main/resources/servers/jmx-rbac-broker-security/broker.xml @@ -0,0 +1,148 @@ + + + + + + + + 0.0.0.0 + + true + + ./data/paging + + ./data/bindings + + ./data/journal + + ./data/large-messages + + true + + 2 + + 10 + + 4096 + + 10M + + 5000 + + 90 + + + + tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;amqpMinLargeMessageSize=102400;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;amqpDuplicateDetection=true;supportAdvisory=false;suppressInternalManagementObjects=false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DLQ + ExpiryQueue + 0 + + -1 + 10 + PAGE + true + true + + + + DLQ + ExpiryQueue + 0 + + 10 + PAGE + true + true + false + false + + + 10M + + + + -1 + -1 + + + + -1 + 20M + + + + -1 + -1 + + + + +

+ + + +
+
+ + + +
+ + + + + diff --git a/tests/smoke-tests/src/main/resources/servers/jmx-rbac-broker-security/management.xml b/tests/smoke-tests/src/main/resources/servers/jmx-rbac-broker-security/management.xml new file mode 100644 index 0000000000..4a5ac25a21 --- /dev/null +++ b/tests/smoke-tests/src/main/resources/servers/jmx-rbac-broker-security/management.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACBrokerSecurityTest.java b/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACBrokerSecurityTest.java new file mode 100644 index 0000000000..0b9a0b54fb --- /dev/null +++ b/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACBrokerSecurityTest.java @@ -0,0 +1,224 @@ +/* + * 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.activemq.artemis.tests.smoke.jmxrbac; + +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerInvocationHandler; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import java.io.File; +import java.util.Collections; + +import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; +import org.apache.activemq.artemis.api.core.Message; +import org.apache.activemq.artemis.api.core.RoutingType; +import org.apache.activemq.artemis.api.core.SimpleString; +import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl; +import org.apache.activemq.artemis.api.core.management.AddressControl; +import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder; +import org.apache.activemq.artemis.tests.smoke.common.SmokeTestBase; +import org.apache.activemq.artemis.util.ServerUtil; +import org.apache.activemq.artemis.utils.cli.helper.HelperCreate; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +// clone of JmxRBACTest with jmx security settings in broker.xml and new guard that delegates to security settings +// configured via -Djavax.management.builder.initial=org.apache.activemq.artemis.core.server.management.ArtemisRbacMBeanServerBuilder +public class JmxRBACBrokerSecurityTest extends SmokeTestBase { + + private static final String JMX_SERVER_HOSTNAME = "localhost"; + private static final int JMX_SERVER_PORT = 10099; + + public static final String BROKER_NAME = "0.0.0.0"; + + public static final String SERVER_NAME_0 = "jmx-rbac-broker-security"; + + public static final String SERVER_ADMIN = "admin"; + public static final String SERVER_USER = "user"; + + public static final String ADDRESS_TEST = "TEST"; + + @BeforeClass + public static void createServers() throws Exception { + + File server0Location = getFileServerLocation(SERVER_NAME_0); + deleteDirectory(server0Location); + + { + HelperCreate cliCreateServer = new HelperCreate(); + cliCreateServer.setRole("amq").setUser("admin").setPassword("admin").setAllowAnonymous(false).setNoWeb(true).setArtemisInstance(server0Location). + setConfiguration("./src/main/resources/servers/jmx-rbac-broker-security").setArgs("--java-options", "-Djava.rmi.server.hostname=localhost -Djavax.management.builder.initial=org.apache.activemq.artemis.core.server.management.ArtemisRbacMBeanServerBuilder"); + cliCreateServer.createServer(); + } + } + + + @Before + public void before() throws Exception { + cleanupData(SERVER_NAME_0); + disableCheckThread(); + startServer(SERVER_NAME_0, 0, 0); + ServerUtil.waitForServerToStart(0, SERVER_ADMIN, SERVER_ADMIN, 30000); + } + + @Test + public void testManagementRoleAccess() throws Exception { + + // I don't specify both ports here manually on purpose. See actual RMI registry connection port extraction below. + String urlString = "service:jmx:rmi:///jndi/rmi://" + JMX_SERVER_HOSTNAME + ":" + JMX_SERVER_PORT + "/jmxrmi"; + + JMXServiceURL url = new JMXServiceURL(urlString); + JMXConnector jmxConnector; + + try { + //Connect using the admin. + jmxConnector = JMXConnectorFactory.connect(url, Collections.singletonMap( + "jmx.remote.credentials", new String[] {SERVER_ADMIN, SERVER_ADMIN})); + System.out.println("Successfully connected to: " + urlString); + } catch (Exception e) { + jmxConnector = null; + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + + try { + //Create an user. + MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); + ObjectNameBuilder objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), BROKER_NAME, true); + ActiveMQServerControl activeMQServerControl = MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, objectNameBuilder.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); + ObjectName memoryObjectName = new ObjectName("java.lang:type=Memory"); + + try { + activeMQServerControl.removeUser(SERVER_USER); + } catch (Exception ignore) { + } + activeMQServerControl.addUser(SERVER_USER, SERVER_USER, "amq-user", true); + + activeMQServerControl.getVersion(); + + try { + mBeanServerConnection.invoke(memoryObjectName, "gc", null, null); + Assert.fail(SERVER_ADMIN + " should not access to " + memoryObjectName); + } catch (Exception e) { + Assert.assertEquals(SecurityException.class, e.getClass()); + } + } finally { + jmxConnector.close(); + } + + try { + //Connect using an user. + jmxConnector = JMXConnectorFactory.connect(url, Collections.singletonMap( + "jmx.remote.credentials", new String[] {SERVER_USER, SERVER_USER})); + System.out.println("Successfully connected to: " + urlString); + } catch (Exception e) { + jmxConnector = null; + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + + + try { + MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); + ObjectNameBuilder objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), BROKER_NAME, true); + ActiveMQServerControl activeMQServerControl = MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, objectNameBuilder.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); + ObjectName memoryObjectName = new ObjectName("java.lang:type=Memory"); + + mBeanServerConnection.invoke(memoryObjectName, "gc", null, null); + + try { + activeMQServerControl.getVersion(); + Assert.fail(SERVER_USER + " should not access to " + objectNameBuilder.getActiveMQServerObjectName()); + } catch (Exception e) { + Assert.assertEquals(SecurityException.class, e.getClass()); + } + } finally { + jmxConnector.close(); + } + } + + @Test + public void testSendMessageWithoutUserAndPassword() throws Exception { + + // I don't specify both ports here manually on purpose. See actual RMI registry connection port extraction below. + String urlString = "service:jmx:rmi:///jndi/rmi://" + JMX_SERVER_HOSTNAME + ":" + JMX_SERVER_PORT + "/jmxrmi"; + + JMXServiceURL url = new JMXServiceURL(urlString); + JMXConnector jmxConnector; + + try { + //Connect using the admin. + jmxConnector = JMXConnectorFactory.connect(url, Collections.singletonMap( + "jmx.remote.credentials", new String[] {SERVER_ADMIN, SERVER_ADMIN})); + System.out.println("Successfully connected to: " + urlString); + } catch (Exception e) { + jmxConnector = null; + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + + try { + MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); + ObjectNameBuilder objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), BROKER_NAME, true); + ActiveMQServerControl activeMQServerControl = MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, objectNameBuilder.getActiveMQServerObjectName(), ActiveMQServerControl.class, false); + + activeMQServerControl.createAddress(ADDRESS_TEST, RoutingType.MULTICAST.name()); + AddressControl testAddressControl = MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, objectNameBuilder.getAddressObjectName(SimpleString.toSimpleString(ADDRESS_TEST)), AddressControl.class, false); + + testAddressControl.sendMessage(null, Message.TEXT_TYPE, ADDRESS_TEST, true, null, null); + + + try { + activeMQServerControl.removeUser(SERVER_USER); + } catch (Exception ignore) { + } + activeMQServerControl.addUser(SERVER_USER, SERVER_USER, "amq-user", true); + } finally { + jmxConnector.close(); + } + + try { + //Connect using an user. + jmxConnector = JMXConnectorFactory.connect(url, Collections.singletonMap( + "jmx.remote.credentials", new String[] {SERVER_USER, SERVER_USER})); + System.out.println("Successfully connected to: " + urlString); + } catch (Exception e) { + jmxConnector = null; + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + + try { + MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); + ObjectNameBuilder objectNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), BROKER_NAME, true); + AddressControl testAddressControl = MBeanServerInvocationHandler.newProxyInstance(mBeanServerConnection, objectNameBuilder.getAddressObjectName(SimpleString.toSimpleString("TEST")), AddressControl.class, false); + + try { + testAddressControl.sendMessage(null, Message.TEXT_TYPE, ADDRESS_TEST, true, null, null); + Assert.fail(SERVER_USER + " should not have permissions to send a message to the address " + ADDRESS_TEST); + } catch (Exception e) { + Assert.assertEquals(SecurityException.class, e.getClass()); + } + } finally { + jmxConnector.close(); + } + } +} diff --git a/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACTest.java b/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACTest.java index 573c63bf62..94eca1018b 100644 --- a/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACTest.java +++ b/tests/smoke-tests/src/test/java/org/apache/activemq/artemis/tests/smoke/jmxrbac/JmxRBACTest.java @@ -81,8 +81,6 @@ public class JmxRBACTest extends SmokeTestBase { @Test public void testManagementRoleAccess() throws Exception { - // Without this, the RMI server would bind to the default interface IP (the user's local IP mostly) - System.setProperty("java.rmi.server.hostname", JMX_SERVER_HOSTNAME); // I don't specify both ports here manually on purpose. See actual RMI registry connection port extraction below. String urlString = "service:jmx:rmi:///jndi/rmi://" + JMX_SERVER_HOSTNAME + ":" + JMX_SERVER_PORT + "/jmxrmi"; @@ -159,8 +157,6 @@ public class JmxRBACTest extends SmokeTestBase { @Test public void testSendMessageWithoutUserAndPassword() throws Exception { - // Without this, the RMI server would bind to the default interface IP (the user's local IP mostly) - System.setProperty("java.rmi.server.hostname", JMX_SERVER_HOSTNAME); // I don't specify both ports here manually on purpose. See actual RMI registry connection port extraction below. String urlString = "service:jmx:rmi:///jndi/rmi://" + JMX_SERVER_HOSTNAME + ":" + JMX_SERVER_PORT + "/jmxrmi"; diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/security/impl/ActiveMQSecurityManagerImplTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/security/impl/ActiveMQSecurityManagerImplTest.java index eccdb5f5d5..c0b9d12f61 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/security/impl/ActiveMQSecurityManagerImplTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/security/impl/ActiveMQSecurityManagerImplTest.java @@ -59,22 +59,22 @@ public class ActiveMQSecurityManagerImplTest extends ActiveMQTestBase { Assert.assertTrue(securityManager.validateUser("guest", "password")); Assert.assertFalse(securityManager.validateUser(null, "wrongpass")); HashSet roles = new HashSet<>(); - roles.add(new Role("guest", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("guest", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertTrue(securityManager.validateUserAndRole(null, null, roles, CheckType.CREATE_DURABLE_QUEUE)); Assert.assertTrue(securityManager.validateUserAndRole(null, null, roles, CheckType.SEND)); Assert.assertTrue(securityManager.validateUserAndRole(null, null, roles, CheckType.CONSUME)); roles = new HashSet<>(); - roles.add(new Role("guest", true, true, false, true, true, true, true, true, true, true)); + roles.add(new Role("guest", true, true, false, true, true, true, true, true, true, true, false, false)); Assert.assertFalse(securityManager.validateUserAndRole(null, null, roles, CheckType.CREATE_DURABLE_QUEUE)); Assert.assertTrue(securityManager.validateUserAndRole(null, null, roles, CheckType.SEND)); Assert.assertTrue(securityManager.validateUserAndRole(null, null, roles, CheckType.CONSUME)); roles = new HashSet<>(); - roles.add(new Role("guest", true, false, false, true, true, true, true, true, true, true)); + roles.add(new Role("guest", true, false, false, true, true, true, true, true, true, true, false, false)); Assert.assertFalse(securityManager.validateUserAndRole(null, null, roles, CheckType.CREATE_DURABLE_QUEUE)); Assert.assertTrue(securityManager.validateUserAndRole(null, null, roles, CheckType.SEND)); Assert.assertFalse(securityManager.validateUserAndRole(null, null, roles, CheckType.CONSUME)); roles = new HashSet<>(); - roles.add(new Role("guest", false, false, false, true, true, true, true, true, true, true)); + roles.add(new Role("guest", false, false, false, true, true, true, true, true, true, true, false, false)); Assert.assertFalse(securityManager.validateUserAndRole(null, null, roles, CheckType.CREATE_DURABLE_QUEUE)); Assert.assertFalse(securityManager.validateUserAndRole(null, null, roles, CheckType.SEND)); Assert.assertFalse(securityManager.validateUserAndRole(null, null, roles, CheckType.CONSUME)); @@ -124,19 +124,19 @@ public class ActiveMQSecurityManagerImplTest extends ActiveMQTestBase { securityManager.getConfiguration().addRole("newuser1", "role3"); securityManager.getConfiguration().addRole("newuser1", "role4"); HashSet roles = new HashSet<>(); - roles.add(new Role("role1", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("role1", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertTrue(securityManager.validateUserAndRole("newuser1", "newpassword1", roles, CheckType.SEND)); roles = new HashSet<>(); - roles.add(new Role("role2", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("role2", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertTrue(securityManager.validateUserAndRole("newuser1", "newpassword1", roles, CheckType.SEND)); roles = new HashSet<>(); - roles.add(new Role("role3", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("role3", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertTrue(securityManager.validateUserAndRole("newuser1", "newpassword1", roles, CheckType.SEND)); roles = new HashSet<>(); - roles.add(new Role("role4", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("role4", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertTrue(securityManager.validateUserAndRole("newuser1", "newpassword1", roles, CheckType.SEND)); roles = new HashSet<>(); - roles.add(new Role("role5", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("role5", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertFalse(securityManager.validateUserAndRole("newuser1", "newpassword1", roles, CheckType.SEND)); } @@ -150,19 +150,19 @@ public class ActiveMQSecurityManagerImplTest extends ActiveMQTestBase { securityManager.getConfiguration().removeRole("newuser1", "role2"); securityManager.getConfiguration().removeRole("newuser1", "role4"); HashSet roles = new HashSet<>(); - roles.add(new Role("role1", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("role1", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertTrue(securityManager.validateUserAndRole("newuser1", "newpassword1", roles, CheckType.SEND)); roles = new HashSet<>(); - roles.add(new Role("role2", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("role2", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertFalse(securityManager.validateUserAndRole("newuser1", "newpassword1", roles, CheckType.SEND)); roles = new HashSet<>(); - roles.add(new Role("role3", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("role3", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertTrue(securityManager.validateUserAndRole("newuser1", "newpassword1", roles, CheckType.SEND)); roles = new HashSet<>(); - roles.add(new Role("role4", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("role4", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertFalse(securityManager.validateUserAndRole("newuser1", "newpassword1", roles, CheckType.SEND)); roles = new HashSet<>(); - roles.add(new Role("role5", true, true, true, true, true, true, true, true, true, true)); + roles.add(new Role("role5", true, true, true, true, true, true, true, true, true, true, false, false)); Assert.assertFalse(securityManager.validateUserAndRole("newuser1", "newpassword1", roles, CheckType.SEND)); } }