Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Arquillian to test secure EJB

I am using JBoss 6.1 and I got a secure EJB having methods annotated with @RolesAllowed("Admin"). I am trying to test this method with Arquillian.

I have done the EJB log in successfully in the @Before of the test, however, it failed to invoke the method. From the TRACE log, I can see that the principal and roles are correct (in this case, 'myuser' and 'Admin'), but the secure EJB's method info is wrong (requiredRoles are empty).

TRACE [org.jboss.security.plugins.authorization.JBossAuthorizationContext] Control flag for entry:org.jboss.security.authorization.config.AuthorizationModuleEntry{org.jboss.security.authorization.modules.DelegatingAuthorizationModule:{}REQUIRED}is:[REQUIRED]
TRACE [org.jboss.security.authorization.modules.ejb.EJBPolicyModuleDelegate] method=public au.com.domain.DTOObject au.com.ejb.SecureServiceBean.save(au.com.domain.DTOObject), interface=Local, requiredRoles=Roles()
TRACE [org.jboss.security.authorization.modules.ejb.EJBPolicyModuleDelegate] Exception:Insufficient method permissions, principal=myuser, ejbName=SecureServiceBean, method=save, interface=Local, requiredRoles=Roles(), principalRoles=Roles(Admin,)

I was able to successfully invoke a method in the same EJB with @PermitAll.

I have looked for Arquillian documentation around secure EJB, but couldn't find any.

Many thanks for your help.

-- Linh

like image 590
Linh Avatar asked Nov 10 '11 00:11

Linh


2 Answers

In JBoss, the security system is not enabled on EJB3 beans if you have not set a <security-domain> value in jboss.xml. Here is a reminder for JBoss7 and it is also relevant for JBoss 6.1.

An alternate option is to use the proprietary annotation @org.jboss.ejb3.annotation.SecurityDomain with the proper domain value on your EJB3 beans.

According to this forum thread, a deployment descriptor WEB-INF/jboss-ejb3.xml is required when deploying EJBs in a WAR file and here is an example for it:

<?xml version="1.0"?>  
<jboss:ejb-jar
  xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
  xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:s="urn:security"
  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-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
  version="3.1"
  impl-version="2.0">
  <assembly-descriptor>
    <s:security>
      <ejb-name>*</ejb-name>
      <s:security-domain>yourSecurityDomain</s:security-domain>
    </s:security>
  </assembly-descriptor>
</jboss:ejb-jar>
like image 179
Yves Martin Avatar answered Oct 12 '22 12:10

Yves Martin


Thanks Yves Martin for the suggestion. I have tried adding the jboss.xml and ejb-jar.xml as you suggested, unfortunately it didn't work.

I examined the code again and again, and finally I have found a solution to this problem. My original code set up is as follow:

ObjectRepository interface:

public interface ObjectRepository<T extends DomainObject>
{
    public T save(T object);
    ...
}

TaskServiceBeanLocal interface:

@Local
public interface TaskServiceBeanLocal extends ObjectRepository<Task>
{
}

Task EJB:

@Stateless
@LocalBinding(jndiBinding = TaskServiceBean.LOOKUP_STRING)
@SecurityDomain(value = Security.DOMAIN)
@DeclareRoles({ Roles.ADMIN, Roles.CLERK, Roles.READ_ONLY })

//By default, allow no one access, we'll enable access at the method level
@RolesAllowed({})
public class TaskServiceBean implements TaskServiceBeanLocal
{
    public static final String LOOKUP_STRING = "TaskServiceBean/local";

    @RolesAllowed({ Roles.ADMIN, Roles.CLERK })
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public Task save(Task task)
    {
        ...
    }
}

The Arquillian failed to access the TaskServiceBean.save() method with the error as in the question:

TRACE [org.jboss.security.authorization.modules.ejb.EJBPolicyModuleDelegate] Exception:Insufficient method permissions, principal=myuser, ejbName=SecureServiceBean, method=save, interface=Local, requiredRoles=Roles(), principalRoles=Roles(Admin,)

From the TRACE logging, the requiredRoles() is empty for unknown reason. I tested by implementing a different method to the TaskServiceBeanLocal and the TaskServiceBean with the same permission:

@Local
public interface TaskServiceBeanLocal extends ObjectRepository<Task>
{
    public void test();
}

//and implement the test() method, having the same permission as the save() method.
public class TaskServiceBean implements TaskServiceBeanLocal
{
    @RolesAllowed({ Roles.ADMIN, Roles.CLERK })
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public Task save(Task task)
    {
        ...
    }

    @RolesAllowed({ Roles.ADMIN, Roles.CLERK })
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public void test()
    {
        System.out.println("hello");
    }
}

To my surprise, testing the test() method was successful. So I then redeclare the save() method in the interface:

@Local
public interface TaskServiceBeanLocal extends ObjectRepository<Task>
{
    public Task save(Task object);
    public void test();
}

Now, testing the save() method was successful. In the TRACE logging statement, I can see my requiredRoles are fully populated in the method signature.

13:44:35,399 TRACE [org.jboss.security.authorization.modules.ejb.EJBPolicyModuleDelegate] method=public au.com.infomedix.harvey.humantask.domain.Task au.com.infomedix.harvey.ejb.TaskServiceBean.save(au.com.infomedix.harvey.humantask.domain.Task), interface=Local, requiredRoles=Roles(Clerk,Admin,)

My guess is that Arquillian did not inject the security information for the generic method signature, but honestly I don't fully understand that.

Anyhow, re-declaring the method in the interface fixes the problem. Arquillian can access my secured EJB now. Thanks everyone for your valuable inputs.

-- Linh

like image 23
Linh Avatar answered Oct 12 '22 11:10

Linh