- /*
- * @(#)MBeanServerAccessController.java 1.7 03/12/19
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package com.sun.jmx.remote.security;
-
- import java.io.ObjectInputStream;
- import java.util.Set;
- import javax.management.Attribute;
- import javax.management.AttributeList;
- import javax.management.AttributeNotFoundException;
- import javax.management.InstanceNotFoundException;
- import javax.management.InstanceAlreadyExistsException;
- import javax.management.IntrospectionException;
- import javax.management.InvalidAttributeValueException;
- import javax.management.ListenerNotFoundException;
- import javax.management.MBeanException;
- import javax.management.MBeanInfo;
- import javax.management.MBeanRegistrationException;
- import javax.management.MBeanServer;
- import javax.management.NotCompliantMBeanException;
- import javax.management.NotificationFilter;
- import javax.management.NotificationListener;
- import javax.management.ObjectInstance;
- import javax.management.ObjectName;
- import javax.management.OperationsException;
- import javax.management.QueryExp;
- import javax.management.ReflectionException;
- import javax.management.loading.ClassLoaderRepository;
- import javax.management.remote.MBeanServerForwarder;
-
- /**
- * <p>An object of this class implements the MBeanServer interface
- * and, for each of its methods, calls an appropriate checking method
- * and then forwards the request to a wrapped MBeanServer object. The
- * checking method may throw a RuntimeException if the operation is
- * not allowed; in this case the request is not forwarded to the
- * wrapped object.</p>
- *
- * <p>A typical use of this class is to insert it between a connector server
- * such as the RMI connector and the MBeanServer with which the connector
- * is associated. Requests from the connector client can then be filtered
- * and those operations that are not allowed, or not allowed in a particular
- * context, can be rejected by throwing a <code>SecurityException</code>
- * in the corresponding <code>check*</code> method.</p>
- *
- * <p>This is an abstract class, because in its implementation none of
- * the checking methods does anything. To be useful, it must be
- * subclassed and at least one of the checking methods overridden to
- * do some checking. Some or all of the MBeanServer methods may also
- * be overridden, for instance if the default checking behaviour is
- * inappropriate.</p>
- *
- * <p>If there is no SecurityManager, then the access controller will refuse
- * to create an MBean that is a ClassLoader, which includes MLets, or to
- * execute the method addURL on an MBean that is an MLet. This prevents
- * people from opening security holes unintentionally. Otherwise, it
- * would not be obvious that granting write access grants the ability to
- * download and execute arbitrary code in the target MBean server. Advanced
- * users who do want the ability to use MLets are presumably advanced enough
- * to handle policy files and security managers.</p>
- */
- public abstract class MBeanServerAccessController
- implements MBeanServerForwarder {
-
- public MBeanServer getMBeanServer() {
- return mbs;
- }
-
- public void setMBeanServer(MBeanServer mbs) {
- if (mbs == null)
- throw new IllegalArgumentException("Null MBeanServer");
- if (this.mbs != null)
- throw new IllegalArgumentException("MBeanServer object already " +
- "initialized");
- this.mbs = mbs;
- }
-
- /**
- * Check if the caller can do read operations. This method does
- * nothing if so, otherwise throws SecurityException.
- */
- protected abstract void checkRead();
-
- /**
- * Check if the caller can do write operations. This method does
- * nothing if so, otherwise throws SecurityException.
- */
- protected abstract void checkWrite();
-
- //--------------------------------------------
- //--------------------------------------------
- //
- // Implementation of the MBeanServer interface
- //
- //--------------------------------------------
- //--------------------------------------------
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public void addNotificationListener(ObjectName name,
- NotificationListener listener,
- NotificationFilter filter,
- Object handback)
- throws InstanceNotFoundException {
- checkRead();
- getMBeanServer().addNotificationListener(name, listener,
- filter, handback);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public void addNotificationListener(ObjectName name,
- ObjectName listener,
- NotificationFilter filter,
- Object handback)
- throws InstanceNotFoundException {
- checkRead();
- getMBeanServer().addNotificationListener(name, listener,
- filter, handback);
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public ObjectInstance createMBean(String className, ObjectName name)
- throws
- ReflectionException,
- InstanceAlreadyExistsException,
- MBeanRegistrationException,
- MBeanException,
- NotCompliantMBeanException {
- checkWrite();
- SecurityManager sm = System.getSecurityManager();
- if (sm == null) {
- Object object = getMBeanServer().instantiate(className);
- checkClassLoader(object);
- return getMBeanServer().registerMBean(object, name);
- } else {
- return getMBeanServer().createMBean(className, name);
- }
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public ObjectInstance createMBean(String className, ObjectName name,
- Object params[], String signature[])
- throws
- ReflectionException,
- InstanceAlreadyExistsException,
- MBeanRegistrationException,
- MBeanException,
- NotCompliantMBeanException {
- checkWrite();
- SecurityManager sm = System.getSecurityManager();
- if (sm == null) {
- Object object = getMBeanServer().instantiate(className,
- params,
- signature);
- checkClassLoader(object);
- return getMBeanServer().registerMBean(object, name);
- } else {
- return getMBeanServer().createMBean(className, name,
- params, signature);
- }
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public ObjectInstance createMBean(String className,
- ObjectName name,
- ObjectName loaderName)
- throws
- ReflectionException,
- InstanceAlreadyExistsException,
- MBeanRegistrationException,
- MBeanException,
- NotCompliantMBeanException,
- InstanceNotFoundException {
- checkWrite();
- SecurityManager sm = System.getSecurityManager();
- if (sm == null) {
- Object object = getMBeanServer().instantiate(className,
- loaderName);
- checkClassLoader(object);
- return getMBeanServer().registerMBean(object, name);
- } else {
- return getMBeanServer().createMBean(className, name, loaderName);
- }
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public ObjectInstance createMBean(String className,
- ObjectName name,
- ObjectName loaderName,
- Object params[],
- String signature[])
- throws
- ReflectionException,
- InstanceAlreadyExistsException,
- MBeanRegistrationException,
- MBeanException,
- NotCompliantMBeanException,
- InstanceNotFoundException {
- checkWrite();
- SecurityManager sm = System.getSecurityManager();
- if (sm == null) {
- Object object = getMBeanServer().instantiate(className,
- loaderName,
- params,
- signature);
- checkClassLoader(object);
- return getMBeanServer().registerMBean(object, name);
- } else {
- return getMBeanServer().createMBean(className, name, loaderName,
- params, signature);
- }
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public ObjectInputStream deserialize(ObjectName name, byte[] data)
- throws InstanceNotFoundException, OperationsException {
- checkRead();
- return getMBeanServer().deserialize(name, data);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public ObjectInputStream deserialize(String className, byte[] data)
- throws OperationsException, ReflectionException {
- checkRead();
- return getMBeanServer().deserialize(className, data);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public ObjectInputStream deserialize(String className,
- ObjectName loaderName,
- byte[] data)
- throws
- InstanceNotFoundException,
- OperationsException,
- ReflectionException {
- checkRead();
- return getMBeanServer().deserialize(className, loaderName, data);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public Object getAttribute(ObjectName name, String attribute)
- throws
- MBeanException,
- AttributeNotFoundException,
- InstanceNotFoundException,
- ReflectionException {
- checkRead();
- return getMBeanServer().getAttribute(name, attribute);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public AttributeList getAttributes(ObjectName name, String[] attributes)
- throws InstanceNotFoundException, ReflectionException {
- checkRead();
- return getMBeanServer().getAttributes(name, attributes);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public ClassLoader getClassLoader(ObjectName loaderName)
- throws InstanceNotFoundException {
- checkRead();
- return getMBeanServer().getClassLoader(loaderName);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public ClassLoader getClassLoaderFor(ObjectName mbeanName)
- throws InstanceNotFoundException {
- checkRead();
- return getMBeanServer().getClassLoaderFor(mbeanName);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public ClassLoaderRepository getClassLoaderRepository() {
- checkRead();
- return getMBeanServer().getClassLoaderRepository();
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public String getDefaultDomain() {
- checkRead();
- return getMBeanServer().getDefaultDomain();
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public String[] getDomains() {
- checkRead();
- return getMBeanServer().getDomains();
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public Integer getMBeanCount() {
- checkRead();
- return getMBeanServer().getMBeanCount();
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public MBeanInfo getMBeanInfo(ObjectName name)
- throws
- InstanceNotFoundException,
- IntrospectionException,
- ReflectionException {
- checkRead();
- return getMBeanServer().getMBeanInfo(name);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public ObjectInstance getObjectInstance(ObjectName name)
- throws InstanceNotFoundException {
- checkRead();
- return getMBeanServer().getObjectInstance(name);
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public Object instantiate(String className)
- throws ReflectionException, MBeanException {
- checkWrite();
- return getMBeanServer().instantiate(className);
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public Object instantiate(String className,
- Object params[],
- String signature[])
- throws ReflectionException, MBeanException {
- checkWrite();
- return getMBeanServer().instantiate(className, params, signature);
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public Object instantiate(String className, ObjectName loaderName)
- throws ReflectionException, MBeanException, InstanceNotFoundException {
- checkWrite();
- return getMBeanServer().instantiate(className, loaderName);
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public Object instantiate(String className, ObjectName loaderName,
- Object params[], String signature[])
- throws ReflectionException, MBeanException, InstanceNotFoundException {
- checkWrite();
- return getMBeanServer().instantiate(className, loaderName,
- params, signature);
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public Object invoke(ObjectName name, String operationName,
- Object params[], String signature[])
- throws
- InstanceNotFoundException,
- MBeanException,
- ReflectionException {
- checkWrite();
- checkMLetAddURL(name, operationName);
- return getMBeanServer().invoke(name, operationName, params, signature);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public boolean isInstanceOf(ObjectName name, String className)
- throws InstanceNotFoundException {
- checkRead();
- return getMBeanServer().isInstanceOf(name, className);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public boolean isRegistered(ObjectName name) {
- checkRead();
- return getMBeanServer().isRegistered(name);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public Set queryMBeans(ObjectName name, QueryExp query) {
- checkRead();
- return getMBeanServer().queryMBeans(name, query);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public Set queryNames(ObjectName name, QueryExp query) {
- checkRead();
- return getMBeanServer().queryNames(name, query);
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public ObjectInstance registerMBean(Object object, ObjectName name)
- throws
- InstanceAlreadyExistsException,
- MBeanRegistrationException,
- NotCompliantMBeanException {
- checkWrite();
- return getMBeanServer().registerMBean(object, name);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public void removeNotificationListener(ObjectName name,
- NotificationListener listener)
- throws InstanceNotFoundException, ListenerNotFoundException {
- checkRead();
- getMBeanServer().removeNotificationListener(name, listener);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public void removeNotificationListener(ObjectName name,
- NotificationListener listener,
- NotificationFilter filter,
- Object handback)
- throws InstanceNotFoundException, ListenerNotFoundException {
- checkRead();
- getMBeanServer().removeNotificationListener(name, listener,
- filter, handback);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public void removeNotificationListener(ObjectName name,
- ObjectName listener)
- throws InstanceNotFoundException, ListenerNotFoundException {
- checkRead();
- getMBeanServer().removeNotificationListener(name, listener);
- }
-
- /**
- * Call <code>checkRead()</code>, then forward this method to the
- * wrapped object.
- */
- public void removeNotificationListener(ObjectName name,
- ObjectName listener,
- NotificationFilter filter,
- Object handback)
- throws InstanceNotFoundException, ListenerNotFoundException {
- checkRead();
- getMBeanServer().removeNotificationListener(name, listener,
- filter, handback);
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public void setAttribute(ObjectName name, Attribute attribute)
- throws
- InstanceNotFoundException,
- AttributeNotFoundException,
- InvalidAttributeValueException,
- MBeanException,
- ReflectionException {
- checkWrite();
- getMBeanServer().setAttribute(name, attribute);
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public AttributeList setAttributes(ObjectName name,
- AttributeList attributes)
- throws InstanceNotFoundException, ReflectionException {
- checkWrite();
- return getMBeanServer().setAttributes(name, attributes);
- }
-
- /**
- * Call <code>checkWrite()</code>, then forward this method to the
- * wrapped object.
- */
- public void unregisterMBean(ObjectName name)
- throws InstanceNotFoundException, MBeanRegistrationException {
- checkWrite();
- getMBeanServer().unregisterMBean(name);
- }
-
- //----------------
- // PRIVATE METHODS
- //----------------
-
- private void checkClassLoader(Object object) {
- if (object instanceof ClassLoader)
- throw new SecurityException("Access denied! Creating an " +
- "MBean that is a ClassLoader " +
- "is forbidden unless a security " +
- "manager is installed.");
- }
-
- private void checkMLetAddURL(ObjectName name, String operationName)
- throws InstanceNotFoundException {
- SecurityManager sm = System.getSecurityManager();
- if (sm == null) {
- if (operationName.equals("addURL") &&
- getMBeanServer().isInstanceOf(name,
- "javax.management.loading.MLet"))
- throw new SecurityException("Access denied! MLet method " +
- "addURL cannot be invoked " +
- "unless a security manager " +
- "is installed.");
- }
- }
-
- //------------------
- // PRIVATE VARIABLES
- //------------------
-
- private MBeanServer mbs;
- }