User: stark
Date: 01/02/12 01:21:26
Added: security/src/main/org/jboss/ejb/plugins
SecurityInterceptor.java
Log:
Patches to the ejb container layer to suppor the security proxy model
Revision Changes Path
1.1
contrib/security/src/main/org/jboss/ejb/plugins/SecurityInterceptor.java
Index: SecurityInterceptor.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.ejb.plugins;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.rmi.RemoteException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.util.Iterator;
import java.util.Set;
import javax.ejb.EJBContext;
import javax.ejb.EntityContext;
import javax.ejb.SessionContext;
import javax.security.auth.Subject;
import org.jboss.ejb.Container;
import org.jboss.ejb.MethodInvocation;
import org.jboss.logging.Logger;
import org.jboss.security.EJBSecurityManager;
import org.jboss.security.RealmMapping;
import org.jboss.security.SecurityAssociation;
import org.jboss.security.SecurityPolicy;
import org.jboss.security.plugins.SubjectSecurityManager;
/** An alternate implementation of the EJB security interceptor that allows
for Subject based authorization checks via stateless and stateful proxy
instances. A stateless proxy is one which can perform its security checks
independent of the bean it is securing. A stateful proxy is one that needs
access to the bean it is securing. Maybe bean indepdendent and bean
dependent would be better names.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class SecurityInterceptor extends AbstractInterceptor
{
/**
* @clientCardinality 0..1
* @supplierCardinality 1
*/
protected Container container;
protected EJBSecurityManager securityManager;
protected RealmMapping realmMapping;
protected Object statelessSecurityProxy;
protected Object statefulSecurityProxy;
protected Method beanSetterMethod;
protected Method statefulContextSetterMethod;
protected Method statelessContextSetterMethod;
public SecurityInterceptor()
{
System.out.println("Created SecurityInterceptor[patch]");
}
public void setContainer(Container container)
{
this.container = container;
securityManager = container.getSecurityManager();
realmMapping = container.getRealmMapping();
statelessSecurityProxy = container.getStatelessSecurityProxy();
statefulSecurityProxy = container.getStatefulSecurityProxy();
statelessContextSetterMethod = findContextSetter(statelessSecurityProxy);
statefulContextSetterMethod = findContextSetter(statefulSecurityProxy);
beanSetterMethod = findBeanSetter(statefulSecurityProxy);
}
public Container getContainer()
{
return container;
}
// Container implementation --------------------------------------
public void start() throws Exception
{
super.start();
}
public Object invokeHome(MethodInvocation mi) throws Exception
{
// Apply any declarative security checks
checkSecurityAssociation( mi, true );
return getNext().invokeHome(mi);
}
public Object invoke(final MethodInvocation mi) throws Exception
{
// Authenticate the subject and pply any declarative security checks
checkSecurityAssociation(mi, false);
// Get the authenticated subject
SubjectSecurityManager subjectSecurityManager = (SubjectSecurityManager)
securityManager;
Subject subject = subjectSecurityManager.getActiveSubject();
// Perform any non-declarative security checks
System.out.println("SecurityInterceptor.invoke, s="+subject+",
slessp="+statelessSecurityProxy+", sfulp="+statefulSecurityProxy);
if( subject != null && (statelessSecurityProxy != null ||
statefulSecurityProxy != null) )
{
try
{
String domainName = subjectSecurityManager.getSecurityDomain();
SecurityPolicy.setActiveApp(domainName);
Subject.doAsPrivileged(subject, new PrivilegedExceptionAction()
{
public Object run() throws Exception
{
// Apply any stateless non-declarative security checks
if( statelessSecurityProxy != null )
checkStatelessSecurityProxy(mi);
// Apply any statelful non-declarative security checks
if( statefulSecurityProxy != null )
checkStatefulSecurityProxy(mi);
return null;
}
},
null
);
}
catch(PrivilegedActionException e)
{
throw e.getException();
}
}
// All security checks passed, allow the invocation
return getNext().invoke(mi);
}
private void checkSecurityAssociation(MethodInvocation mi, boolean home)
throws Exception
{
// if this isn't ok, bean shouldn't deploy
if (securityManager == null)
{
return;
}
if (realmMapping == null)
{
throw new RemoteException("checkSecurityAssociation", new
SecurityException("Role mapping manager has not been set"));
}
// Check the security info from the method invocation
Principal principal = mi.getPrincipal();
Object credential = mi.getCredential();
if( principal == null || !securityManager.isValid(principal, credential) )
{
Logger.error("Authentication exception, principal="+principal);
SecurityException e = new SecurityException("Authentication exception");
throw new RemoteException("checkSecurityAssociation", e);
}
else
{
SecurityAssociation.setPrincipal( principal );
SecurityAssociation.setCredential( credential );
}
Set methodRoles = container.getMethodPermissions(mi.getMethod(), home);
if( methodRoles != null && !realmMapping.doesUserHaveRole(principal,
methodRoles) )
{
Logger.error("Illegal access, principal="+principal);
SecurityException e = new SecurityException("Illegal access exception");
throw new RemoteException("checkSecurityAssociation", e);
}
}
private void checkStatelessSecurityProxy(MethodInvocation mi)
throws Exception
{
Method method = mi.getMethod();
Object[] args = mi.getArguments();
try
{
if( statelessContextSetterMethod != null )
{
Object[] ctx = { mi.getEnterpriseContext().getEJBContext() };
statelessContextSetterMethod.invoke(statelessSecurityProxy, ctx);
}
method.invoke(statelessSecurityProxy, args);
}
catch(InvocationTargetException e)
{
Throwable t = e.getTargetException();
if( t instanceof SecurityException )
throw new RemoteException("checkStatelessSecurity", t);
else if( t instanceof Exception )
throw (Exception) t;
throw new RemoteException("checkStatelessSecurity, unexpected
Throwable", t);
}
catch(UndeclaredThrowableException e)
{
Throwable t = e.getUndeclaredThrowable();
if( t instanceof SecurityException )
throw new RemoteException("checkStatelessSecurity", t);
else if( t instanceof Exception )
throw (Exception) t;
throw new RemoteException("checkStatelessSecurity, unexpected
Throwable", t);
}
}
private void checkStatefulSecurityProxy(MethodInvocation mi)
throws Exception
{
Method method = mi.getMethod();
Object[] args = mi.getArguments();
try
{
if( beanSetterMethod != null )
{ // Set the bean instance the proxy is securing
Object[] bean = { mi.getEnterpriseContext().getInstance() };
beanSetterMethod.invoke(statefulSecurityProxy, bean);
}
if( statefulContextSetterMethod != null )
{
Object[] ctx = { mi.getEnterpriseContext().getEJBContext() };
statefulContextSetterMethod.invoke(statefulSecurityProxy, ctx);
}
method.invoke(statefulSecurityProxy, args);
}
catch(InvocationTargetException e)
{
Throwable t = e.getTargetException();
if( t instanceof SecurityException )
throw new RemoteException("checkStatelessSecurity", t);
else if( t instanceof Exception )
throw (Exception) t;
throw new RemoteException("checkStatelessSecurity, unexpected
Throwable", t);
}
catch(UndeclaredThrowableException e)
{
Throwable t = e.getUndeclaredThrowable();
if( t instanceof SecurityException )
throw new RemoteException("checkStatelessSecurity", t);
else if( t instanceof Exception )
throw (Exception) t;
throw new RemoteException("checkStatelessSecurity, unexpected
Throwable", t);
}
}
private Method findContextSetter(Object proxy)
{
if( proxy == null )
return null;
Method m = null;
try
{ // Look for a setContext method that accepts the generic EJBContext
Class[] parameterTypes = {EJBContext.class};
m = proxy.getClass().getMethod("setContext", parameterTypes);
}
catch(Exception e)
{
}
if( m == null )
{
try
{ // Look for a setContext method that accepts a SessionContext
Class[] parameterTypes = {SessionContext.class};
m = proxy.getClass().getMethod("setContext", parameterTypes);
}
catch(Exception e)
{
}
}
if( m == null )
{
try
{ // Look for a setContext method that accepts a EntityContext
Class[] parameterTypes = {EntityContext.class};
m = proxy.getClass().getMethod("setContext", parameterTypes);
}
catch(Exception e)
{
}
}
return m;
}
private Method findBeanSetter(Object proxy)
{
if( proxy == null )
return null;
Method m = null;
try
{ // Look for a setBean method
Class[] parameterTypes = {Object.class};
m = statefulSecurityProxy.getClass().getMethod("setBean",
parameterTypes);
}
catch(Exception e)
{
Logger.exception(e);
}
return m;
}
}