/* * 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.karaf.management.internal; import java.io.IOException; import java.security.AccessControlContext; import java.security.AccessController; import java.security.Principal; import java.util.ArrayList; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.security.auth.Subject; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; /** * <p>Class to optimize ConfigAdmin access with the lifecycle of single * {@link org.apache.karaf.management.JMXSecurityMBean#canInvoke(Map) bulk query invocation}. This prevents countless * {@link org.osgi.service.cm.ConfigurationAdmin#listConfigurations(String) listings of ConfigAdmin configurations} * for each checked MBean/method.</p> * <p>Access to this object doesn't have to be synchronized, as it is passed down the <code>canInvoke</code> chain.</p> */ public class BulkRequestContext { private List<String> allPids = new ArrayList<String>(); private List<Dictionary<String, Object>> whiteListProperties = new ArrayList<Dictionary<String, Object>>(); private ConfigurationAdmin configAdmin; // if there's AccessControlContext or subject, we can fail fast private boolean anonymous = false; // otherwise we can cache current subject's principals for faster access private Set<Principal> principals = new HashSet<>(); // cache with lifecycle bound to BulkRequestContext instance private Map<String, Dictionary<String, Object>> cachedConfigurations = new HashMap<String, Dictionary<String, Object>>(); private BulkRequestContext() {} public static BulkRequestContext newContext(ConfigurationAdmin configAdmin) throws IOException { BulkRequestContext context = new BulkRequestContext(); context.configAdmin = configAdmin; try { // check JAAS subject here AccessControlContext acc = AccessController.getContext(); if (acc == null) { context.anonymous = true; } else { Subject subject = Subject.getSubject(acc); if (subject == null) { context.anonymous = true; } else { context.principals.addAll(subject.getPrincipals()); } } // list available ACL configs - valid for this instance only for (Configuration config : configAdmin.listConfigurations("(service.pid=jmx.acl*)")) { context.allPids.add(config.getPid()); } // list available ACT whitelist configs Configuration[] configs = configAdmin.listConfigurations("(service.pid=jmx.acl.whitelist)"); if (configs != null) { for (Configuration config : configs) { context.whiteListProperties.add(config.getProperties()); } } } catch (InvalidSyntaxException ise) { throw new RuntimeException(ise); } return context; } /** * Return list of PIDs related to RBAC/ACL. * * @return The list of PIDs. */ public List<String> getAllPids() { return allPids; } /** * Return list of configurations from the whitelist. * * @return The list of configurations. */ public List<Dictionary<String,Object>> getWhitelistProperties() { return whiteListProperties; } /** * Return {@link Configuration ConfigAdmin configuration} - may be cached in this instance of * {@link BulkRequestContext context} * * @param generalPid The configuration PID. * @return The configuration. * @throws IOException If an error ocurrs while retrieving the configuration. */ public Dictionary<String, Object> getConfiguration(String generalPid) throws IOException { if (!cachedConfigurations.containsKey(generalPid)) { cachedConfigurations.put(generalPid, configAdmin.getConfiguration(generalPid, null).getProperties()); } return cachedConfigurations.get(generalPid); } public boolean isAnonymous() { return anonymous; } public Set<Principal> getPrincipals() { return principals; } }