5 Replies Latest reply on Nov 17, 2005 10:41 AM by Ramil Israfilov

    Security, testing, and embbedable ejb3

    dunks80 Newbie

      I was wondering if anyone had a temporary work around for testing ejbs that have been annotated with the @SecurityDomain annotation from within the embbedable ejb container? I realize this task http://jira.jboss.com/jira/browse/EJBTHREE-291
      out on jira should hopefully implement security for embeddable ejb for the next RC. In the mean time I have a couple of stateless session beans that I've been holding off annotating with @SecurityDomain because I knew it would screw up my unit tests. But now I don't see anyway around using it and of course I still would like to unit test my beans.

        • 1. Re: Security, testing, and embbedable ejb3
          Kabir Khan Master

          In the ejb3-interceptors-aop.xml file that comes with the embedded distribution, you'll find a couple of occurrances of:

           <bind pointcut="execution(* @org.jboss.annotation.security.SecurityDomain->*(..))">
           <interceptor-ref name="org.jboss.ejb3.security.RoleBasedAuthorizationInterceptorFactory"/>
           </bind>
          


          Try commenting these out

          • 2. Re: Security, testing, and embbedable ejb3
            dunks80 Newbie

            Thanks Kabir! You totally pointed me in the right direction. I went ahead and extended the AuthernticationInterceptorFactory (and then bound it in the ejb3-interceptors-aop.xml file) to actualy create the jaas subcontext in the jndi tree and then place a custom authentication manager (extension of JaasAuthenticationManager) in it. In my baseTest i have a login function that calls my custom authentication service which my login module usually calls so that i can get back my custom principal. I push that principal onto the SubjectContext along with the password and now I can call my ejbs from within my test environment with all the security bells and whistles in place!

            • 3. Re: Security, testing, and embbedable ejb3
              Ramil Israfilov Newbie

              Hi dunks,
              Is it possible to share your code ? because I struggle with the same problem.
              Thanks

              • 4. Re: Security, testing, and embbedable ejb3
                dunks80 Newbie

                Yeah here you go. Hopefully this will work for you as well.


                import javax.naming.Context;
                import javax.naming.InitialContext;
                import javax.naming.NameAlreadyBoundException;
                import javax.naming.NamingException;
                import org.jboss.annotation.security.SecurityDomain;
                import org.jboss.aop.Advisor;
                import org.jboss.ejb3.Container;
                import org.jboss.ejb3.security.Ejb3AuthenticationInterceptor;
                import org.jboss.security.AuthenticationManager;
                
                
                /**
                 * A extension of jboss's standard AuthenticationInterceptorFactory which will created
                 * the jaas subcontext and bind a TestJaasAuthenticationManager in it.
                 *
                 * @author Galen Dunkleberger (galendunkleberger@gmail.com)
                 *
                 */
                public class AuthenticationInterceptorFactory extends org.jboss.ejb3.security.AuthenticationInterceptorFactory
                {
                 private boolean JAAS_BOUND=false;
                
                 public AuthenticationInterceptorFactory()
                 {
                 super();
                 }
                
                
                
                 @Override
                 public Object createPerClass(Advisor advisor)
                 {
                 Object domain=null;
                 try
                 {
                 Container container = (Container)advisor;
                 InitialContext ctx = container.getInitialContext();
                 SecurityDomain securityAnnotation = (SecurityDomain) advisor.resolveAnnotation(SecurityDomain.class);
                 if (securityAnnotation != null)
                 {
                 domain = new TestJaasAuthenticationManager(securityAnnotation.value(),new TestSecurityAssociationHandler());
                 try
                 {
                 if(!JAAS_BOUND)
                 {
                 Context jaas=ctx.createSubcontext("java:jaas");
                 jaas.bind("insight",domain);
                 JAAS_BOUND=true;
                 }
                 }
                 catch(NameAlreadyBoundException e){}
                 }
                 }
                 catch (NamingException e)
                 {
                 throw new RuntimeException(e);
                 }
                 AuthenticationManager manager = (AuthenticationManager) domain;
                 return new Ejb3AuthenticationInterceptor(manager);
                 }
                
                 @Override
                 public String getName()
                 {
                 return getClass().getName();
                 }
                
                
                }
                


                import java.io.Serializable;
                import org.jboss.security.plugins.JaasSecurityManager;
                import org.jboss.util.TimedCachePolicy;
                
                /**
                 * A extension of jboss's standard JaasSecurityManager it simply implements serialziable
                 * (because the jndi bind was complaining if i just tried to insert a normal JaasSecurityManager)
                 * and it's constuctor sets a new TimedCachePolicy
                 *
                 * @author Galen Dunkleberger (galendunkleberger@gmail.com)
                 *
                 */
                public class TestJaasAuthenticationManager extends JaasSecurityManager implements Serializable
                {
                
                 /**
                 *
                 */
                 private static final long serialVersionUID = 6677937424769496355L;
                
                
                 public TestJaasAuthenticationManager(String securityDomain, TestSecurityAssociationHandler handler)
                 {
                 super(securityDomain, handler);
                 TimedCachePolicy cachePolicy=new TimedCachePolicy();
                 cachePolicy.create();
                 cachePolicy.start();
                 setCachePolicy(cachePolicy);
                 }
                
                
                
                
                
                
                }
                


                import java.io.Serializable;
                import java.security.Principal;
                import org.jboss.security.auth.callback.SecurityAssociationHandler;
                /**
                 *
                 * A extension of jboss's standard SecurityAssociationHandler it simply implements serialziable
                 * (because the jndi bind or the TestJaasAuthenticationManager was complaining if i just tried to
                 * insert a TestJaasAuthenticationManager which took a normal SecurityAssociationHandler)
                
                 * @author Galen Dunkleberger (galendunkleberger@gmail.com)
                 *
                 *
                 */
                public class TestSecurityAssociationHandler extends SecurityAssociationHandler implements Serializable
                {
                 public TestSecurityAssociationHandler()
                 {
                 super();
                 }
                
                 public TestSecurityAssociationHandler(Principal principal, Object credential)
                 {
                 super(principal, credential);
                 }
                }
                


                I did not write this next class the source can be found in jboss head i simply made my version public so my base test class (in a differernt package) could access it.
                import java.lang.reflect.UndeclaredThrowableException;
                import java.security.AccessController;
                import java.security.Principal;
                import java.security.PrivilegedAction;
                import java.security.PrivilegedActionException;
                import java.security.PrivilegedExceptionAction;
                import javax.security.auth.Subject;
                import javax.security.jacc.PolicyContext;
                import javax.security.jacc.PolicyContextException;
                import org.jboss.logging.Logger;
                import org.jboss.security.RunAsIdentity;
                import org.jboss.security.SecurityAssociation;
                
                
                /** A collection of privileged actions for this package
                 * @author Scott.Stark@jboss.org
                 * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
                 * @version $Revison: $
                 */
                public class SecurityActions
                {
                 private static final Logger log = Logger.getLogger(SecurityActions.class);
                
                
                
                 interface PrincipalInfoAction
                 {
                 PrincipalInfoAction PRIVILEGED = new PrincipalInfoAction()
                 {
                 public void push(final Principal principal, final Object credential,
                 final Subject subject)
                 {
                 AccessController.doPrivileged(
                 new PrivilegedAction()
                 {
                 public Object run()
                 {
                 SecurityAssociation.pushSubjectContext(subject, principal, credential);
                 return null;
                 }
                 }
                 );
                 }
                 public void pop()
                 {
                 AccessController.doPrivileged(
                 new PrivilegedAction()
                 {
                 public Object run()
                 {
                 SecurityAssociation.popSubjectContext();
                 return null;
                 }
                 }
                 );
                 }
                
                 public Principal getPrincipal()
                 {
                 return (Principal)AccessController.doPrivileged(
                 new PrivilegedAction()
                 {
                 public Object run()
                 {
                 SecurityAssociation.getPrincipal();
                 return null;
                 }
                 }
                 );
                 }
                
                 public Object getCredential()
                 {
                 return AccessController.doPrivileged(
                 new PrivilegedAction()
                 {
                 public Object run()
                 {
                 SecurityAssociation.getCredential();
                 return null;
                 }
                 }
                 );
                 }
                
                
                 };
                
                 PrincipalInfoAction NON_PRIVILEGED = new PrincipalInfoAction()
                 {
                 public void push(Principal principal, Object credential, Subject subject)
                 {
                 SecurityAssociation.pushSubjectContext(subject, principal, credential);
                 }
                 public void pop()
                 {
                 SecurityAssociation.popSubjectContext();
                 }
                 public Principal getPrincipal()
                 {
                 return SecurityAssociation.getPrincipal();
                 }
                 public Object getCredential()
                 {
                 return SecurityAssociation.getCredential();
                 }
                 };
                
                 void push(Principal principal, Object credential, Subject subject);
                 void pop();
                 Principal getPrincipal();
                 Object getCredential();
                 }
                
                
                 interface RunAsIdentityActions
                 {
                 RunAsIdentityActions PRIVILEGED = new RunAsIdentityActions()
                 {
                 private final PrivilegedAction peekAction = new PrivilegedAction()
                 {
                 public Object run()
                 {
                 return SecurityAssociation.peekRunAsIdentity();
                 }
                 };
                
                 private final PrivilegedAction popAction = new PrivilegedAction()
                 {
                 public Object run()
                 {
                 return SecurityAssociation.popRunAsIdentity();
                 }
                 };
                
                 public RunAsIdentity peek()
                 {
                 return (RunAsIdentity)AccessController.doPrivileged(peekAction);
                 }
                
                 public void push(final RunAsIdentity id)
                 {
                 AccessController.doPrivileged(
                 new PrivilegedAction()
                 {
                 public Object run()
                 {
                 SecurityAssociation.pushRunAsIdentity(id);
                 return null;
                 }
                 }
                 );
                 }
                
                 public RunAsIdentity pop()
                 {
                 return (RunAsIdentity)AccessController.doPrivileged(popAction);
                 }
                 };
                
                 RunAsIdentityActions NON_PRIVILEGED = new RunAsIdentityActions()
                 {
                 public RunAsIdentity peek()
                 {
                 return SecurityAssociation.peekRunAsIdentity();
                 }
                
                 public void push(RunAsIdentity id)
                 {
                 SecurityAssociation.pushRunAsIdentity(id);
                 }
                
                 public RunAsIdentity pop()
                 {
                 return SecurityAssociation.popRunAsIdentity();
                 }
                 };
                
                 RunAsIdentity peek();
                
                 void push(RunAsIdentity id);
                
                 RunAsIdentity pop();
                 }
                
                 interface ContextInfoActions
                 {
                 static final String EX_KEY = "org.jboss.security.exception";
                 ContextInfoActions PRIVILEGED = new ContextInfoActions()
                 {
                 private final PrivilegedAction exAction = new PrivilegedAction()
                 {
                 public Object run()
                 {
                 return SecurityAssociation.getContextInfo(EX_KEY);
                 }
                 };
                 public Exception getContextException()
                 {
                 return (Exception)AccessController.doPrivileged(exAction);
                 }
                 };
                
                 ContextInfoActions NON_PRIVILEGED = new ContextInfoActions()
                 {
                 public Exception getContextException()
                 {
                 return (Exception)SecurityAssociation.getContextInfo(EX_KEY);
                 }
                 };
                
                 Exception getContextException();
                 }
                
                 interface PolicyContextActions
                 {
                 /** The JACC PolicyContext key for the current Subject */
                 static final String SUBJECT_CONTEXT_KEY = "javax.security.auth.Subject.container";
                 PolicyContextActions PRIVILEGED = new PolicyContextActions()
                 {
                 private final PrivilegedExceptionAction exAction = new PrivilegedExceptionAction()
                 {
                 public Object run() throws Exception
                 {
                 return (Subject) PolicyContext.getContext(SUBJECT_CONTEXT_KEY);
                 }
                 };
                 public Subject getContextSubject()
                 throws PolicyContextException
                 {
                 try
                 {
                 return (Subject) AccessController.doPrivileged(exAction);
                 }
                 catch(PrivilegedActionException e)
                 {
                 Exception ex = e.getException();
                 if( ex instanceof PolicyContextException )
                 throw (PolicyContextException) ex;
                 else
                 throw new UndeclaredThrowableException(ex);
                 }
                 }
                 };
                
                 PolicyContextActions NON_PRIVILEGED = new PolicyContextActions()
                 {
                 public Subject getContextSubject()
                 throws PolicyContextException
                 {
                 return (Subject) PolicyContext.getContext(SUBJECT_CONTEXT_KEY);
                 }
                 };
                
                 Subject getContextSubject()
                 throws PolicyContextException;
                 }
                
                 private static class SetServerAction implements PrivilegedAction
                 {
                 static PrivilegedAction ACTION = new SetServerAction();
                 public Object run()
                 {
                 SecurityAssociation.setServer();
                 return null;
                 }
                 }
                
                
                
                 public static Principal getPrincipal()
                 {
                 if (System.getSecurityManager() == null)
                 {
                 return PrincipalInfoAction.NON_PRIVILEGED.getPrincipal();
                 }
                 else
                 {
                 return PrincipalInfoAction.PRIVILEGED.getPrincipal();
                 }
                 }
                
                 public static void setServer()
                 {
                 AccessController.doPrivileged(SetServerAction.ACTION);
                 }
                
                 public static Object getCredential()
                 {
                 if (System.getSecurityManager() == null)
                 {
                 return PrincipalInfoAction.NON_PRIVILEGED.getCredential();
                 }
                 else
                 {
                 return PrincipalInfoAction.PRIVILEGED.getCredential();
                 }
                 }
                
                 public static void pushSubjectContext(Principal principal, Object credential,
                 Subject subject)
                 {
                 if(System.getSecurityManager() == null)
                 {
                 PrincipalInfoAction.NON_PRIVILEGED.push(principal, credential, subject);
                 }
                 else
                 {
                 PrincipalInfoAction.PRIVILEGED.push(principal, credential, subject);
                 }
                 }
                 public static void popSubjectContext()
                 {
                 if(System.getSecurityManager() == null)
                 {
                 PrincipalInfoAction.NON_PRIVILEGED.pop();
                 }
                 else
                 {
                 PrincipalInfoAction.PRIVILEGED.pop();
                 }
                 }
                
                 public static RunAsIdentity peekRunAsIdentity()
                 {
                 if(System.getSecurityManager() == null)
                 {
                 return RunAsIdentityActions.NON_PRIVILEGED.peek();
                 }
                 else
                 {
                 return RunAsIdentityActions.PRIVILEGED.peek();
                 }
                 }
                
                 public static void pushRunAsIdentity(RunAsIdentity principal)
                 {
                 if(System.getSecurityManager() == null)
                 {
                 RunAsIdentityActions.NON_PRIVILEGED.push(principal);
                 }
                 else
                 {
                 RunAsIdentityActions.PRIVILEGED.push(principal);
                 }
                 }
                
                 public static RunAsIdentity popRunAsIdentity()
                 {
                 if(System.getSecurityManager() == null)
                 {
                 return RunAsIdentityActions.NON_PRIVILEGED.pop();
                 }
                 else
                 {
                 return RunAsIdentityActions.PRIVILEGED.pop();
                 }
                 }
                
                 public static Exception getContextException()
                 {
                 if(System.getSecurityManager() == null)
                 {
                 return ContextInfoActions.NON_PRIVILEGED.getContextException();
                 }
                 else
                 {
                 return ContextInfoActions.PRIVILEGED.getContextException();
                 }
                 }
                
                 public static Subject getContextSubject()
                 throws PolicyContextException
                 {
                 if(System.getSecurityManager() == null)
                 {
                 return PolicyContextActions.NON_PRIVILEGED.getContextSubject();
                 }
                 else
                 {
                 return PolicyContextActions.PRIVILEGED.getContextSubject();
                 }
                 }
                
                
                }
                


                Then for the actual call my login method in my base test class looks like this....

                protected void login(String username,String password)throws Exception
                 {
                 Principal user=/*I make a call to a custom service that my login module usually calls to get the custom principal. You could do the same or build your custom principal manually, or just use SimplePrincipal*/
                 SecurityActions.setServer();
                 SecurityActions.pushSubjectContext(user,password,null);
                
                 }
                


                Now to get embeddable ejb to use this I had to include and auth.conf file in the classpath when i ran my tests and poin tto that file using this jvm arg

                -Djava.security.auth.login.config


                Here is what my auth.conf file sorta looks like
                yousecuritydomain{
                [any_custom_login_modules sufficient;]
                org.jboss.security.auth.spi.IdentityLoginModule required;
                };
                


                Hope that helps it's been working great for me.

                • 5. Re: Security, testing, and embbedable ejb3
                  Ramil Israfilov Newbie

                  Thanks dunks !
                  It works perfectly for me.