diff options
author | Robert Gemmell <robbie@apache.org> | 2010-05-31 16:03:41 +0000 |
---|---|---|
committer | Robert Gemmell <robbie@apache.org> | 2010-05-31 16:03:41 +0000 |
commit | 48e49bef0775e91625ba7b5c03823dbaca943bf7 (patch) | |
tree | f987246a0d61c3a23e5c52b9a233778d57e3fca4 /java/broker/src/main/java/org/apache/qpid/server/management | |
parent | a2d26b71f141f3166bdd0342b481723d98b0bb99 (diff) | |
download | qpid-python-48e49bef0775e91625ba7b5c03823dbaca943bf7.tar.gz |
QPID-2606: Access Control Modifications
Applied patch from Andrew Kennedy <andrew.international@gmail.com>
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@949781 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/broker/src/main/java/org/apache/qpid/server/management')
-rw-r--r-- | java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java | 288 |
1 files changed, 158 insertions, 130 deletions
diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 0ee5763d91..7e7ac94d06 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -20,34 +20,36 @@ */ package org.apache.qpid.server.management; -import org.apache.qpid.management.common.mbeans.ConfigurationManagement; -import org.apache.qpid.management.common.mbeans.LoggingManagement; -import org.apache.qpid.management.common.mbeans.UserManagement; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; -import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; -import org.apache.log4j.Logger; - -import javax.management.remote.MBeanServerForwarder; -import javax.management.remote.JMXPrincipal; -import javax.management.remote.JMXConnectionNotification; -import javax.management.MBeanServer; -import javax.management.ObjectName; -import javax.management.MBeanInfo; -import javax.management.MBeanOperationInfo; -import javax.management.JMException; -import javax.management.NotificationListener; -import javax.management.Notification; -import javax.security.auth.Subject; import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.Principal; -import java.security.AccessControlContext; -import java.util.HashSet; -import java.util.Set; import java.util.Properties; +import java.util.Set; + +import javax.management.Attribute; +import javax.management.JMException; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanServer; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnectionNotification; +import javax.management.remote.JMXPrincipal; +import javax.management.remote.MBeanServerForwarder; +import javax.security.auth.Subject; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.ManagementActor; +import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.security.access.Operation; /** * This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. This implements @@ -65,18 +67,11 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati private MBeanServer _mbs; private static Properties _userRoles = new Properties(); private static ManagementActor _logActor; - - private static HashSet<String> _adminOnlyMethods = new HashSet<String>(); - { - _adminOnlyMethods.add(UserManagement.TYPE); - _adminOnlyMethods.add(LoggingManagement.TYPE); - _adminOnlyMethods.add(ConfigurationManagement.TYPE); - } public static MBeanServerForwarder newProxyInstance() { final InvocationHandler handler = new MBeanInvocationHandlerImpl(); - final Class[] interfaces = new Class[]{MBeanServerForwarder.class}; + final Class<?>[] interfaces = new Class[] { MBeanServerForwarder.class }; _logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger()); @@ -87,7 +82,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - final String methodName = method.getName(); + final String methodName = getMethodName(method, args); if (methodName.equals("getMBeanServer")) { @@ -112,145 +107,165 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati AccessControlContext acc = AccessController.getContext(); Subject subject = Subject.getSubject(acc); - // Allow operations performed locally on behalf of the connector server itself - if (subject == null) - { - return method.invoke(_mbs, args); - } - - if (args == null || DELEGATE.equals(args[0])) - { - return method.invoke(_mbs, args); - } - - // Restrict access to "createMBean" and "unregisterMBean" to any user - if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) - { - _logger.debug("User trying to create or unregister an MBean"); - throw new SecurityException("Access denied"); - } - - // Retrieve JMXPrincipal from Subject - Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class); - if (principals == null || principals.isEmpty()) - { - throw new SecurityException("Access denied"); - } - - Principal principal = principals.iterator().next(); - String identity = principal.getName(); - - if (isAdminMethod(args)) + try { - if (isAdmin(identity)) + // Allow operations performed locally on behalf of the connector server itself + if (subject == null) + { + return method.invoke(_mbs, args); + } + + if (args == null || DELEGATE.equals(args[0])) { return method.invoke(_mbs, args); } + + // Restrict access to "createMBean" and "unregisterMBean" to any user + if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) + { + _logger.debug("User trying to create or unregister an MBean"); + throw new SecurityException("Access denied: " + methodName); + } + + // Allow querying available object names + if (methodName.equals("queryNames")) + { + return method.invoke(_mbs, args); + } + + // Retrieve JMXPrincipal from Subject + Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + throw new SecurityException("Access denied: no principal"); + } + + // Save the principal + Principal principal = principals.iterator().next(); + SecurityManager.setThreadPrincipal(principal); + + // Get the component, type and impact, which may be null + String type = getType(method, args); + String vhost = getVirtualHost(method, args); + int impact = getImpact(method, args); + + // Get the security manager for the virtual host (if set) + SecurityManager security; + if (vhost == null) + { + security = ApplicationRegistry.getInstance().getSecurityManager(); + } else { - throw new SecurityException("Access denied"); + security = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager(); } + + if (isAccessMethod(methodName) || impact == MBeanOperationInfo.INFO) + { + // Check for read-only method invocation permission + if (!security.authoriseMethod(Operation.ACCESS, type, methodName)) + { + throw new SecurityException("Permission denied: Access " + methodName); + } + } + else if (isUpdateMethod(methodName)) + { + // Check for setting properties permission + if (!security.authoriseMethod(Operation.UPDATE, type, methodName)) + { + throw new SecurityException("Permission denied: Update " + methodName); + } + } + else + { + // Check for invoking/executing method action/operation permission + if (!security.authoriseMethod(Operation.EXECUTE, type, methodName)) + { + throw new SecurityException("Permission denied: Execute " + methodName); + } + } + + // Actually invoke the method + return method.invoke(_mbs, args); } - - // Following users can perform any operation other than "createMBean" and "unregisterMBean" - if (isAllowedToModify(identity)) - { - return method.invoke(_mbs, args); - } - - // These users can only call "getAttribute" on the MBeanServerDelegate MBean - // Here we can add other fine grained permissions like specific method for a particular mbean - if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args)) + catch (InvocationTargetException e) { - return method.invoke(_mbs, args); + throw e.getTargetException(); } + } - throw new SecurityException("Access denied"); + private String getType(Method method, Object[] args) + { + if (args[0] instanceof ObjectName) + { + ObjectName object = (ObjectName) args[0]; + String type = object.getKeyProperty("type"); + + return type; + } + return null; } - private boolean isAdminMethod(Object[] args) - { + private String getVirtualHost(Method method, Object[] args) + { if (args[0] instanceof ObjectName) { ObjectName object = (ObjectName) args[0]; + String vhost = object.getKeyProperty("VirtualHost"); - return _adminOnlyMethods.contains(object.getKeyProperty("type")); - } - return false; - } - - // Initialises the user roles - public static void setAccessRights(Properties accessRights) - { - _userRoles = accessRights; - } - - private boolean isAdmin(String userName) - { - if (ADMIN.equals(_userRoles.getProperty(userName))) - { - return true; + return vhost; } - return false; + return null; } - - private boolean isAllowedToModify(String userName) + + private String getMethodName(Method method, Object[] args) { - if (ADMIN.equals(_userRoles.getProperty(userName)) - || READWRITE.equals(_userRoles.getProperty(userName))) - { - return true; - } - return false; - } + String methodName = method.getName(); - private boolean isReadOnlyUser(String userName) - { - if (READONLY.equals(_userRoles.getProperty(userName))) + // if arguments are set, try and work out real method name + if (args != null && args.length >= 1 && args[0] instanceof ObjectName) { - return true; + if (methodName.equals("getAttribute")) + { + methodName = "get" + (String) args[1]; + } + else if (methodName.equals("setAttribute")) + { + methodName = "set" + ((Attribute) args[1]).getName(); + } + else if (methodName.equals("invoke")) + { + methodName = (String) args[1]; + } } - return false; + + return methodName; } - private boolean isReadOnlyMethod(Method method, Object[] args) + private int getImpact(Method method, Object[] args) { - String methodName = method.getName(); - - //handle standard get/set/query and select 'is' methods from MBeanServer - if (methodName.startsWith("query") || methodName.startsWith("get") - ||methodName.startsWith("isInstanceOf") || methodName.startsWith("isRegistered")) - { - return true; - } - else if (methodName.startsWith("set")) - { - return false; - } - //handle invocation of other methods on mbeans - if ((args[0] instanceof ObjectName) && (methodName.equals("invoke"))) + if ((args[0] instanceof ObjectName) && (method.getName().equals("invoke"))) { - //get invoked method name String mbeanMethod = (args.length > 1) ? (String) args[1] : null; if (mbeanMethod == null) { - return false; + return -1; } - + try { - //check if the given method is tagged with an INFO impact attribute + //Get the impact attribute MBeanInfo mbeanInfo = _mbs.getMBeanInfo((ObjectName) args[0]); if (mbeanInfo != null) { MBeanOperationInfo[] opInfos = mbeanInfo.getOperations(); for (MBeanOperationInfo opInfo : opInfos) { - if (opInfo.getName().equals(mbeanMethod) && (opInfo.getImpact() == MBeanOperationInfo.INFO)) + if (opInfo.getName().equals(mbeanMethod)) { - return true; + return opInfo.getImpact(); } } } @@ -261,7 +276,20 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati } } - return false; + return -1; + } + + private boolean isAccessMethod(String methodName) + { + //handle standard get/query/is methods from MBeanServer + return (methodName.startsWith("query") || methodName.startsWith("get") || methodName.startsWith("is")); + } + + + private boolean isUpdateMethod(String methodName) + { + //handle standard set methods from MBeanServer + return methodName.startsWith("set"); } public void handleNotification(Notification notification, Object handback) |