Documentation

EJB 3.0

Deployment

Configuration

Commands

Feeds

 

Overview

Builds upon the Injection of EntityManager Example but adds the use of @RolesAllowed and @PermitAll in the @Stateful bean to restrict who can perform create, persist and remove operations on the EntityManager. Shows a TestCase using the @RunAs annotation to execute and test the bean code as various users.

In this example we restrict the ability to create Movie Entities to a Manager or an Employee. Reads are open to anyone, logged in or not. And delete operations are only allowed by a Manager.

See the Security Annotations page for a full description of how the security annotations work.

The source for this example is in the "testing-security" directory located in the openejb-examples.zip available on the download page.

The Code

Just as with the Testing Transactions Example the magic of this unit test is in the ManagerBean and EmployeeBean @Stateless beans that we've tucked into our TestCase as inner classes. These beans allow us to execute our test code as either a Manager or as an Employee and test that Movies @Stateful bean is setup to restrict and permit calls according to our intended design.

import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;
import java.util.List;

@Stateful(name = "Movies")
public class MoviesImpl implements Movies {

    @PersistenceContext(unitName = "movie-unit", type = PersistenceContextType.EXTENDED)
    private EntityManager entityManager;

    @RolesAllowed({"Employee", "Manager"})
    public void addMovie(Movie movie) throws Exception {
        entityManager.persist(movie);
    }

    @RolesAllowed({"Manager"})
    public void deleteMovie(Movie movie) throws Exception {
        entityManager.remove(movie);
    }

    @PermitAll
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public List<Movie> getMovies() throws Exception {
        Query query = entityManager.createQuery("SELECT m from Movie as m");
        return query.getResultList();
    }
}

Writing a unit test for the example

public class MovieTest extends TestCase {
    private Context context;

    protected void setUp() throws Exception {
        Properties p = new Properties();
        p.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
        p.put("movieDatabase", "new://Resource?type=DataSource");
        p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
        p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");

        p.put("movieDatabaseUnmanaged", "new://Resource?type=DataSource");
        p.put("movieDatabaseUnmanaged.JdbcDriver", "org.hsqldb.jdbcDriver");
        p.put("movieDatabaseUnmanaged.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
        p.put("movieDatabaseUnmanaged.JtaManaged", "false");

        context = new InitialContext(p);
    }

    public void testAsManager() throws Exception {
        Caller managerBean = (Caller) context.lookup("ManagerBeanLocal");
        managerBean.call(new Callable() {
            public Object call() throws Exception {

                Movies movies = (Movies) context.lookup("MoviesLocal");

                movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
                movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
                movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));

                List<Movie> list = movies.getMovies();
                assertEquals("List.size()", 3, list.size());

                for (Movie movie : list) {
                    movies.deleteMovie(movie);
                }

                assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
                return null;
            }
        });
    }

    public void testAsEmployee() throws Exception {
        Caller employeeBean = (Caller) context.lookup("EmployeeBeanLocal");
        employeeBean.call(new Callable() {
            public Object call() throws Exception {
                Movies movies = (Movies) context.lookup("MoviesLocal");

                movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
                movies.addMovie(new Movie("Joel Coen", "Fargo", 1996));
                movies.addMovie(new Movie("Joel Coen", "The Big Lebowski", 1998));

                List<Movie> list = movies.getMovies();
                assertEquals("List.size()", 3, list.size());

                for (Movie movie : list) {
                    try {
                        movies.deleteMovie(movie);
                        fail("Employees should not be allowed to delete");
                    } catch (EJBAccessException e) {
                        // Good, Employees cannot delete things
                    }
                }

                // The list should still be three movies long
                assertEquals("Movies.getMovies()", 3, movies.getMovies().size());
                return null;
            }
        });
    }

    public void testUnauthenticated() throws Exception {
        Movies movies = (Movies) context.lookup("MoviesLocal");

        try {
            movies.addMovie(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
            fail("Unauthenticated users should not be able to add movies");
        } catch (EJBAccessException e) {
            // Good, guests cannot add things
        }

        try {
            movies.deleteMovie(null);
            fail("Unauthenticated users should not be allowed to delete");
        } catch (EJBAccessException e) {
            // Good, Unauthenticated users cannot delete things
        }

        try {
            // Read access should be allowed

            List<Movie> list = movies.getMovies();

        } catch (EJBAccessException e) {
            fail("Read access should be allowed");
        }

    }


    public static interface Caller {
        public <V> V call(Callable<V> callable) throws Exception;
    }

    /**
     * This little bit of magic allows our test code to execute in
     * the desired security scope.
     * <p/>
     * The src/test/resource/META-INF/ejb-jar.xml will cause this
     * EJB to be automatically discovered and deployed when
     * OpenEJB boots up.
     */

    @Stateless
    @RunAs("Manager")
    public static class ManagerBean implements Caller {

        public <V> V call(Callable<V> callable) throws Exception {
            return callable.call();
        }

    }

    @Stateless
    @RunAs("Employee")
    public static class EmployeeBean implements Caller {

        public <V> V call(Callable<V> callable) throws Exception {
            return callable.call();
        }

    }

}

Curious on the InitialContext parameters used? See the Injection of DataSource Example for an explanation of how any Resource can be configured via properties in the TestCase itself or via an openejb.xml file.

Running

Running the example is fairly simple. In the "testing-security" directory of the examples zip, just run:

$ mvn clean install

Which should create output like the following.

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.superbiz.injection.secure.MovieTest
Apache OpenEJB 3.0    build: 20080408-04:13
http://openejb.apache.org/
INFO - openejb.home = /Users/dblevins/work/openejb-3.0/examples/testing-security
INFO - openejb.base = /Users/dblevins/work/openejb-3.0/examples/testing-security
INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
INFO - Configuring Service(id=movieDatabaseUnmanaged, type=Resource, provider-id=Default JDBC Database)
INFO - Configuring Service(id=movieDatabase, type=Resource, provider-id=Default JDBC Database)
INFO - Configuring Service(id=Default JDK 1.3 ProxyFactory, type=ProxyFactory, provider-id=Default JDK 1.3 ProxyFactory)
INFO - Found EjbModule in classpath: /Users/dblevins/work/openejb-3.0/examples/testing-security/target/classes
INFO - Found EjbModule in classpath: /Users/dblevins/work/openejb-3.0/examples/testing-security/target/test-classes
INFO - Configuring app: /Users/dblevins/work/openejb-3.0/examples/testing-security/target/classes
INFO - Configuring Service(id=Default Stateful Container, type=Container, provider-id=Default Stateful Container)
INFO - Auto-creating a container for bean Movies: Container(type=STATEFUL, id=Default Stateful Container)
INFO - Configuring PersistenceUnit(name=movie-unit)
INFO - Loaded Module: /Users/dblevins/work/openejb-3.0/examples/testing-security/target/classes
INFO - Configuring app: /Users/dblevins/work/openejb-3.0/examples/testing-security/target/test-classes
INFO - Configuring Service(id=Default Stateless Container, type=Container, provider-id=Default Stateless Container)
INFO - Auto-creating a container for bean EmployeeBean: Container(type=STATELESS, id=Default Stateless Container)
INFO - Loaded Module: /Users/dblevins/work/openejb-3.0/examples/testing-security/target/test-classes
INFO - Assembling app: /Users/dblevins/work/openejb-3.0/examples/testing-security/target/classes
INFO - PersistenceUnit(name=movie-unit, provider=org.apache.openjpa.persistence.PersistenceProviderImpl)
ERROR - JAVA AGENT NOT INSTALLED. The JPA Persistence Provider requested installation of a ClassFileTransformer which 
        requires a JavaAgent.  See http://openejb.apache.org/3.0/javaagent.html
INFO - Jndi(name=MoviesLocal) --> Ejb(deployment-id=Movies)
INFO - Created Ejb(deployment-id=Movies, ejb-name=Movies, container=Default Stateful Container)
INFO - Deployed Application(path=/Users/dblevins/work/openejb-3.0/examples/testing-security/target/classes)
INFO - Assembling app: /Users/dblevins/work/openejb-3.0/examples/testing-security/target/test-classes
INFO - Jndi(name=EmployeeBeanLocal) --> Ejb(deployment-id=EmployeeBean)
INFO - Jndi(name=ManagerBeanLocal) --> Ejb(deployment-id=ManagerBean)
INFO - Created Ejb(deployment-id=EmployeeBean, ejb-name=EmployeeBean, container=Default Stateless Container)
INFO - Created Ejb(deployment-id=ManagerBean, ejb-name=ManagerBean, container=Default Stateless Container)
INFO - Deployed Application(path=/Users/dblevins/work/openejb-3.0/examples/testing-security/target/test-classes)
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.109 sec

Results :

Tests run: 3, Failures: 0, Errors: 0, Skipped: 0

   

Apache OpenEJB is an project of The Apache Software Foundation (ASF)
Site Powered by Atlassian Confluence .
[ edit ]