in platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/RBACDecorator.java [100:166]
public void decorate(Map<String, Object> result) throws Exception {
try {
ServiceReference<ConfigurationAdmin> cmRef = bundleContext.getServiceReference(ConfigurationAdmin.class);
ServiceReference<JMXSecurityMBean> jmxSecRef = bundleContext.getServiceReference(JMXSecurityMBean.class);
if (cmRef == null || jmxSecRef == null) {
return;
}
ConfigurationAdmin configAdmin = bundleContext.getService(cmRef);
JMXSecurityMBean jmxSec = bundleContext.getService(jmxSecRef);
if (configAdmin == null || jmxSec == null) {
return;
}
// 1. each pair of MBean/operation has to be marked with RBAC flag (can/can't invoke)
// 2. the information is provided by org.apache.karaf.management.JMXSecurityMBean.canInvoke(java.util.Map)
// 3. we'll peek into available configadmin jmx.acl* configs, to see which MBeans/operations have to
// be examined and which will produce same results
// 4. only then we'll prepare Map as parameter for canInvoke()
Configuration[] configurations = configAdmin.listConfigurations("(service.pid=jmx.acl*)");
if (configurations == null) {
return;
}
List<String> allJmxAclPids = Arrays.stream(configurations)
.map(Configuration::getPid)
.collect(Collectors.toCollection(LinkedList::new));
if (allJmxAclPids.isEmpty()) {
return;
}
Map<String, Map<String, Object>> domains = (Map<String, Map<String, Object>>) result.get("domains");
// cache contains MBeanInfos for different MBeans/ObjectNames
Map<String, Map<String, Object>> cache = (Map<String, Map<String, Object>>) result.get("cache");
// new cache will contain MBeanInfos + RBAC info
Map<String, Map<String, Object>> rbacCache = new HashMap<>();
// the fact that some MBeans share JSON MBeanInfo doesn't mean that they can share RBAC info
// - each MBean's name may have RBAC information configured in different PIDs.
// when iterating through all repeating MBeans that share MBeanInfo (that doesn't have RBAC info
// yet), we have to decide if it'll use shared info after RBAC check or will switch to dedicated
// info. we have to be careful not to end with most MBeans *not* sharing MBeanInfo (in case if
// somehow the shared info will be "special case" from RBAC point of view)
Map<String, List<String>> queryForMBeans = new HashMap<>();
Map<String, List<String>> queryForMBeanOperations = new HashMap<>();
constructQueries(allJmxAclPids, domains, cache, rbacCache, queryForMBeans, queryForMBeanOperations);
// RBAC per MBeans (can invoke *any* operation or attribute?)
doQueryForMBeans(jmxSec, domains, rbacCache, queryForMBeans);
// RBAC per { MBean,operation } (can invoke status for each operation)
doQueryForMBeanOperations(jmxSec, domains, rbacCache, queryForMBeanOperations);
result.remove("cache");
result.put("cache", rbacCache);
if (verify) {
verify(result);
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
// simply do not decorate
}
}