- We first create a User entity:
@Entity
public class User implements Serializable{
@Id
private Long id;
private String name;
private String email;
public User(){
}
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
//DON'T FORGET THE GETTERS AND SETTERS
//THIS RECIPE WON'T WORK WITHOUT THEM
}
- Here, we create a class to store our security roles:
public class Roles {
public static final String ADMIN = "ADMIN";
public static final String OPERATOR = "OPERATOR";
}
- Then, we create a stateful bean to manage our user operations:
@Stateful
public class UserBean {
@PersistenceContext(unitName = "ch01-security-pu",
type = PersistenceContextType.EXTENDED)
private EntityManager em;
@RolesAllowed({Roles.ADMIN, Roles.OPERATOR})
public void add(User user){
em.persist(user);
}
@RolesAllowed({Roles.ADMIN})
public void remove(User user){
em.remove(user);
}
@RolesAllowed({Roles.ADMIN})
public void update(User user){
em.merge(user);
}
@PermitAll
public List<User> get(){
Query q = em.createQuery("SELECT u FROM User as u ");
return q.getResultList();
}
- Now, we need to create an executor for each role:
public class RoleExecutor {
public interface Executable {
void execute() throws Exception;
}
@Stateless
@RunAs(Roles.ADMIN)
public static class AdminExecutor {
public void run(Executable executable) throws Exception {
executable.execute();
}
}
@Stateless
@RunAs(Roles.OPERATOR)
public static class OperatorExecutor {
public void run(Executable executable) throws Exception {
executable.execute();
}
}
}
- And finally, we create a test class to try our security rules.
Our code uses three test methods: asAdmin(), asOperator(), and asAnonymous().
- First, it tests asAdmin():
//Lot of setup code before this point
@Test
public void asAdmin() throws Exception {
adminExecutor.run(() -> {
userBean.add(new User(1L, "user1", "user1@user.com"));
userBean.add(new User(2L, "user2", "user2@user.com"));
userBean.add(new User(3L, "user3", "user3@user.com"));
userBean.add(new User(4L, "user4", "user4@user.com"));
List<User> list = userBean.get();
list.forEach((user) -> {
userBean.remove(user);
});
Assert.assertEquals("userBean.get()", 0,
userBean.get().size());
});
}
- Then it tests asOperator():
@Test
public void asOperator() throws Exception {
operatorExecutor.run(() -> {
userBean.add(new User(1L, "user1", "user1@user.com"));
userBean.add(new User(2L, "user2", "user2@user.com"));
userBean.add(new User(3L, "user3", "user3@user.com"));
userBean.add(new User(4L, "user4", "user4@user.com"));
List<User> list = userBean.get();
list.forEach((user) -> {
try {
userBean.remove(user);
Assert.fail("Operator was able to remove user " +
user.getName());
} catch (EJBAccessException e) {
}
});
Assert.assertEquals("userBean.get()", 4,
userBean.get().size());
});
}
- And, finally it tests asAnonymous():
@Test
public void asAnonymous() {
try {
userBean.add(new User(1L, "elder",
"elder@eldermoraes.com"));
Assert.fail("Anonymous user should not add users");
} catch (EJBAccessException e) {
}
try {
userBean.remove(new User(1L, "elder",
"elder@eldermoraes.com"));
Assert.fail("Anonymous user should not remove users");
} catch (EJBAccessException e) {
}
try {
userBean.get();
} catch (EJBAccessException e) {
Assert.fail("Everyone can list users");
}
}
This class is huge! For the full source code, check the link at the end of the recipe.