Skip to content

Commit

Permalink
ARTEMIS-4582 - view and edit permissions, mops. security-settings for…
Browse files Browse the repository at this point in the history
… rbac on management apis
  • Loading branch information
gtully committed Mar 15, 2024
1 parent 5766225 commit 2e17a4a
Show file tree
Hide file tree
Showing 116 changed files with 3,843 additions and 456 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ private void sendMessage(List<String> queues, Message message) throws Exception
}

for (String queue : queues) {
long queueID;
long queueID = -1;

if (queueIDs.containsKey(queue)) {
queueID = queueIDs.get(queue);
Expand All @@ -337,17 +337,27 @@ private void sendMessage(List<String> queues, Message message) throws Exception
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(", ");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,12 @@ public static String getDefaultHapolicyBackupStrategy() {

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.
*/
Expand Down Expand Up @@ -1900,4 +1906,16 @@ public static long getDefaultEmbeddedWebServerRestartTimeout() {
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1406,6 +1406,21 @@ void addSecuritySettings(@Parameter(desc = "an address match", name = "addressMa
@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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,12 @@ private String getActiveMQServerName() {
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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -79,7 +84,7 @@ public Role(final String name,
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);
}

Expand All @@ -95,9 +100,10 @@ public Role(final String name,
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,
Expand All @@ -109,6 +115,22 @@ public Role(final String name,
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,
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,
final boolean view,
final boolean edit) {
if (name == null) {
throw new NullPointerException("name is null");
}
Expand All @@ -123,6 +145,8 @@ public Role(final String name,
this.deleteNonDurableQueue = deleteNonDurableQueue;
this.manage = manage;
this.browse = browse;
this.view = view;
this.edit = edit;
}

public String getName() {
Expand Down Expand Up @@ -247,7 +271,12 @@ public String toString() {
if (browse) {
stringReturn.append(" browse ");
}

if (view) {
stringReturn.append(" view ");
}
if (edit) {
stringReturn.append(" edit ");
}
stringReturn.append("]}");

return stringReturn.toString();
Expand Down Expand Up @@ -297,6 +326,12 @@ public boolean equals(final Object o) {
if (!name.equals(role.name)) {
return false;
}
if (view != role.view) {
return false;
}
if (edit != role.edit) {
return false;
}

return true;
}
Expand All @@ -315,6 +350,8 @@ public int hashCode() {
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;
}

Expand All @@ -329,5 +366,23 @@ public void merge(Role other) {
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public static Set<Role> createSecurity(String sendRoles,

Set<Role> 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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 8 additions & 1 deletion artemis-hawtio/artemis-console/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,19 @@
</execution>
</executions>
<configuration>
<file>${project.build.directory}/${project.build.finalName}/index.html</file>
<includes>
<include>${project.build.directory}/${project.build.finalName}/index.html</include>
<include>${project.build.directory}/${project.build.finalName}/WEB-INF/web.xml</include>
</includes>
<replacements>
<replacement>
<token>&lt;title&gt;.*&lt;/title&gt;</token>
<value>&lt;title&gt;${project.name}&lt;/title&gt;</value>
</replacement>
<replacement>
<token>&lt;load-on-startup>1&lt;/load-on-startup></token>
<value>&lt;load-on-startup>-1&lt;/load-on-startup></value>
</replacement>
</replacements>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class OsgiBroker {
private String name;
private String configurationUrl;
private String rolePrincipalClass;
private String userPrincipalClass;
private Map<String, ActiveMQComponent> components;
private Map<String, ServiceRegistration<?>> registrations;
private ServiceTracker tracker;
Expand All @@ -69,11 +70,16 @@ public void activate(ComponentContext cctx) throws Exception {
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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1496,4 +1496,17 @@ default String resolvePropertiesSources(String propertiesFileUrl) {
Configuration setLargeMessageSync(boolean largeMessageSync);

boolean isLargeMessageSync();

String getViewPermissionMethodMatchPattern();

void setViewPermissionMethodMatchPattern(String permissionMatchPattern);

boolean isManagementMessageRbac();

void setManagementMessageRbac(boolean val);

String getManagementRbacPrefix();

void setManagementRbacPrefix(String prefix);

}
Original file line number Diff line number Diff line change
Expand Up @@ -434,14 +434,19 @@ 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.
*/
private File artemisInstance;
private transient JsonObject jsonStatus = JsonLoader.createObjectBuilder().build();
private transient Checksum transientChecksum = null;


private JsonObject getJsonStatus() {
if (jsonStatus == null) {
jsonStatus = JsonLoader.createObjectBuilder().build();
Expand Down Expand Up @@ -3308,6 +3313,36 @@ public boolean isLargeMessageSync() {
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 {
Expand Down
Loading

0 comments on commit 2e17a4a

Please sign in to comment.