Hi,

EJB authentication and authorization, we define the principals, under which each method executes, by configuring the EJB deployment descriptor or using standard annotations like “javax.annotation.security.RolesAllowed”. The container enforces that the user, who is trying to execute the method, is the same as defined within the deployment descriptor or in the @RolesAllowed annotation.

In this example we will see how to define a EJB3 Security Domain using “org.jboss.ejb3.annotation.SecurityDomain” Annotation. This annotation adds container specific things inside the EJB code so it is not much recommended to use this annotation if yu don’t want to put any Application server specific feature inside your application code. So in the same example we will see how we can add the security-domain for our EJBs using the JBoss deployment descriptor “jboss.xml” file.

The most important thing we will see in this example on how to add the minimum number of required JARs in the classpath in of client to compile and run the EJB3 application in JBoss AS6.

Step1). Create a directory somewhere in your file system with some name like “C:/SecureEJB3.jar”.

Step2). Create a EJB interface with name “Calculator.java” like following inside directory “C:/SecureEJB3.jar”.

package ejb3;
import javax.ejb.Remote;
@Remote
public interface Calculator
{
   int add(int x, int y);
   int subtract(int x, int y);
   int divide(int x, int y);
}

Step3). Create a EJB Bean class with name “CalculatorBean.java” like following inside directory “C:/SecureEJB3.jar”.

package ejb3;
import javax.annotation.security.RolesAllowed;
import javax.ejb.*;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Remote;
import javax.annotation.Resource;
import java.security.Principal;
// import org.jboss.security.annotation.SecurityDomain;
// Above is not for EJB3 security so make sure that you are not using above SecurityDomain
import org.jboss.ejb3.annotation.SecurityDomain;

@SecurityDomain("EJBRollesAllowedPolicy")
@Stateless
public class CalculatorBean implements Calculator
{
   @Resource SessionContext ctx;
   @PermitAll
   @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
   public int add(int x, int y)
   {
      System.out.println("nntUnsecured method of CalculatorBean  add() called...sum="+(x+y));
      return x + y;
   }

   @RolesAllowed({"RoleOne"})
   public int subtract(int x, int y)
   {
     boolean callerInRole=ctx.isCallerInRole("RoleOne");
     System.out.println("nt isCallerInRole("RoleOne"): " + callerInRole);
     System.out.println("nnt CalculatorBean  subtract() called...substract="+(x-y));
     return x - y;
   }

   @RolesAllowed({"RoleTwo"})
   public int divide(int x, int y)
   {
      boolean callerInRole=ctx.isCallerInRole("RoleTwo");
      System.out.println("nt isCallerInRole("RoleTwo"): " + callerInRole);
      System.out.println("nnt CalculatorBean  divide() called...divide="+(x/y));
      return x / y;
   }
}

NOTE: If you dont want to use the “org.jboss.ejb3.annotation.SecurityDomain” annotation to define the Security-Domain for your EJB3 then we will need to add the jboss.xml file in order to define the security-domain. Which we will do in later steps.

Step4). Create a file “ejbapp-roles.properties” inside “C:/SecureEJB3.jar” directory to define the Roles for your EJB3 access, along with the role holder usernames like following:

userOne=RoleOne
userTwo=RoleTwo

Step5). Create a file “ejbapp-users.properties” inside “C:/SecureEJB3.jar” directory to define the passwords for your EJB3 access, along with the usernames like following:

userOne=userOnePassword
userTwo=userTwoPassword

Step6). If you have not defined the Security Domain for your EJB using Annotation “org.jboss.ejb3.annotation.SecurityDomain” inside your Bean class then we will need to provide the “jboss.xml” file like following inside “C:/SecureEJB3.jar/META-INF” directory.

<?xml version="1.0"?>
<jboss xmlns="http://www.jboss.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee
       http://www.jboss.org/j2ee/schema/jboss_5_0.xsd"
       version="3.0">

  <enterprise-beans>
      <session>
           <ejb-name>CalculatorBean</ejb-name>
           <jndi-name>CalculatorBean/remote</jndi-name>
           <security-domain>java:/jaas/EJBRollesAllowedPolicy</security-domain>
        </session>
     </enterprise-beans>
</jboss>

NOTE: In the above “jboss.xml” file you can define your own JNDI name for the EJBs by changing the jndi-name value for your Bean.

Step7). The most important part is to findout what all minimum number of jars are rewquired in order to compile and run theEJB3 application in JBoss AS6. So here we are going to use a very simple Shell Script to set the CLASSPATH to compile the above bean classes. Somewhere in your filesystem create a file like “setClasspath.sh” like following :

JBOSS_HOME=/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as
CLIENT_JARS_DIR=${JBOSS_HOME}/client
JAVA_HOME=/home/useroneMyJdks/jdk1.6.0_21

export PATH=${JAVA_HOME}/bin:${JBOSS_HOME}/bin:$PATH:

export CLASSPATH=

export CLASSPATH="${CLIENT_JARS_DIR}/jboss-logging-spi.jar:${CLIENT_JARS_DIR}/jnp-client.jar:${CLIENT_JARS_DIR}/jboss-ejb3-proxy-impl-client.jar:${CLIENT_JARS_DIR}/jboss-ejb3-common-client.jar:${CLIENT_JARS_DIR}/jboss-aspect-jdk50-client.jar:${CLIENT_JARS_DIR}/jboss-remoting.jar:${CLIENT_JARS_DIR}/jboss-aop-client.jar:${CLIENT_JARS_DIR}/jboss-common-core.jar:${CLIENT_JARS_DIR}/jboss-serialization.jar:${CLIENT_JARS_DIR}/jboss-ejb3-security-client.jar:${CLIENT_JARS_DIR}/jbosssx-client.jar:${CLIENT_JARS_DIR}/jboss-security-spi.jar:${CLIENT_JARS_DIR}/jboss-javaee.jar:${CLIENT_JARS_DIR}/ejb3-persistence.jar:${CLIENT_JARS_DIR}/jboss-ejb3-security-client.jar:${CLIENT_JARS_DIR}/jboss-ejb3-vfs-spi.jar:${CLIENT_JARS_DIR}/concurrent.jar:${CLIENT_JARS_DIR}/jboss-ejb3-proxy-spi-client.jar:${CLIENT_JARS_DIR}/jboss-ejb3-core-client.jar:${CLIENT_JARS_DIR}/jboss-integration.jar:${CLIENT_JARS_DIR}/jbosssx-as-client.jar:${CLIENT_JARS_DIR}/jboss-ejb3-ext-api.jar:.:"

echo "CLASSPATH=$CLASSPATH"

Similarly if you are using WINDOWS Operating system then you need to create a BAT file in order to set the CLASSPATH with minimum number of required jars as following: “setClasspath.bat”

JBOSS_HOME=C:/JBoss_All/jboss-AS6-5.1/jboss-as
CLIENT_JARS_DIR=%JBOSS_HOME%/client
JAVA_HOME=C:/MyJdks/jdk1.6.0_21

set PATH=%JAVA_HOME%/bin;%JBOSS_HOME%/bin;%PATH%;

set CLASSPATH=

set CLASSPATH="%CLIENT_JARS_DIR%/jboss-logging-spi.jar;%CLIENT_JARS_DIR%/jnp-client.jar;%CLIENT_JARS_DIR%/jboss-ejb3-proxy-impl-client.jar;%CLIENT_JARS_DIR%/jboss-ejb3-common-client.jar;%CLIENT_JARS_DIR%/jboss-aspect-jdk50-client.jar;%CLIENT_JARS_DIR%/jboss-remoting.jar;%CLIENT_JARS_DIR%/jboss-aop-client.jar;%CLIENT_JARS_DIR%/jboss-common-core.jar;%CLIENT_JARS_DIR%/jboss-serialization.jar;%CLIENT_JARS_DIR%/jboss-ejb3-security-client.jar;%CLIENT_JARS_DIR%/jbosssx-client.jar;%CLIENT_JARS_DIR%/jboss-security-spi.jar;%CLIENT_JARS_DIR%/jboss-javaee.jar;%CLIENT_JARS_DIR%/ejb3-persistence.jar;%CLIENT_JARS_DIR%/jboss-ejb3-security-client.jar;%CLIENT_JARS_DIR%/jboss-ejb3-vfs-spi.jar;%CLIENT_JARS_DIR%/concurrent.jar;%CLIENT_JARS_DIR%/jboss-ejb3-proxy-spi-client.jar;%CLIENT_JARS_DIR%/jboss-ejb3-core-client.jar;%CLIENT_JARS_DIR%/jboss-integration.jar;%CLIENT_JARS_DIR%/jbosssx-as-client.jar;%CLIENT_JARS_DIR%/jboss-ejb3-ext-api.jar;.;"

echo "CLASSPATH=%CLASSPATH%"

All you need to do is just change the JAVA_HOME and JBOSS_HOME values according to your file system location. then in a command/shell prompt run the script.
NOTE: If you are using Unix based operating system then make sure that you should run the setClasspath.sh script like following by putting an extra DOT (.) before the shell script path, the first DOT represents that set the Environment in the current Shell, AND the second ./ represents execute the script from the current directory:

[userone@localhost Test]$ . ./setClasspath.sh

CLASSPATH=/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-logging-spi.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jnp-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-ejb3-proxy-impl-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-ejb3-common-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-aspect-jdk50-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-remoting.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-aop-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-common-core.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-serialization.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-ejb3-security-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jbosssx-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-security-spi.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-javaee.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/ejb3-persistence.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-ejb3-security-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-ejb3-vfs-spi.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/concurrent.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-ejb3-proxy-spi-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-ejb3-core-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-integration.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jbosssx-as-client.jar:/home/userone/JBoss_All/jboss-AS6-5.1/jboss-as/client/jboss-ejb3-ext-api.jar:.:

Step8). Deploy the EJB application “SecureEJB3.jar” by placing it under “$PROFILE/deploy” directory.

Step9). Once the EJB is deployed we need to write the Client program in order to hit the EJB. So create a directory somewhere in your filesystem like “C:/SecureEJB_Client” and then paste the “ejb3/Calculator.class” inside “C:/SecureEJB_Client”. Because client requires that the Bean interface should be available at his end.
Now write the “Main.java” as following inside “C:/SecureEJB_Client” directory:

import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import ejb3.Calculator;
public class Main
{
   public static void main(String[] args) throws Exception
   {
      Properties env = new Properties();
      env.setProperty(Context.SECURITY_PRINCIPAL, "userTwo");
      env.setProperty(Context.SECURITY_CREDENTIALS, "userTwoPassword");
      //env.setProperty(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");  //----- DO NOT USE THIS-----
      env.setProperty(Context.INITIAL_CONTEXT_FACTORY,"org.jboss.security.jndi.JndiLoginInitialContextFactory");
      env.put(Context.PROVIDER_URL,"localhost:1099");
      InitialContext ctx = new InitialContext(env);

      Calculator calculator = (Calculator) ctx.lookup("CalculatorBean/remote");
      System.out.println("nt Got Calculator Referene After Lookup: "+calculator);

      ctx = new InitialContext(env);
      calculator = (Calculator) ctx.lookup("CalculatorBean/remote");
      System.out.println("nnt1 + 1 = " + calculator.add(1, 1));
      System.out.println("nntUser is is trying to invoke division  which is a Sceure Method...");
      try
      {
         int division=calculator.divide(16, 4);
         System.out.println("nntSecure Method  divide(16, 4) invoked and result is : "+division);
      }
      catch (Exception  ex)
      {
         System.out.println("nnt"+ex.getMessage());
         ex.printStackTrace();
      }
   }
}

Step10). Now compile and run the above Main.java with wrong userName and password. You will see the following kind of message if you will enter a wrong credential:

$ java Main
	 Got Calculator Referene After Lookup: Proxy to jboss.j2ee:jar=SecureEJB3.jar,name=CalculatorBean,service=EJB3 implementing [interface ejb3.Calculator]
	1 + 1 = 2
	User is is trying to invoke division  which is a Sceure Method...

	Caller unauthorized
javax.ejb.EJBAccessException: Caller unauthorized
	at org.jboss.ejb3.security.RoleBasedAuthorizationInterceptorv2.invoke(RoleBasedAuthorizationInterceptorv2.java:199)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.ejb3.security.Ejb3AuthenticationInterceptorv2.invoke(Ejb3AuthenticationInterceptorv2.java:182)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:41)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.ejb3.BlockContainerShutdownInterceptor.invoke(BlockContainerShutdownInterceptor.java:67)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.ejb3.core.context.CurrentInvocationContextInterceptor.invoke(CurrentInvocationContextInterceptor.java:47)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.aspects.currentinvocation.CurrentInvocationInterceptor.invoke(CurrentInvocationInterceptor.java:67)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.ejb3.interceptor.EJB3TCCLInterceptor.invoke(EJB3TCCLInterceptor.java:86)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:444)
	at org.jboss.ejb3.session.InvokableContextClassProxyHack._dynamicInvoke(InvokableContextClassProxyHack.java:53)
	at org.jboss.aop.Dispatcher.invoke(Dispatcher.java:91)
	at org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke(AOPRemotingInvocationHandler.java:82)
	at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:930)
	at org.jboss.remoting.transport.socket.ServerThread.completeInvocation(ServerThread.java:791)
	at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:744)
	at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:548)
	at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:234)
	at org.jboss.remoting.MicroRemoteClientInvoker.invoke(MicroRemoteClientInvoker.java:216)
	at org.jboss.remoting.Client.invoke(Client.java:2034)
	at org.jboss.remoting.Client.invoke(Client.java:877)
	at org.jboss.aspects.remoting.InvokeRemoteInterceptor.invoke(InvokeRemoteInterceptor.java:60)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.aspects.tx.ClientTxPropagationInterceptor.invoke(ClientTxPropagationInterceptor.java:61)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.ejb3.security.client.SecurityClientInterceptor.invoke(SecurityClientInterceptor.java:65)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:77)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.aspects.remoting.PojiProxy.invoke(PojiProxy.java:62)
	at $Proxy4.invoke(Unknown Source)
	at org.jboss.ejb3.proxy.impl.handler.session.SessionProxyInvocationHandlerBase.invoke(SessionProxyInvocationHandlerBase.java:188)
	at $Proxy2.divide(Unknown Source)
	at Main.main(Main.java:26)
	at org.jboss.aspects.remoting.InvokeRemoteInterceptor.invoke(InvokeRemoteInterceptor.java:72)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.aspects.tx.ClientTxPropagationInterceptor.invoke(ClientTxPropagationInterceptor.java:61)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.ejb3.security.client.SecurityClientInterceptor.invoke(SecurityClientInterceptor.java:65)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:77)
	at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
	at org.jboss.aspects.remoting.PojiProxy.invoke(PojiProxy.java:62)
	at $Proxy4.invoke(Unknown Source)
	at org.jboss.ejb3.proxy.impl.handler.session.SessionProxyInvocationHandlerBase.invoke(SessionProxyInvocationHandlerBase.java:188)
	at $Proxy2.divide(Unknown Source)
	at Main.main(Main.java:26)

But once you will enter right credentials you will be able to access the EJBs.
.
.
Thanks
Middleware Magic Team

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.