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.test.jmx.interceptors;
023:
024: import java.security.Principal;
025: import java.lang.reflect.Method;
026: import java.util.HashSet;
027: import java.util.Map;
028: import javax.naming.InitialContext;
029: import javax.security.auth.Subject;
030:
031: import org.jboss.mx.interceptor.AbstractInterceptor;
032: import org.jboss.mx.server.Invocation;
033: import org.jboss.mx.server.MBeanInvoker;
034: import org.jboss.logging.Logger;
035: import org.jboss.security.RealmMapping;
036: import org.jboss.security.SubjectSecurityManager;
037: import org.jboss.security.SimplePrincipal;
038: import org.jboss.security.SecurityAssociation;
039: import org.jboss.invocation.MarshalledInvocation;
040:
041: /** A role based security interceptor that requries the caller of
042: * any write operations to have a JNDIWriter role and the caller of any
043: * read operations to have a JNDIReader role.
044: *
045: * @author Scott.Stark@jboss.org
046: * @version $Revision: 57211 $
047: */
048: public final class JNDISecurity extends AbstractInterceptor {
049: private static Logger log = Logger.getLogger(JNDISecurity.class);
050: private static final Principal READER_ROLE = new SimplePrincipal(
051: "JNDIReader");
052: private static final Principal WRITER_ROLE = new SimplePrincipal(
053: "JNDIWriter");
054:
055: private String securityDomain;
056: private SubjectSecurityManager authMgr;
057: private RealmMapping roleMgr;
058: private Map methodMap;
059:
060: public String getSecurityDomain() {
061: return securityDomain;
062: }
063:
064: public void setSecurityDomain(String securityDomain)
065: throws Exception {
066: log.info("setSecurityDomain: " + securityDomain);
067: this .securityDomain = securityDomain;
068: InitialContext ctx = new InitialContext();
069: this .authMgr = (SubjectSecurityManager) ctx
070: .lookup(securityDomain);
071: this .roleMgr = (RealmMapping) ctx.lookup(securityDomain);
072: }
073:
074: // Interceptor overrides -----------------------------------------
075: public Object invoke(Invocation invocation) throws Throwable {
076: String opName = invocation.getName();
077: log.info("invoke, opName=" + opName);
078:
079: // If this is not the invoke(Invocation) op just pass it along
080: if (opName == null || opName.equals("invoke") == false)
081: return invocation.nextInterceptor().invoke(invocation);
082:
083: Object[] args = invocation.getArgs();
084: org.jboss.invocation.Invocation invokeInfo = (org.jboss.invocation.Invocation) args[0];
085: // There must be a valid security manager
086: if (authMgr == null || roleMgr == null) {
087: String msg = "No security mgr configured, check securityDomain: "
088: + securityDomain;
089: throw new SecurityException(msg);
090: }
091:
092: // Get the security context passed from the client
093: Principal principal = invokeInfo.getPrincipal();
094: Object credential = invokeInfo.getCredential();
095: Subject subject = new Subject();
096: if (authMgr.isValid(principal, credential, subject) == false) {
097: String msg = "Failed to authenticate principal: "
098: + principal;
099: throw new SecurityException(msg);
100: }
101: SecurityAssociation.pushSubjectContext(subject, principal,
102: credential);
103:
104: try {
105: // See what operation is being attempted
106: if (methodMap == null)
107: initMethodMap(invocation);
108: HashSet methodRoles = new HashSet();
109: if (invokeInfo instanceof MarshalledInvocation) {
110: MarshalledInvocation mi = (MarshalledInvocation) invokeInfo;
111: mi.setMethodMap(methodMap);
112: }
113: Method method = invokeInfo.getMethod();
114: boolean isRead = isReadMethod(method);
115: if (isRead == true)
116: methodRoles.add(READER_ROLE);
117: else
118: methodRoles.add(WRITER_ROLE);
119: if (roleMgr.doesUserHaveRole(principal, methodRoles) == false) {
120: String msg = "Failed to authorize subject: "
121: + authMgr.getActiveSubject() + " principal: "
122: + principal + " for access roles:"
123: + methodRoles;
124: throw new SecurityException(msg);
125: }
126:
127: // Let the invocation go
128: return invocation.nextInterceptor().invoke(invocation);
129: } finally {
130: SecurityAssociation.popSubjectContext();
131: }
132: }
133:
134: private boolean isReadMethod(Method method) {
135: boolean isRead = true;
136: String name = method.getName();
137: isRead = name.equals("lookup") || name.equals("list")
138: || name.equals("listBindings");
139: return isRead;
140: }
141:
142: /**
143: *
144: */
145: private void initMethodMap(Invocation invocation) throws Throwable {
146: MBeanInvoker invoker = invocation.getInvoker();
147: methodMap = (Map) invoker.getAttribute("MethodMap");
148: }
149: }
|