karaf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gno...@apache.org
Subject [1/2] karaf git commit: [KARAF-4351] Optimize ConfigAdmin access in bulk RBAC calls
Date Mon, 29 Feb 2016 10:06:54 GMT
Repository: karaf
Updated Branches:
  refs/heads/karaf-4.0.x e41bf62f7 -> 3877c0013


[KARAF-4351] Optimize ConfigAdmin access in bulk RBAC calls


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/78ee25b4
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/78ee25b4
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/78ee25b4

Branch: refs/heads/karaf-4.0.x
Commit: 78ee25b467bdd26a9451f1f293a50fe321e5175e
Parents: e41bf62
Author: Grzegorz Grzybek <gr.grzybek@gmail.com>
Authored: Fri Feb 19 18:47:15 2016 +0100
Committer: Guillaume Nodet <gnodet@apache.org>
Committed: Mon Feb 29 11:00:16 2016 +0100

----------------------------------------------------------------------
 .../karaf/management/KarafMBeanServerGuard.java | 139 +++++++++++++------
 .../management/internal/BulkRequestContext.java | 100 +++++++++++++
 .../internal/JMXSecurityMBeanImpl.java          |  30 ++--
 .../internal/JMXSecurityMBeanImplTestCase.java  |  87 ++++++++++--
 4 files changed, 290 insertions(+), 66 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/78ee25b4/management/server/src/main/java/org/apache/karaf/management/KarafMBeanServerGuard.java
----------------------------------------------------------------------
diff --git a/management/server/src/main/java/org/apache/karaf/management/KarafMBeanServerGuard.java
b/management/server/src/main/java/org/apache/karaf/management/KarafMBeanServerGuard.java
index 645a0df..b112c2f 100644
--- a/management/server/src/main/java/org/apache/karaf/management/KarafMBeanServerGuard.java
+++ b/management/server/src/main/java/org/apache/karaf/management/KarafMBeanServerGuard.java
@@ -16,10 +16,9 @@
  */
 package org.apache.karaf.management;
 
+import org.apache.karaf.management.internal.BulkRequestContext;
 import org.apache.karaf.service.guard.tools.ACLConfigurationParser;
 import org.apache.karaf.util.jaas.JaasHelper;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
 
 import javax.management.*;
@@ -27,9 +26,9 @@ import java.io.IOException;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
@@ -95,6 +94,20 @@ public class KarafMBeanServerGuard implements InvocationHandler {
      * @throws IOException
      */
     public boolean canInvoke(MBeanServer mbeanServer, ObjectName objectName) throws JMException,
IOException {
+        return canInvoke(null, mbeanServer, objectName);
+    }
+
+    /**
+     * Returns whether there is any method that the current user can invoke.
+     *
+     * @param context {@link BulkRequestContext} for optimized ConfigAdmin access, may be
<code>null</code>
+     * @param mbeanServer the MBeanServer where the object is registered.
+     * @param objectName the ObjectName to check.
+     * @return {@code true} if there is a method on the object that can be invoked, {@code
false} else.
+     * @throws JMException
+     * @throws IOException
+     */
+    public boolean canInvoke(BulkRequestContext context, MBeanServer mbeanServer, ObjectName
objectName) throws JMException, IOException {
         MBeanInfo info = mbeanServer.getMBeanInfo(objectName);
 
         for (MBeanOperationInfo operation : info.getOperations()) {
@@ -102,18 +115,18 @@ public class KarafMBeanServerGuard implements InvocationHandler {
             for (MBeanParameterInfo param : operation.getSignature()) {
                 sig.add(param.getType());
             }
-            if (canInvoke(objectName, operation.getName(), sig.toArray(new String[] {})))
{
+            if (canInvoke(context, objectName, operation.getName(), sig.toArray(new String[]
{}))) {
                 return true;
             }
         }
 
         for (MBeanAttributeInfo attr : info.getAttributes()) {
             if (attr.isReadable()) {
-                if (canInvoke(objectName, attr.isIs() ? "is" : "get" + attr.getName(), new
String[] {}))
+                if (canInvoke(context, objectName, attr.isIs() ? "is" : "get" + attr.getName(),
new String[] {}))
                     return true;
             }
             if (attr.isWritable()) {
-                if (canInvoke(objectName, "set" + attr.getName(), new String[]{attr.getType()}))
+                if (canInvoke(context, objectName, "set" + attr.getName(), new String[]{attr.getType()}))
                     return true;
             }
         }
@@ -132,6 +145,21 @@ public class KarafMBeanServerGuard implements InvocationHandler {
      * @throws IOException
      */
     public boolean canInvoke(MBeanServer mbeanServer, ObjectName objectName, String methodName)
throws JMException, IOException {
+        return canInvoke(null, mbeanServer, objectName, methodName);
+    }
+
+    /**
+     * Returns whether there is any overload of the specified method that can be invoked
by the current user.
+     *
+     * @param context {@link BulkRequestContext} for optimized ConfigAdmin access, may be
<code>null</code>
+     * @param mbeanServer the MBeanServer where the object is registered.
+     * @param objectName the MBean ObjectName.
+     * @param methodName the name of the method.
+     * @return {@code true} if there is an overload of the method that can be invoked by
the current user.
+     * @throws JMException
+     * @throws IOException
+     */
+    public boolean canInvoke(BulkRequestContext context, MBeanServer mbeanServer, ObjectName
objectName, String methodName) throws JMException, IOException {
         methodName = methodName.trim();
         MBeanInfo info = mbeanServer.getMBeanInfo(objectName);
 
@@ -144,7 +172,7 @@ public class KarafMBeanServerGuard implements InvocationHandler {
             for (MBeanParameterInfo param : op.getSignature()) {
                 sig.add(param.getType());
             }
-            if (canInvoke(objectName, op.getName(), sig.toArray(new String[] {}))) {
+            if (canInvoke(context, objectName, op.getName(), sig.toArray(new String[] {})))
{
                 return true;
             }
         }
@@ -152,10 +180,10 @@ public class KarafMBeanServerGuard implements InvocationHandler {
         for (MBeanAttributeInfo attr : info.getAttributes()) {
             String attrName = attr.getName();
             if (methodName.equals("is" + attrName) || methodName.equals("get" + attrName))
{
-                return canInvoke(objectName, methodName, new String[] {});
+                return canInvoke(context, objectName, methodName, new String[] {});
             }
             if (methodName.equals("set" + attrName)) {
-                return canInvoke(objectName, methodName, new String[] { attr.getType() });
+                return canInvoke(context, objectName, methodName, new String[] { attr.getType()
});
             }
         }
 
@@ -176,15 +204,36 @@ public class KarafMBeanServerGuard implements InvocationHandler {
      * @throws IOException
      */
     public boolean canInvoke(MBeanServer mbeanServer, ObjectName objectName, String methodName,
String[] signature) throws IOException {
+        return canInvoke(null, mbeanServer, objectName, methodName, signature);
+    }
+
+    /**
+     * Returns true if the method on the MBean with the specified signature can be invoked.
+     *
+     * @param context {@link BulkRequestContext} for optimized ConfigAdmin access, may be
<code>null</code>
+     * @param mbeanServer the MBeanServer where the object is registered.
+     * @param objectName the MBean ObjectName.
+     * @param methodName the name of the method.
+     * @param signature the signature of the method.
+     * @return {@code true} if the method can be invoked, {@code false} else. Note that if
a method name or signature
+     *      is provided that does not exist on the MBean, the behaviour of this method is
undefined. In other words,
+     *      if you ask whether a method that does not exist can be invoked, the method may
return {@code true} but
+     *      actually invoking that method will obviously not work.
+     * @throws IOException
+     */
+    public boolean canInvoke(BulkRequestContext context, MBeanServer mbeanServer, ObjectName
objectName, String methodName, String[] signature) throws IOException {
         // no checking done on the MBeanServer of whether the method actually exists...
-        return canInvoke(objectName, methodName, signature);
+        return canInvoke(context, objectName, methodName, signature);
     }
 
-    private boolean canInvoke(ObjectName objectName, String methodName, String[] signature)
throws IOException {
-        if (canBypassRBAC(objectName, methodName)) {
+    private boolean canInvoke(BulkRequestContext context, ObjectName objectName, String methodName,
String[] signature) throws IOException {
+        if (context == null) {
+            context = BulkRequestContext.newContext(configAdmin);
+        }
+        if (canBypassRBAC(context, objectName, methodName)) {
             return true;
         }
-        for (String role : getRequiredRoles(objectName, methodName, signature)) {
+        for (String role : getRequiredRoles(context, objectName, methodName, signature))
{
             if (JaasHelper.currentUserHasRole(role))
                 return true;
         }
@@ -203,7 +252,7 @@ public class KarafMBeanServerGuard implements InvocationHandler {
         if (prefix == null) {
             LOG.debug("Attribute " + attributeName + " can not be found for MBean " + objectName.toString());
         } else {
-            handleInvoke(objectName, prefix + attributeName, new Object[]{}, new String[]{});
+            handleInvoke(null, objectName, prefix + attributeName, new Object[]{}, new String[]{});
         }
     }
 
@@ -226,7 +275,7 @@ public class KarafMBeanServerGuard implements InvocationHandler {
         if (dataType == null)
             throw new IllegalStateException("Attribute data type can not be found");
 
-        handleInvoke(objectName, "set" + attribute.getName(), new Object[]{ attribute.getValue()
}, new String[]{ dataType });
+        handleInvoke(null, objectName, "set" + attribute.getName(), new Object[]{ attribute.getValue()
}, new String[]{ dataType });
     }
 
     private void handleSetAttributes(MBeanServer proxy, ObjectName objectName, AttributeList
attributes) throws JMException, IOException {
@@ -235,24 +284,17 @@ public class KarafMBeanServerGuard implements InvocationHandler {
         }
     }
     
-    private boolean canBypassRBAC(ObjectName objectName, String operationName) {
+    private boolean canBypassRBAC(BulkRequestContext context, ObjectName objectName, String
operationName) {
         List<String> allBypassObjectName = new ArrayList<String>();
-        try {
-            Configuration[] configs = configAdmin.listConfigurations("(service.pid=" + JMX_ACL_WHITELIST
+ ")");
-            if (configs != null) {
-                for (Configuration config : configs) {
-                    Enumeration<String> keys = config.getProperties().keys();
-                    while (keys.hasMoreElements()) {
-                        String element = keys.nextElement();
-                        allBypassObjectName.add(element);
-                    }
-                }
+
+        List<Dictionary<String, Object>> configs = context.getWhitelistProperties();
+        for (Dictionary<String, Object> config : configs) {
+            Enumeration<String> keys = config.keys();
+            while (keys.hasMoreElements()) {
+                String element = keys.nextElement();
+                allBypassObjectName.add(element);
             }
-        } catch (InvalidSyntaxException ise) {
-            throw new RuntimeException(ise);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        } 
+        }
 
         for (String pid : iterateDownPids(getNameSegments(objectName))) {
             if (!pid.equals("jmx.acl"))  {
@@ -276,10 +318,17 @@ public class KarafMBeanServerGuard implements InvocationHandler {
     }
 
     void handleInvoke(ObjectName objectName, String operationName, Object[] params, String[]
signature) throws IOException {
-        if (canBypassRBAC(objectName, operationName)) {
+        handleInvoke(null, objectName, operationName, params, signature);
+    }
+
+    void handleInvoke(BulkRequestContext context, ObjectName objectName, String operationName,
Object[] params, String[] signature) throws IOException {
+        if (context == null) {
+            context = BulkRequestContext.newContext(configAdmin);
+        }
+        if (canBypassRBAC(context, objectName, operationName)) {
             return;
         }
-        for (String role : getRequiredRoles(objectName, operationName, params, signature))
{
+        for (String role : getRequiredRoles(context, objectName, operationName, params, signature))
{
             if (JaasHelper.currentUserHasRole(role))
                 return;
         }
@@ -287,26 +336,24 @@ public class KarafMBeanServerGuard implements InvocationHandler {
     }
 
     List<String> getRequiredRoles(ObjectName objectName, String methodName, String[]
signature) throws IOException {
-        return getRequiredRoles(objectName, methodName, null, signature);
+        return getRequiredRoles(BulkRequestContext.newContext(configAdmin), objectName, methodName,
null, signature);
     }
 
-    List<String> getRequiredRoles(ObjectName objectName, String methodName, Object[]
params, String[] signature) throws IOException {
+    List<String> getRequiredRoles(BulkRequestContext context, ObjectName objectName,
String methodName, String[] signature) throws IOException {
+        return getRequiredRoles(context, objectName, methodName, null, signature);
+    }
 
-        List<String> allPids = new ArrayList<String>();
-        try {
-            for (Configuration config : configAdmin.listConfigurations("(service.pid=jmx.acl*)"))
{
-                allPids.add(config.getPid());
-            }
-        } catch (InvalidSyntaxException ise) {
-            throw new RuntimeException(ise);
-        }
+    List<String> getRequiredRoles(ObjectName objectName, String methodName, Object[]
params, String[] signature) throws IOException {
+        return getRequiredRoles(BulkRequestContext.newContext(configAdmin), objectName, methodName,
params, signature);
+    }
 
+    List<String> getRequiredRoles(BulkRequestContext context, ObjectName objectName,
String methodName, Object[] params, String[] signature) throws IOException {
         for (String pid : iterateDownPids(getNameSegments(objectName))) {
-            String generalPid = getGeneralPid(allPids, pid);
+            String generalPid = getGeneralPid(context.getAllPids(), pid);
             if (generalPid.length() > 0) {
-                Configuration config = configAdmin.getConfiguration(generalPid, null);
+                Dictionary<String, Object> config = context.getConfiguration(generalPid);
                 List<String> roles = new ArrayList<String>();
-                ACLConfigurationParser.Specificity s = ACLConfigurationParser.getRolesForInvocation(methodName,
params, signature, config.getProperties(), roles);
+                ACLConfigurationParser.Specificity s = ACLConfigurationParser.getRolesForInvocation(methodName,
params, signature, config, roles);
                 if (s != ACLConfigurationParser.Specificity.NO_MATCH) {
                     return roles;
                 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/78ee25b4/management/server/src/main/java/org/apache/karaf/management/internal/BulkRequestContext.java
----------------------------------------------------------------------
diff --git a/management/server/src/main/java/org/apache/karaf/management/internal/BulkRequestContext.java
b/management/server/src/main/java/org/apache/karaf/management/internal/BulkRequestContext.java
new file mode 100644
index 0000000..1c72a60
--- /dev/null
+++ b/management/server/src/main/java/org/apache/karaf/management/internal/BulkRequestContext.java
@@ -0,0 +1,100 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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;
+
+    // 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 {
+            // 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;
+    }
+
+    /**
+     * Returns list of PIDs related to RBAC/ACL
+     * @return
+     */
+    public List<String> getAllPids() {
+        return allPids;
+    }
+
+    /**
+     * Returns list of configurations from
+     * @return
+     */
+    public List<Dictionary<String,Object>> getWhitelistProperties() {
+        return whiteListProperties;
+    }
+
+    /**
+     * Returns {@link Configuration ConfigAdmin configuration} - may be cached in this instance
of
+     * {@link BulkRequestContext context}
+     * @param generalPid
+     * @return
+     */
+    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);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/78ee25b4/management/server/src/main/java/org/apache/karaf/management/internal/JMXSecurityMBeanImpl.java
----------------------------------------------------------------------
diff --git a/management/server/src/main/java/org/apache/karaf/management/internal/JMXSecurityMBeanImpl.java
b/management/server/src/main/java/org/apache/karaf/management/internal/JMXSecurityMBeanImpl.java
index 031fbdf..683be51 100644
--- a/management/server/src/main/java/org/apache/karaf/management/internal/JMXSecurityMBeanImpl.java
+++ b/management/server/src/main/java/org/apache/karaf/management/internal/JMXSecurityMBeanImpl.java
@@ -41,36 +41,50 @@ public class JMXSecurityMBeanImpl extends StandardMBean implements JMXSecurityMB
     }
 
     public boolean canInvoke(String objectName) throws Exception {
+        return canInvoke((BulkRequestContext) null, objectName);
+    }
+
+    public boolean canInvoke(String objectName, String methodName) throws Exception {
+        return canInvoke(null, objectName, methodName);
+    }
+
+    public boolean canInvoke(String objectName, String methodName, String[] argumentTypes)
throws Exception {
+        return canInvoke(null, objectName, methodName, argumentTypes);
+    }
+
+    private boolean canInvoke(BulkRequestContext context, String objectName) throws Exception
{
         if (guard == null)
             return true;
 
-        return guard.canInvoke(mbeanServer, new ObjectName(objectName));
+        return guard.canInvoke(context, mbeanServer, new ObjectName(objectName));
     }
 
-    public boolean canInvoke(String objectName, String methodName) throws Exception {
+    private boolean canInvoke(BulkRequestContext context, String objectName, String methodName)
throws Exception {
         if (guard == null)
             return true;
 
-        return guard.canInvoke(mbeanServer, new ObjectName(objectName), methodName);
+        return guard.canInvoke(context, mbeanServer, new ObjectName(objectName), methodName);
     }
 
-    public boolean canInvoke(String objectName, String methodName, String[] argumentTypes)
throws Exception {
+    private boolean canInvoke(BulkRequestContext context, String objectName, String methodName,
String[] argumentTypes) throws Exception {
         ObjectName on = new ObjectName(objectName);
 
         if (guard == null)
             return true;
 
-        return guard.canInvoke(mbeanServer, on, methodName, argumentTypes);
+        return guard.canInvoke(context, mbeanServer, on, methodName, argumentTypes);
     }
 
     public TabularData canInvoke(Map<String, List<String>> bulkQuery) throws
Exception {
         TabularData table = new TabularDataSupport(CAN_INVOKE_TABULAR_TYPE);
 
+        BulkRequestContext context = BulkRequestContext.newContext(guard.getConfigAdmin());
+
         for (Map.Entry<String, List<String>> entry : bulkQuery.entrySet()) {
             String objectName = entry.getKey();
             List<String> methods = entry.getValue();
             if (methods.size() == 0) {
-                boolean res = canInvoke(objectName);
+                boolean res = canInvoke(context, objectName);
                 CompositeData data = new CompositeDataSupport(CAN_INVOKE_RESULT_ROW_TYPE,
CAN_INVOKE_RESULT_COLUMNS, new Object[]{ objectName, "", res });
                 table.put(data);
             } else {
@@ -80,9 +94,9 @@ public class JMXSecurityMBeanImpl extends StandardMBean implements JMXSecurityMB
 
                     boolean res;
                     if (name.equals(method)) {
-                        res = canInvoke(objectName, name);
+                        res = canInvoke(context, objectName, name);
                     } else {
-                        res = canInvoke(objectName, name, argTypes.toArray(new String[]{}));
+                        res = canInvoke(context, objectName, name, argTypes.toArray(new String[]{}));
                     }
                     CompositeData data = new CompositeDataSupport(CAN_INVOKE_RESULT_ROW_TYPE,
CAN_INVOKE_RESULT_COLUMNS, new Object[]{ objectName, method, res });
                     table.put(data);

http://git-wip-us.apache.org/repos/asf/karaf/blob/78ee25b4/management/server/src/test/java/org/apache/karaf/management/internal/JMXSecurityMBeanImplTestCase.java
----------------------------------------------------------------------
diff --git a/management/server/src/test/java/org/apache/karaf/management/internal/JMXSecurityMBeanImplTestCase.java
b/management/server/src/test/java/org/apache/karaf/management/internal/JMXSecurityMBeanImplTestCase.java
index cea0092..c77c484 100644
--- a/management/server/src/test/java/org/apache/karaf/management/internal/JMXSecurityMBeanImplTestCase.java
+++ b/management/server/src/test/java/org/apache/karaf/management/internal/JMXSecurityMBeanImplTestCase.java
@@ -19,6 +19,8 @@ package org.apache.karaf.management.internal;
 import junit.framework.TestCase;
 import org.apache.karaf.management.KarafMBeanServerGuard;
 import org.easymock.EasyMock;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
 
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
@@ -44,7 +46,7 @@ public class JMXSecurityMBeanImplTestCase extends TestCase {
 
         String objectName = "foo.bar.testing:type=SomeMBean";
         KarafMBeanServerGuard testGuard = EasyMock.createMock(KarafMBeanServerGuard.class);
-        EasyMock.expect(testGuard.canInvoke(mbs, new ObjectName(objectName))).andReturn(true);
+        EasyMock.expect(testGuard.canInvoke(null, mbs, new ObjectName(objectName))).andReturn(true);
         EasyMock.replay(testGuard);
 
         JMXSecurityMBeanImpl mb = new JMXSecurityMBeanImpl();
@@ -59,7 +61,7 @@ public class JMXSecurityMBeanImplTestCase extends TestCase {
 
         String objectName = "foo.bar.testing:type=SomeMBean";
         KarafMBeanServerGuard testGuard = EasyMock.createMock(KarafMBeanServerGuard.class);
-        EasyMock.expect(testGuard.canInvoke(mbs, new ObjectName(objectName))).andReturn(false);
+        EasyMock.expect(testGuard.canInvoke(null, mbs, new ObjectName(objectName))).andReturn(false);
         EasyMock.replay(testGuard);
 
         JMXSecurityMBeanImpl mb = new JMXSecurityMBeanImpl();
@@ -75,7 +77,7 @@ public class JMXSecurityMBeanImplTestCase extends TestCase {
 
             String objectName = "foo.bar.testing:type=SomeMBean";
             KarafMBeanServerGuard testGuard = EasyMock.createMock(KarafMBeanServerGuard.class);
-            EasyMock.expect(testGuard.canInvoke(mbs, new ObjectName(objectName))).andThrow(new
IOException());
+            EasyMock.expect(testGuard.canInvoke(null, mbs, new ObjectName(objectName))).andThrow(new
IOException());
             EasyMock.replay(testGuard);
 
             JMXSecurityMBeanImpl mb = new JMXSecurityMBeanImpl();
@@ -102,9 +104,9 @@ public class JMXSecurityMBeanImplTestCase extends TestCase {
         String[] la = new String[]{"long"};
         String[] sa = new String[]{"java.lang.String"};
         String[] sa2 = new String[]{"java.lang.String", "java.lang.String"};
-        EasyMock.expect(testGuard.canInvoke(mbs, new ObjectName(objectName), "testMethod",
la)).andReturn(true);
-        EasyMock.expect(testGuard.canInvoke(mbs, new ObjectName(objectName), "testMethod",
sa)).andReturn(true);
-        EasyMock.expect(testGuard.canInvoke(mbs, new ObjectName(objectName), "otherMethod",
sa2)).andReturn(false);
+        EasyMock.expect(testGuard.canInvoke(null, mbs, new ObjectName(objectName), "testMethod",
la)).andReturn(true);
+        EasyMock.expect(testGuard.canInvoke(null, mbs, new ObjectName(objectName), "testMethod",
sa)).andReturn(true);
+        EasyMock.expect(testGuard.canInvoke(null, mbs, new ObjectName(objectName), "otherMethod",
sa2)).andReturn(false);
         EasyMock.replay(testGuard);
 
         JMXSecurityMBeanImpl mb = new JMXSecurityMBeanImpl();
@@ -123,7 +125,7 @@ public class JMXSecurityMBeanImplTestCase extends TestCase {
             String objectName = "foo.bar.testing:type=SomeMBean";
             KarafMBeanServerGuard testGuard = EasyMock.createMock(KarafMBeanServerGuard.class);
             String[] ea = new String[]{};
-            EasyMock.expect(testGuard.canInvoke(mbs, new ObjectName(objectName), "testMethod",
ea)).andThrow(new IOException());
+            EasyMock.expect(testGuard.canInvoke(null, mbs, new ObjectName(objectName), "testMethod",
ea)).andThrow(new IOException());
             EasyMock.replay(testGuard);
 
             JMXSecurityMBeanImpl mb = new JMXSecurityMBeanImpl();
@@ -145,17 +147,25 @@ public class JMXSecurityMBeanImplTestCase extends TestCase {
         MBeanServer mbs = EasyMock.createMock(MBeanServer.class);
         EasyMock.replay(mbs);
 
+        ConfigurationAdmin testConfigAdmin = EasyMock.createMock(ConfigurationAdmin.class);
+        EasyMock.expect(testConfigAdmin.listConfigurations(EasyMock.eq("(service.pid=jmx.acl*)")))
+                .andReturn(new Configuration[0]).anyTimes();
+        EasyMock.expect(testConfigAdmin.listConfigurations(EasyMock.eq("(service.pid=jmx.acl.whitelist)")))
+                .andReturn(new Configuration[0]).once();
+        EasyMock.replay(testConfigAdmin);
+
         KarafMBeanServerGuard testGuard = EasyMock.createMock(KarafMBeanServerGuard.class);
         String objectName = "foo.bar.testing:type=SomeMBean";
         final String[] la = new String[]{"long"};
         final String[] sa = new String[]{"java.lang.String"};
-        EasyMock.expect(testGuard.canInvoke(EasyMock.eq(mbs), EasyMock.eq(new ObjectName(objectName)),
EasyMock.eq("testMethod"), EasyMock.aryEq(la))).andReturn(true).anyTimes();
-        EasyMock.expect(testGuard.canInvoke(EasyMock.eq(mbs), EasyMock.eq(new ObjectName(objectName)),
EasyMock.eq("testMethod"), EasyMock.aryEq(sa))).andReturn(false).anyTimes();
-        EasyMock.expect(testGuard.canInvoke(EasyMock.eq(mbs), EasyMock.eq(new ObjectName(objectName)),
EasyMock.eq("otherMethod"))).andReturn(true).anyTimes();
+        EasyMock.expect(testGuard.getConfigAdmin()).andReturn(testConfigAdmin).anyTimes();
+        EasyMock.expect(testGuard.canInvoke(EasyMock.anyObject(BulkRequestContext.class),
EasyMock.eq(mbs), EasyMock.eq(new ObjectName(objectName)), EasyMock.eq("testMethod"), EasyMock.aryEq(la))).andReturn(true).anyTimes();
+        EasyMock.expect(testGuard.canInvoke(EasyMock.anyObject(BulkRequestContext.class),
EasyMock.eq(mbs), EasyMock.eq(new ObjectName(objectName)), EasyMock.eq("testMethod"), EasyMock.aryEq(sa))).andReturn(false).anyTimes();
+        EasyMock.expect(testGuard.canInvoke(EasyMock.anyObject(BulkRequestContext.class),
EasyMock.eq(mbs), EasyMock.eq(new ObjectName(objectName)), EasyMock.eq("otherMethod"))).andReturn(true).anyTimes();
         String objectName2 = "foo.bar.testing:type=SomeOtherMBean";
-        EasyMock.expect(testGuard.canInvoke(EasyMock.eq(mbs), EasyMock.eq(new ObjectName(objectName2)))).andReturn(true).anyTimes();
+        EasyMock.expect(testGuard.canInvoke(EasyMock.anyObject(BulkRequestContext.class),
EasyMock.eq(mbs), EasyMock.eq(new ObjectName(objectName2)))).andReturn(true).anyTimes();
         String objectName3 = "foo.bar.foo.testing:type=SomeOtherMBean";
-        EasyMock.expect(testGuard.canInvoke(EasyMock.eq(mbs), EasyMock.eq(new ObjectName(objectName3)))).andReturn(false).anyTimes();
+        EasyMock.expect(testGuard.canInvoke(EasyMock.anyObject(BulkRequestContext.class),
EasyMock.eq(mbs), EasyMock.eq(new ObjectName(objectName3)))).andReturn(false).anyTimes();
         EasyMock.replay(testGuard);
 
         JMXSecurityMBeanImpl mb = new JMXSecurityMBeanImpl();
@@ -190,4 +200,57 @@ public class JMXSecurityMBeanImplTestCase extends TestCase {
         assertEquals(false, cd5.get("CanInvoke"));
     }
 
+    public void testCanInvokeBulkCacheConfigAdmin() throws Exception {
+        MBeanServer mbs = EasyMock.createMock(MBeanServer.class);
+        EasyMock.replay(mbs);
+
+        Configuration fooWildcardTesting = EasyMock.createMock(Configuration.class);
+        EasyMock.expect(fooWildcardTesting.getPid()).andReturn("jmx.acl.foo._.testing").once();
+        EasyMock.replay(fooWildcardTesting);
+
+        Dictionary<String, Object> fooBarProperties = new Hashtable<>();
+        // using '*' frees us from mocking JAAS
+        fooBarProperties.put("testMethod(java.lang.String)", "*");
+        fooBarProperties.put("testMethod(long)", "*");
+        Configuration fooBarTesting = EasyMock.createMock(Configuration.class);
+        EasyMock.expect(fooBarTesting.getPid()).andReturn("jmx.acl.foo.bar.testing").once();
+        EasyMock.expect(fooBarTesting.getProperties()).andReturn(fooBarProperties).once();
+        EasyMock.replay(fooBarTesting);
+
+        ConfigurationAdmin testConfigAdmin = EasyMock.createMock(ConfigurationAdmin.class);
+        EasyMock.expect(testConfigAdmin.listConfigurations(EasyMock.eq("(service.pid=jmx.acl*)")))
+                .andReturn(new Configuration[] { fooWildcardTesting, fooBarTesting }).once();
+        EasyMock.expect(testConfigAdmin.listConfigurations(EasyMock.eq("(service.pid=jmx.acl.whitelist)")))
+                .andReturn(new Configuration[0]).once();
+        EasyMock.expect(testConfigAdmin.getConfiguration(EasyMock.eq("jmx.acl.foo.bar.testing"),
EasyMock.isNull(String.class)))
+                .andReturn(fooBarTesting).once();
+        EasyMock.replay(testConfigAdmin);
+
+        KarafMBeanServerGuard guard = new KarafMBeanServerGuard();
+        guard.setConfigAdmin(testConfigAdmin);
+
+        String objectName = "foo.bar.testing:type=SomeMBean";
+        String objectName2 = "foo.bar.testing:type=SomeOtherMBean";
+
+        JMXSecurityMBeanImpl mb = new JMXSecurityMBeanImpl();
+        mb.setMBeanServer(mbs);
+        mb.setGuard(guard);
+        Map<String, List<String>> query = new HashMap<String, List<String>>();
+        query.put(objectName, Collections.singletonList("testMethod(java.lang.String)"));
+        query.put(objectName2, Collections.singletonList("testMethod(long)"));
+        TabularData result = mb.canInvoke(query);
+        assertEquals(2, result.size());
+
+        CompositeData cd2 = result.get(new Object[]{objectName, "testMethod(java.lang.String)"});
+        assertEquals(objectName, cd2.get("ObjectName"));
+        assertEquals("testMethod(java.lang.String)", cd2.get("Method"));
+        assertEquals(true, cd2.get("CanInvoke"));
+        CompositeData cd4 = result.get(new Object[]{objectName2, "testMethod(long)"});
+        assertEquals(objectName2, cd4.get("ObjectName"));
+        assertEquals("testMethod(long)", cd4.get("Method"));
+        assertEquals(true, cd4.get("CanInvoke"));
+
+        EasyMock.verify(testConfigAdmin, fooWildcardTesting, fooBarTesting);
+    }
+
 }


Mime
View raw message