6747899: jmx namespaces: hooks for permission checks should be defined in HandlerInterceptor

Reviewed-by: emcmanus
This commit is contained in:
Daniel Fuchs 2008-09-12 17:58:15 +02:00
parent a1e4e3ec94
commit 38e8cbedc6
2 changed files with 174 additions and 151 deletions

View file

@ -135,7 +135,11 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
public AttributeList getAttributes(ObjectName name, String[] attributes) public AttributeList getAttributes(ObjectName name, String[] attributes)
throws InstanceNotFoundException, ReflectionException { throws InstanceNotFoundException, ReflectionException {
try { try {
return super.getAttributes(name, attributes); final String[] authorized =
checkAttributes(name,attributes,"getAttribute");
final AttributeList attrList =
super.getAttributes(name,authorized);
return attrList;
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"getAttributes",name,attributes); throw handleIOException(ex,"getAttributes",name,attributes);
} }
@ -185,6 +189,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
public void removeNotificationListener(ObjectName name, ObjectName listener) public void removeNotificationListener(ObjectName name, ObjectName listener)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
try { try {
check(name,null,"removeNotificationListener");
super.removeNotificationListener(name,listener); super.removeNotificationListener(name,listener);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name,listener); throw handleIOException(ex,"removeNotificationListener",name,listener);
@ -205,7 +210,9 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
@Override @Override
public String[] getDomains() { public String[] getDomains() {
try { try {
return super.getDomains(); check(null,null,"getDomains");
final String[] domains = super.getDomains();
return checkDomains(domains,"getDomains");
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"getDomains"); throw handleIOException(ex,"getDomains");
} }
@ -228,6 +235,9 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
InvalidAttributeValueException, MBeanException, InvalidAttributeValueException, MBeanException,
ReflectionException { ReflectionException {
try { try {
check(name,
(attribute==null?null:attribute.getName()),
"setAttribute");
super.setAttribute(name,attribute); super.setAttribute(name,attribute);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"setAttribute",name, attribute); throw handleIOException(ex,"setAttribute",name, attribute);
@ -237,7 +247,9 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
// From MBeanServerConnection: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) { public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
if (name == null) name=ObjectName.WILDCARD;
try { try {
checkPattern(name,null,"queryNames");
return super.queryNames(name,query); return super.queryNames(name,query);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"queryNames",name, query); throw handleIOException(ex,"queryNames",name, query);
@ -247,7 +259,9 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
// From MBeanServerConnection: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) { public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
if (name == null) name=ObjectName.WILDCARD;
try { try {
checkPattern(name,null,"queryMBeans");
return super.queryMBeans(name,query); return super.queryMBeans(name,query);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"queryMBeans",name, query); throw handleIOException(ex,"queryMBeans",name, query);
@ -259,6 +273,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
public boolean isInstanceOf(ObjectName name, String className) public boolean isInstanceOf(ObjectName name, String className)
throws InstanceNotFoundException { throws InstanceNotFoundException {
try { try {
check(name, null, "isInstanceOf");
return super.isInstanceOf(name, className); return super.isInstanceOf(name, className);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"isInstanceOf",name, className); throw handleIOException(ex,"isInstanceOf",name, className);
@ -272,6 +287,8 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException { NotCompliantMBeanException {
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return super.createMBean(className, name); return super.createMBean(className, name);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"createMBean",className, name); throw handleIOException(ex,"createMBean",className, name);
@ -286,6 +303,8 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException, InstanceNotFoundException { NotCompliantMBeanException, InstanceNotFoundException {
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return super.createMBean(className, name, loaderName); return super.createMBean(className, name, loaderName);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"createMBean",className, name, loaderName); throw handleIOException(ex,"createMBean",className, name, loaderName);
@ -298,6 +317,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
throws MBeanException, AttributeNotFoundException, throws MBeanException, AttributeNotFoundException,
InstanceNotFoundException, ReflectionException { InstanceNotFoundException, ReflectionException {
try { try {
check(name, attribute, "getAttribute");
return super.getAttribute(name, attribute); return super.getAttribute(name, attribute);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"getAttribute",name, attribute); throw handleIOException(ex,"getAttribute",name, attribute);
@ -310,6 +330,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
NotificationFilter filter, Object handback) NotificationFilter filter, Object handback)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
try { try {
check(name,null,"removeNotificationListener");
super.removeNotificationListener(name, listener, filter, handback); super.removeNotificationListener(name, listener, filter, handback);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name, throw handleIOException(ex,"removeNotificationListener",name,
@ -324,6 +345,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
Object handback) Object handback)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
try { try {
check(name,null,"removeNotificationListener");
super.removeNotificationListener(name, listener, filter, handback); super.removeNotificationListener(name, listener, filter, handback);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name, throw handleIOException(ex,"removeNotificationListener",name,
@ -337,6 +359,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
NotificationListener listener) NotificationListener listener)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
try { try {
check(name,null,"removeNotificationListener");
super.removeNotificationListener(name, listener); super.removeNotificationListener(name, listener);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name, throw handleIOException(ex,"removeNotificationListener",name,
@ -350,6 +373,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
NotificationListener listener, NotificationFilter filter, NotificationListener listener, NotificationFilter filter,
Object handback) throws InstanceNotFoundException { Object handback) throws InstanceNotFoundException {
try { try {
check(name,null,"addNotificationListener");
super.addNotificationListener(name, listener, filter, handback); super.addNotificationListener(name, listener, filter, handback);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"addNotificationListener",name, throw handleIOException(ex,"addNotificationListener",name,
@ -363,6 +387,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
NotificationFilter filter, Object handback) NotificationFilter filter, Object handback)
throws InstanceNotFoundException { throws InstanceNotFoundException {
try { try {
check(name,null,"addNotificationListener");
super.addNotificationListener(name, listener, filter, handback); super.addNotificationListener(name, listener, filter, handback);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"addNotificationListener",name, throw handleIOException(ex,"addNotificationListener",name,
@ -385,6 +410,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
public void unregisterMBean(ObjectName name) public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException { throws InstanceNotFoundException, MBeanRegistrationException {
try { try {
check(name, null, "unregisterMBean");
super.unregisterMBean(name); super.unregisterMBean(name);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"unregisterMBean",name); throw handleIOException(ex,"unregisterMBean",name);
@ -397,6 +423,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
throws InstanceNotFoundException, IntrospectionException, throws InstanceNotFoundException, IntrospectionException,
ReflectionException { ReflectionException {
try { try {
check(name, null, "getMBeanInfo");
return super.getMBeanInfo(name); return super.getMBeanInfo(name);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"getMBeanInfo",name); throw handleIOException(ex,"getMBeanInfo",name);
@ -408,6 +435,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
public ObjectInstance getObjectInstance(ObjectName name) public ObjectInstance getObjectInstance(ObjectName name)
throws InstanceNotFoundException { throws InstanceNotFoundException {
try { try {
check(name, null, "getObjectInstance");
return super.getObjectInstance(name); return super.getObjectInstance(name);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"getObjectInstance",name); throw handleIOException(ex,"getObjectInstance",name);
@ -422,6 +450,8 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException { NotCompliantMBeanException {
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return super.createMBean(className, name, params, signature); return super.createMBean(className, name, params, signature);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"createMBean",className, name, throw handleIOException(ex,"createMBean",className, name,
@ -437,6 +467,8 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException, InstanceNotFoundException { NotCompliantMBeanException, InstanceNotFoundException {
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return super.createMBean(className, name, loaderName, params, return super.createMBean(className, name, loaderName, params,
signature); signature);
} catch (IOException ex) { } catch (IOException ex) {
@ -450,7 +482,9 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
public AttributeList setAttributes(ObjectName name,AttributeList attributes) public AttributeList setAttributes(ObjectName name,AttributeList attributes)
throws InstanceNotFoundException, ReflectionException { throws InstanceNotFoundException, ReflectionException {
try { try {
return super.setAttributes(name, attributes); final AttributeList authorized =
checkAttributes(name, attributes, "setAttribute");
return super.setAttributes(name, authorized);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"setAttributes",name, attributes); throw handleIOException(ex,"setAttributes",name, attributes);
} }
@ -462,6 +496,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
String[] signature) String[] signature)
throws InstanceNotFoundException, MBeanException, ReflectionException { throws InstanceNotFoundException, MBeanException, ReflectionException {
try { try {
check(name, operationName, "invoke");
return super.invoke(name, operationName, params, signature); return super.invoke(name, operationName, params, signature);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"invoke",name, operationName, throw handleIOException(ex,"invoke",name, operationName,
@ -582,4 +617,118 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
"Not supported in this namespace: "+namespace)); "Not supported in this namespace: "+namespace));
} }
/**
* A result might be excluded for security reasons.
*/
@Override
boolean excludesFromResult(ObjectName targetName, String queryMethod) {
return !checkQuery(targetName, queryMethod);
}
//----------------------------------------------------------------------
// Hooks for checking permissions
//----------------------------------------------------------------------
/**
* This method is a hook to implement permission checking in subclasses.
* A subclass may override this method and throw a {@link
* SecurityException} if the permission is denied.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param member The {@link
* javax.management.namespace.JMXNamespacePermission#getMember member}
* name.
* @param action The {@link
* javax.management.namespace.JMXNamespacePermission#getActions action}
* name.
* @throws SecurityException if the caller doesn't have the permission
* to perform the given action on the MBean pointed to
* by routingName.
*/
abstract void check(ObjectName routingName,
String member, String action);
// called in createMBean and registerMBean
abstract void checkCreate(ObjectName routingName, String className,
String action);
/**
* This is a hook to implement permission checking in subclasses.
*
* Checks that the caller has sufficient permission for returning
* information about {@code sourceName} in {@code action}.
*
* Subclass may override this method and return false if the caller
* doesn't have sufficient permissions.
*
* @param routingName The name of the MBean to include or exclude from
* the query, expressed in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param action one of "queryNames" or "queryMBeans"
* @return true if {@code sourceName} can be returned.
*/
abstract boolean checkQuery(ObjectName routingName, String action);
/**
* This method is a hook to implement permission checking in subclasses.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param attributes The list of attributes to check permission for.
* @param action one of "getAttribute" or "setAttribute"
* @return The list of attributes for which the callers has the
* appropriate {@link
* javax.management.namespace.JMXNamespacePermission}.
* @throws SecurityException if the caller doesn't have the permission
* to perform {@code action} on the MBean pointed to by routingName.
*/
abstract String[] checkAttributes(ObjectName routingName,
String[] attributes, String action);
/**
* This method is a hook to implement permission checking in subclasses.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param attributes The list of attributes to check permission for.
* @param action one of "getAttribute" or "setAttribute"
* @return The list of attributes for which the callers has the
* appropriate {@link
* javax.management.namespace.JMXNamespacePermission}.
* @throws SecurityException if the caller doesn't have the permission
* to perform {@code action} on the MBean pointed to by routingName.
*/
abstract AttributeList checkAttributes(ObjectName routingName,
AttributeList attributes, String action);
/**
* This method is a hook to implement permission checking in subclasses.
* Checks that the caller as the necessary permissions to view the
* given domain. If not remove the domains for which the caller doesn't
* have permission from the list.
* <p>
* By default, this method always returns {@code domains}
*
* @param domains The domains to return.
* @param action "getDomains"
* @return a filtered list of domains.
*/
String[] checkDomains(String[] domains, String action) {
return domains;
}
// A priori check for queryNames/queryMBeans/
void checkPattern(ObjectName routingPattern,
String member, String action) {
// pattern is checked only at posteriori by checkQuery.
// checking it a priori usually doesn't work, because ObjectName.apply
// does not work between two patterns.
// We only check that we have the permission requested for 'action'.
check(null,null,action);
}
} }

View file

@ -161,11 +161,7 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
throws InstanceNotFoundException, ReflectionException, IOException { throws InstanceNotFoundException, ReflectionException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
final String[] authorized = return source().getAttributes(sourceName, attributes);
checkAttributes(name,attributes,"getAttribute");
final AttributeList attrList =
source().getAttributes(sourceName,authorized);
return attrList;
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
} }
@ -178,7 +174,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
IOException { IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, operationName, "invoke");
final Object result = final Object result =
source().invoke(sourceName,operationName,params, source().invoke(sourceName,operationName,params,
signature); signature);
@ -194,7 +189,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
IOException { IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, null, "unregisterMBean");
source().unregisterMBean(sourceName); source().unregisterMBean(sourceName);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
@ -207,7 +201,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
ReflectionException, IOException { ReflectionException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, null, "getMBeanInfo");
return source().getMBeanInfo(sourceName); return source().getMBeanInfo(sourceName);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
@ -219,7 +212,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
throws InstanceNotFoundException, IOException { throws InstanceNotFoundException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, null, "getObjectInstance");
return processOutputInstance( return processOutputInstance(
source().getObjectInstance(sourceName)); source().getObjectInstance(sourceName));
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
@ -246,9 +238,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
ReflectionException, IOException { ReflectionException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name,
(attribute==null?null:attribute.getName()),
"setAttribute");
source().setAttribute(sourceName,attribute); source().setAttribute(sourceName,attribute);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
@ -266,8 +255,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
// Loader Name is already a sourceLoaderName. // Loader Name is already a sourceLoaderName.
final ObjectName sourceLoaderName = loaderName; final ObjectName sourceLoaderName = loaderName;
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
final ObjectInstance instance = final ObjectInstance instance =
source().createMBean(className,sourceName, source().createMBean(className,sourceName,
sourceLoaderName, sourceLoaderName,
@ -286,8 +273,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
NotCompliantMBeanException, IOException { NotCompliantMBeanException, IOException {
final ObjectName sourceName = newSourceMBeanName(name); final ObjectName sourceName = newSourceMBeanName(name);
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return processOutputInstance(source().createMBean(className, return processOutputInstance(source().createMBean(className,
sourceName,params,signature)); sourceName,params,signature));
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
@ -305,8 +290,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
// Loader Name is already a source Loader Name. // Loader Name is already a source Loader Name.
final ObjectName sourceLoaderName = loaderName; final ObjectName sourceLoaderName = loaderName;
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return processOutputInstance(source().createMBean(className, return processOutputInstance(source().createMBean(className,
sourceName,sourceLoaderName)); sourceName,sourceLoaderName));
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
@ -321,8 +304,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
NotCompliantMBeanException, IOException { NotCompliantMBeanException, IOException {
final ObjectName sourceName = newSourceMBeanName(name); final ObjectName sourceName = newSourceMBeanName(name);
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return processOutputInstance(source(). return processOutputInstance(source().
createMBean(className,sourceName)); createMBean(className,sourceName));
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
@ -336,7 +317,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
InstanceNotFoundException, ReflectionException, IOException { InstanceNotFoundException, ReflectionException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, attribute, "getAttribute");
return source().getAttribute(sourceName,attribute); return source().getAttribute(sourceName,attribute);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
@ -348,7 +328,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
throws InstanceNotFoundException, IOException { throws InstanceNotFoundException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, null, "isInstanceOf");
return source().isInstanceOf(sourceName,className); return source().isInstanceOf(sourceName,className);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
@ -360,10 +339,8 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
throws InstanceNotFoundException, ReflectionException, IOException { throws InstanceNotFoundException, ReflectionException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
final AttributeList authorized =
checkAttributes(name, attributes, "setAttribute");
return source(). return source().
setAttributes(sourceName,authorized); setAttributes(sourceName,attributes);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
} }
@ -376,7 +353,7 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
for (ObjectInstance i : sources) { for (ObjectInstance i : sources) {
try { try {
final ObjectInstance target = processOutputInstance(i); final ObjectInstance target = processOutputInstance(i);
if (!checkQuery(target.getObjectName(), "queryMBeans")) if (excludesFromResult(target.getObjectName(), "queryMBeans"))
continue; continue;
result.add(target); result.add(target);
} catch (Exception x) { } catch (Exception x) {
@ -415,7 +392,7 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
for (ObjectName n : sourceNames) { for (ObjectName n : sourceNames) {
try { try {
final ObjectName targetName = toTarget(n); final ObjectName targetName = toTarget(n);
if (!checkQuery(targetName, "queryNames")) continue; if (excludesFromResult(targetName, "queryNames")) continue;
names.add(targetName); names.add(targetName);
} catch (Exception x) { } catch (Exception x) {
if (LOG.isLoggable(Level.FINE)) { if (LOG.isLoggable(Level.FINE)) {
@ -435,7 +412,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
if (name == null) name=ObjectName.WILDCARD; if (name == null) name=ObjectName.WILDCARD;
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
checkPattern(name,null,"queryMBeans");
return processOutputInstances( return processOutputInstances(
source().queryMBeans(sourceName,query)); source().queryMBeans(sourceName,query));
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
@ -450,7 +426,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
if (name == null) name=ObjectName.WILDCARD; if (name == null) name=ObjectName.WILDCARD;
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
checkPattern(name,null,"queryNames");
final Set<ObjectName> tmp = source().queryNames(sourceName,query); final Set<ObjectName> tmp = source().queryNames(sourceName,query);
final Set<ObjectName> out = processOutputNames(tmp); final Set<ObjectName> out = processOutputNames(tmp);
//System.err.println("queryNames: out: "+out); //System.err.println("queryNames: out: "+out);
@ -467,7 +442,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
ListenerNotFoundException, IOException { ListenerNotFoundException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name,null,"removeNotificationListener");
source().removeNotificationListener(sourceName,listener); source().removeNotificationListener(sourceName,listener);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
@ -481,7 +455,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
// Listener name is already a source listener name. // Listener name is already a source listener name.
try { try {
check(name,null,"addNotificationListener");
source().addNotificationListener(sourceName,listener, source().addNotificationListener(sourceName,listener,
filter,handback); filter,handback);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
@ -495,7 +468,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
Object handback) throws InstanceNotFoundException, IOException { Object handback) throws InstanceNotFoundException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name,null,"addNotificationListener");
source().addNotificationListener(sourceName, listener, filter, source().addNotificationListener(sourceName, listener, filter,
handback); handback);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
@ -512,7 +484,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
IOException { IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name,null,"removeNotificationListener");
source().removeNotificationListener(sourceName,listener,filter, source().removeNotificationListener(sourceName,listener,filter,
handback); handback);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
@ -527,7 +498,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
IOException { IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name,null,"removeNotificationListener");
source().removeNotificationListener(sourceName,listener, source().removeNotificationListener(sourceName,listener,
filter,handback); filter,handback);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
@ -543,7 +513,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
// listener name is already a source name... // listener name is already a source name...
final ObjectName sourceListener = listener; final ObjectName sourceListener = listener;
try { try {
check(name,null,"removeNotificationListener");
source().removeNotificationListener(sourceName,sourceListener); source().removeNotificationListener(sourceName,sourceListener);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
@ -562,9 +531,7 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
// from MBeanServerConnection // from MBeanServerConnection
public String[] getDomains() throws IOException { public String[] getDomains() throws IOException {
try { try {
check(null,null,"getDomains"); return source().getDomains();
final String[] domains = source().getDomains();
return checkDomains(domains,"getDomains");
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
} }
@ -579,115 +546,22 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
} }
} }
//----------------------------------------------------------------------
// Hooks for checking permissions
//----------------------------------------------------------------------
/** /**
* This method is a hook to implement permission checking in subclasses. * Returns true if the given targetName must be excluded from the
* By default, this method does nothing and simply returns * query result.
* {@code attribute}. * In this base class, always return {@code false}.
* By default all object names returned by the sources are
* transmitted to the caller - there is no filtering.
* *
* @param routingName The name of the MBean in the enclosing context. * @param name A target object name expressed in the caller's
* This is of the form {@code <namespace>//<ObjectName>}. * context. In the case of cascading, where the source
* @param attributes The list of attributes to check permission for. * is a sub agent mounted on e.g. namespace "foo",
* @param action one of "getAttribute" or "setAttribute" * that would be a name prefixed by "foo//"...
* @return The list of attributes for which the callers has the * @param queryMethod either "queryNames" or "queryMBeans".
* appropriate {@link * @return true if the name must be excluded.
* javax.management.namespace.JMXNamespacePermission}.
*/ */
String[] checkAttributes(ObjectName routingName, boolean excludesFromResult(ObjectName targetName, String queryMethod) {
String[] attributes, String action) { return false;
check(routingName,null,action);
return attributes;
} }
/**
* This method is a hook to implement permission checking in subclasses.
* By default, this method does nothing and simply returns
* {@code attribute}.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param attributes The list of attributes to check permission for.
* @param action one of "getAttribute" or "setAttribute"
* @return The list of attributes for which the callers has the
* appropriate {@link
* javax.management.namespace.JMXNamespacePermission}.
*/
AttributeList checkAttributes(ObjectName routingName,
AttributeList attributes, String action) {
check(routingName,null,action);
return attributes;
}
/**
* This method is a hook to implement permission checking in subclasses.
* By default, this method does nothing.
* A subclass may override this method and throw a {@link
* SecurityException} if the permission is denied.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param member The {@link
* javax.management.namespace.JMXNamespacePermission#getMember member}
* name.
* @param action The {@link
* javax.management.namespace.JMXNamespacePermission#getActions action}
* name.
*/
void check(ObjectName routingName,
String member, String action) {
}
// called in createMBean and registerMBean
void checkCreate(ObjectName routingName, String className,
String action) {
}
// A priori check for queryNames/queryMBeans/
void checkPattern(ObjectName routingPattern,
String member, String action) {
// pattern is checked only at posteriori by checkQuery.
// checking it a priori usually doesn't work, because ObjectName.apply
// does not work between two patterns.
// We only check that we have the permission requested for 'action'.
check(null,null,action);
}
/**
* This is a hook to implement permission checking in subclasses.
*
* Checks that the caller has sufficient permission for returning
* information about {@code sourceName} in {@code action}.
*
* By default always return true. Subclass may override this method
* and return false if the caller doesn't have sufficient permissions.
*
* @param routingName The name of the MBean to include or exclude from
* the query, expressed in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param action one of "queryNames" or "queryMBeans"
* @return true if {@code sourceName} can be returned.
*/
boolean checkQuery(ObjectName routingName, String action) {
return true;
}
/**
* This method is a hook to implement permission checking in subclasses.
* Checks that the caller as the necessary permissions to view the
* given domain. If not remove the domains for which the caller doesn't
* have permission from the list.
* <p>
* By default, this method always returns {@code domains}
*
* @param domains The domains to return.
* @param action "getDomains"
* @return a filtered list of domains.
*/
String[] checkDomains(String[] domains, String action) {
return domains;
}
} }