/* * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jmx.remote.security; import com.sun.jmx.mbeanserver.GetPropertyAction; import java.io.ObjectInputStream; import java.security.AccessController; 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; /** *
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.
* *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 SecurityException
* in the corresponding check*
method.
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 behavior is * inappropriate.
* *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.
*/ 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(); /** * Check if the caller can create the named class. The default * implementation of this method calls {@link #checkWrite()}. */ protected void checkCreate(String className) { checkWrite(); } /** * Check if the caller can unregister the named MBean. The default * implementation of this method calls {@link #checkWrite()}. */ protected void checkUnregister(ObjectName name) { checkWrite(); } //-------------------------------------------- //-------------------------------------------- // // Implementation of the MBeanServer interface // //-------------------------------------------- //-------------------------------------------- /** * CallcheckRead()
, 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 checkRead()
, 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 checkCreate(className)
, then forward this method to the
* wrapped object.
*/
public ObjectInstance createMBean(String className, ObjectName name)
throws
ReflectionException,
InstanceAlreadyExistsException,
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException {
checkCreate(className);
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 checkCreate(className)
, 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 {
checkCreate(className);
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 checkCreate(className)
, then forward this method to the
* wrapped object.
*/
public ObjectInstance createMBean(String className,
ObjectName name,
ObjectName loaderName)
throws
ReflectionException,
InstanceAlreadyExistsException,
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException,
InstanceNotFoundException {
checkCreate(className);
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 checkCreate(className)
, 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 {
checkCreate(className);
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 checkRead()
, then forward this method to the
* wrapped object.
*/
@Deprecated
public ObjectInputStream deserialize(ObjectName name, byte[] data)
throws InstanceNotFoundException, OperationsException {
checkRead();
return getMBeanServer().deserialize(name, data);
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
@Deprecated
public ObjectInputStream deserialize(String className, byte[] data)
throws OperationsException, ReflectionException {
checkRead();
return getMBeanServer().deserialize(className, data);
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
@Deprecated
public ObjectInputStream deserialize(String className,
ObjectName loaderName,
byte[] data)
throws
InstanceNotFoundException,
OperationsException,
ReflectionException {
checkRead();
return getMBeanServer().deserialize(className, loaderName, data);
}
/**
* Call checkRead()
, 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 checkRead()
, 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 checkRead()
, then forward this method to the
* wrapped object.
*/
public ClassLoader getClassLoader(ObjectName loaderName)
throws InstanceNotFoundException {
checkRead();
return getMBeanServer().getClassLoader(loaderName);
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
public ClassLoader getClassLoaderFor(ObjectName mbeanName)
throws InstanceNotFoundException {
checkRead();
return getMBeanServer().getClassLoaderFor(mbeanName);
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
public ClassLoaderRepository getClassLoaderRepository() {
checkRead();
return getMBeanServer().getClassLoaderRepository();
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
public String getDefaultDomain() {
checkRead();
return getMBeanServer().getDefaultDomain();
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
public String[] getDomains() {
checkRead();
return getMBeanServer().getDomains();
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
public Integer getMBeanCount() {
checkRead();
return getMBeanServer().getMBeanCount();
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
public MBeanInfo getMBeanInfo(ObjectName name)
throws
InstanceNotFoundException,
IntrospectionException,
ReflectionException {
checkRead();
return getMBeanServer().getMBeanInfo(name);
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
public ObjectInstance getObjectInstance(ObjectName name)
throws InstanceNotFoundException {
checkRead();
return getMBeanServer().getObjectInstance(name);
}
/**
* Call checkCreate(className)
, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className)
throws ReflectionException, MBeanException {
checkCreate(className);
return getMBeanServer().instantiate(className);
}
/**
* Call checkCreate(className)
, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className,
Object params[],
String signature[])
throws ReflectionException, MBeanException {
checkCreate(className);
return getMBeanServer().instantiate(className, params, signature);
}
/**
* Call checkCreate(className)
, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className, ObjectName loaderName)
throws ReflectionException, MBeanException, InstanceNotFoundException {
checkCreate(className);
return getMBeanServer().instantiate(className, loaderName);
}
/**
* Call checkCreate(className)
, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className, ObjectName loaderName,
Object params[], String signature[])
throws ReflectionException, MBeanException, InstanceNotFoundException {
checkCreate(className);
return getMBeanServer().instantiate(className, loaderName,
params, signature);
}
/**
* Call checkWrite()
, then forward this method to the
* wrapped object.
*/
public Object invoke(ObjectName name, String operationName,
Object params[], String signature[])
throws
InstanceNotFoundException,
MBeanException,
ReflectionException {
checkWrite();
checkMLetMethods(name, operationName);
return getMBeanServer().invoke(name, operationName, params, signature);
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
public boolean isInstanceOf(ObjectName name, String className)
throws InstanceNotFoundException {
checkRead();
return getMBeanServer().isInstanceOf(name, className);
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
public boolean isRegistered(ObjectName name) {
checkRead();
return getMBeanServer().isRegistered(name);
}
/**
* Call checkRead()
, then forward this method to the
* wrapped object.
*/
public SetcheckRead()
, then forward this method to the
* wrapped object.
*/
public SetcheckWrite()
, 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 checkRead()
, then forward this method to the
* wrapped object.
*/
public void removeNotificationListener(ObjectName name,
NotificationListener listener)
throws InstanceNotFoundException, ListenerNotFoundException {
checkRead();
getMBeanServer().removeNotificationListener(name, listener);
}
/**
* Call checkRead()
, 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 checkRead()
, then forward this method to the
* wrapped object.
*/
public void removeNotificationListener(ObjectName name,
ObjectName listener)
throws InstanceNotFoundException, ListenerNotFoundException {
checkRead();
getMBeanServer().removeNotificationListener(name, listener);
}
/**
* Call checkRead()
, 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 checkWrite()
, 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 checkWrite()
, 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 checkUnregister()
, then forward this method to the
* wrapped object.
*/
public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException {
checkUnregister(name);
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 checkMLetMethods(ObjectName name, String operation)
throws InstanceNotFoundException {
// Check if security manager installed
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
return;
}
// Check for addURL and getMBeansFromURL methods
if (!operation.equals("addURL") &&
!operation.equals("getMBeansFromURL")) {
return;
}
// Check if MBean is instance of MLet
if (!getMBeanServer().isInstanceOf(name,
"javax.management.loading.MLet")) {
return;
}
// Throw security exception
if (operation.equals("addURL")) { // addURL
throw new SecurityException("Access denied! MLet method addURL " +
"cannot be invoked unless a security manager is installed.");
} else { // getMBeansFromURL
// Whether or not calling getMBeansFromURL is allowed is controlled
// by the value of the "jmx.remote.x.mlet.allow.getMBeansFromURL"
// system property. If the value of this property is true, calling
// the MLet's getMBeansFromURL method is allowed. The default value
// for this property is false.
final String propName = "jmx.remote.x.mlet.allow.getMBeansFromURL";
GetPropertyAction propAction = new GetPropertyAction(propName);
String propValue = AccessController.doPrivileged(propAction);
boolean allowGetMBeansFromURL = "true".equalsIgnoreCase(propValue);
if (!allowGetMBeansFromURL) {
throw new SecurityException("Access denied! MLet method " +
"getMBeansFromURL cannot be invoked unless a " +
"security manager is installed or the system property " +
"-Djmx.remote.x.mlet.allow.getMBeansFromURL=true " +
"is specified.");
}
}
}
//------------------
// PRIVATE VARIABLES
//------------------
private MBeanServer mbs;
}