001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.jmx.connector.invoker;
023:
024: import java.lang.reflect.InvocationTargetException;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.UndeclaredThrowableException;
027: import java.security.Principal;
028:
029: import javax.management.Attribute;
030: import javax.management.ObjectName;
031: import javax.security.auth.Subject;
032:
033: import org.jboss.mx.interceptor.AbstractInterceptor;
034: import org.jboss.mx.interceptor.Interceptor;
035: import org.jboss.mx.server.Invocation;
036:
037: /**
038: * An Interceptor that aids in providing Authorization to JMX Invocations
039: * at an MBean Operations level. This must be placed after the
040: * AuthenticationInterceptor to ensure a valid caller context exists
041: *
042: * String msg = "Define your own class which has a method authorize with signature";
043: msg += "public void authorize( Principal caller, Subject subject,
044: String objectname,String opname)";
045: msg += ". And replace " + azclassname + " its name";
046:
047: * @see AuthenticationInterceptor
048: *
049: * @author <mailto:Anil.Saldhana@jboss.org>Anil Saldhana
050: * @author Scott.Stark@jboss.org
051: * @version $Revision: 61376 $
052: */
053: public class AuthorizationInterceptor extends AbstractInterceptor {
054: protected Object authenticator = null;
055: protected Method authorize;
056:
057: public final static String ATTRIBUTE_SET = "SetAttribute";
058:
059: public AuthorizationInterceptor() {
060: super ();
061: // Install the default
062: try {
063: setAuthorizingClass(RolesAuthorization.class);
064: } catch (Exception e) {
065: // Can't happen
066: }
067: }
068:
069: /**
070: * The Authorizing class must have a method called
071: * public Boolean authorize( Principal caller, String mbean,String opname )
072: *
073: * @param clazz
074: */
075: public void setAuthorizingClass(Class clazz) throws Exception {
076: authenticator = clazz.newInstance();
077: log.debug("Loaded authenticator: " + authenticator);
078: Class[] sig = { Principal.class, Subject.class, String.class,
079: String.class };
080: authorize = clazz.getMethod("authorize", sig);
081: log
082: .debug("Found authorize(Principal, Subject, String, String)");
083: }
084:
085: /**
086: * Intercept the invoke(Invocation) operations
087: * @param invocation
088: * @return
089: * @throws Throwable
090: */
091: public Object invoke(Invocation invocation) throws Throwable {
092: String type = invocation.getType();
093: if (type == Invocation.OP_INVOKE) {
094: String opName = invocation.getName();
095: if (opName.equals("invoke")) {
096: Object[] args = invocation.getArgs();
097: org.jboss.invocation.Invocation inv = (org.jboss.invocation.Invocation) args[0];
098: // Authenticate the caller based on the security association
099: Principal caller = inv.getPrincipal();
100: //Get the Method Name
101: Object[] obj = inv.getArguments();
102: //Ignore calls like MBeanCount or getMBeanInfo
103: if (obj != null && obj.length > 1) {
104: ObjectName objname = (ObjectName) obj[0];
105: String opname = null;
106: Object ob = obj[1];
107:
108: if (ob instanceof String)
109: opname = (String) ob;
110: else if (ob instanceof Attribute)
111: opname = ATTRIBUTE_SET;
112: else
113: throw new IllegalArgumentException(
114: "Opname type not recognized");
115:
116: try {
117: checkAuthorization(caller, objname
118: .getCanonicalName(), opname);
119: } catch (SecurityException e) {
120: throw e;
121: } catch (Exception e) {
122: String msg = "Failed to authorize principal="
123: + caller + ",MBean=" + objname
124: + ", Operation=" + opname;
125: SecurityException ex = new SecurityException(
126: msg);
127: ex.initCause(e);
128: throw ex;
129: }
130: }
131: }
132: }
133:
134: Interceptor i = invocation.nextInterceptor();
135: return i.invoke(invocation);
136: }
137:
138: /**
139: * Method that delegates authorization to the custom class
140: *
141: * @param caller
142: * @param objname
143: * @param opname
144: * @throws Exception - A SecurityException on authorization failure
145: */
146: private void checkAuthorization(Principal caller, String objname,
147: String opname) throws Exception {
148: // Get the active Subject
149: Subject subject = SecurityActions.getActiveSubject();
150: if (subject == null)
151: throw new SecurityException(
152: "No active Subject found, add the AuthenticationInterceptor");
153:
154: if (log.isTraceEnabled())
155: log.trace("[checkAuthorization:caller=" + caller
156: + ":subject=" + subject + "]");
157:
158: //We will try to use the authorizing class
159: try {
160: Object[] args = { caller, subject, objname, opname };
161: authorize.invoke(authenticator, args);
162: } catch (InvocationTargetException e) {
163: Throwable t = e.getTargetException();
164: if (t instanceof Exception)
165: throw (Exception) t;
166: else
167: throw new UndeclaredThrowableException(t);
168: }
169: if (log.isTraceEnabled())
170: log.trace("[checkAuthorization:Authorization passed]");
171: }
172: }
|