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;
      }
  }
  
  
  

Reply via email to