public void decorate()

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