JmxAuthorizeContext.java
package com.ziesemer.utils.jmx.server.authorization;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.util.Set;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXPrincipal;
import javax.security.auth.Subject;
/**
* <p>Used by {@link BaseJmxAuthorizer}.</p>
* @author Mark A. Ziesemer
* <a href="http://www.ziesemer.com."><www.ziesemer.com></a>
*/
public class JmxAuthorizeContext{
public final MBeanServer mBeanServer;
public final Object proxy;
public final Method method;
public final Object[] args;
public Object customContext;
// These values are cached for performance.
protected boolean subjectLoaded;
protected Subject subject;
protected boolean principalLoaded;
protected JMXPrincipal principal;
protected Integer impact;
public JmxAuthorizeContext(final MBeanServer mBeanServer,
final Object proxy, final Method method, final Object[] args){
this.mBeanServer = mBeanServer;
this.proxy = proxy;
this.method = method;
this.args = args;
}
/**
* <p>Returns the cached or current {@link Subject} from {@link AccessController#getContext()}.
* May be null.</p>
*/
public Subject getSubject(){
if(!subjectLoaded){
subject = Subject.getSubject(AccessController.getContext());
subjectLoaded = true;
}
return subject;
}
/**
* <p>Returns the cached or current {@link JMXPrincipal} from {@link #getSubject()}.
* May be null.</p>
*/
public JMXPrincipal getPrincipal(){
if(!principalLoaded){
final Subject subject = getSubject();
if(subject != null){
final Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
if(principals == null || principals.isEmpty()){
throw new SecurityException("Access denied (principal)");
}
principal = principals.iterator().next();
principalLoaded = true;
}
}
return principal;
}
/**
* <p>Returns the cached or current {@link MBeanOperationInfo#getImpact()}
* for the current operation.</p>
* @throws UnsupportedOperationException If the current call is not a call to
* {@link MBeanServer#invoke(ObjectName, String, Object[], String[])}.
*/
public int getImpact() throws Exception{
if(!"invoke".equals(method.getName())){
throw new UnsupportedOperationException("getImpact only applicable for invoke operations.");
}
if(impact != null){
return impact;
}
final ObjectName on = (ObjectName)args[0];
final String methodName = (String)args[1];
// Actual values are stored in [2].
final String[] methodSig = (String[])args[3];
final MBeanInfo mbi = mBeanServer.getMBeanInfo(on);
for(final MBeanOperationInfo oi : mbi.getOperations()){
if(methodName.equals(oi.getName())){
final MBeanParameterInfo[] sig = oi.getSignature();
if(methodSig.length == sig.length){
boolean match = true;
for(int i=0; i < methodSig.length && match; i++){
match = methodSig[i].equals(sig[i].getType());
}
if(match){
return (impact = oi.getImpact());
}
}
}
}
return (impact = MBeanOperationInfo.UNKNOWN);
}
public Object invoke() throws Throwable{
return method.invoke(mBeanServer, args);
}
}