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