/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.jmx.interceptors;
import java.security.Principal;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import javax.naming.InitialContext;
import javax.security.auth.Subject;
import org.jboss.mx.interceptor.AbstractInterceptor;
import org.jboss.mx.server.Invocation;
import org.jboss.mx.server.MBeanInvoker;
import org.jboss.logging.Logger;
import org.jboss.security.RealmMapping;
import org.jboss.security.SubjectSecurityManager;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.SecurityAssociation;
import org.jboss.invocation.MarshalledInvocation;
/** A role based security interceptor that requries the caller of
* any write operations to have a JNDIWriter role and the caller of any
* read operations to have a JNDIReader role.
*
* @author Scott.Stark@jboss.org
* @version $Revision: 81036 $
*/
public final class JNDISecurity
extends AbstractInterceptor
{
private static Logger log = Logger.getLogger(JNDISecurity.class);
private static final Principal READER_ROLE = new SimplePrincipal("JNDIReader");
private static final Principal WRITER_ROLE = new SimplePrincipal("JNDIWriter");
private String securityDomain;
private SubjectSecurityManager authMgr;
private RealmMapping roleMgr;
private Map methodMap;
public String getSecurityDomain()
{
return securityDomain;
}
public void setSecurityDomain(String securityDomain) throws Exception
{
log.info("setSecurityDomain: "+securityDomain);
this.securityDomain = securityDomain;
InitialContext ctx = new InitialContext();
this.authMgr = (SubjectSecurityManager) ctx.lookup(securityDomain);
this.roleMgr = (RealmMapping) ctx.lookup(securityDomain);
}
// Interceptor overrides -----------------------------------------
public Object invoke(Invocation invocation) throws Throwable
{
String opName = invocation.getName();
log.info("invoke, opName="+opName);
// If this is not the invoke(Invocation) op just pass it along
if( opName == null || opName.equals("invoke") == false )
return invocation.nextInterceptor().invoke(invocation);
Object[] args = invocation.getArgs();
org.jboss.invocation.Invocation invokeInfo =
(org.jboss.invocation.Invocation) args[0];
// There must be a valid security manager
if( authMgr == null || roleMgr == null )
{
String msg = "No security mgr configured, check securityDomain: "+securityDomain;
throw new SecurityException(msg);
}
// Get the security context passed from the client
Principal principal = invokeInfo.getPrincipal();
Object credential = invokeInfo.getCredential();
Subject subject = new Subject();
if( authMgr.isValid(principal, credential, subject) == false )
{
String msg = "Failed to authenticate principal: "+principal;
throw new SecurityException(msg);
}
SecurityAssociation.pushSubjectContext(subject, principal, credential);
try
{
// See what operation is being attempted
if( methodMap == null )
initMethodMap(invocation);
HashSet methodRoles = new HashSet();
if( invokeInfo instanceof MarshalledInvocation )
{
MarshalledInvocation mi = (MarshalledInvocation) invokeInfo;
mi.setMethodMap(methodMap);
}
Method method = invokeInfo.getMethod();
boolean isRead = isReadMethod(method);
if( isRead == true )
methodRoles.add(READER_ROLE);
else
methodRoles.add(WRITER_ROLE);
if( roleMgr.doesUserHaveRole(principal, methodRoles) == false )
{
String msg = "Failed to authorize subject: "+authMgr.getActiveSubject()
+ " principal: " + principal
+ " for access roles:" + methodRoles;
throw new SecurityException(msg);
}
// Let the invocation go
return invocation.nextInterceptor().invoke(invocation);
}
finally
{
SecurityAssociation.popSubjectContext();
}
}
private boolean isReadMethod(Method method)
{
boolean isRead = true;
String name = method.getName();
isRead = name.equals("lookup") || name.equals("list")
|| name.equals("listBindings");
return isRead;
}
/**
*
*/
private void initMethodMap(Invocation invocation) throws Throwable
{
MBeanInvoker invoker = invocation.getInvoker();
methodMap = (Map) invoker.getAttribute("MethodMap");
}
}