Тестирование защищенных EJB исторически было трудно получить правильно. До сих пор я использовал проприетарные методы, такие как JBossLoginContextFactory, описанные в статье Тестирование защищенных EJB-компонентов на WildFly 8.1.x с Arquillian, для тестирования защищенных EJB- компонентов .
В течение этого года Devoxx , Дэвид Блевинс , основатель проекта Apache TomEE — облегченного сервера приложений Java EE, предоставил мне небольшую хитрость, которую мы можем использовать для стандартного подхода к обеспечению безопасности Java EE, который работает на всех серверах, совместимых с Java EE. ,
Пример, используемый в этом посте, доступен в javaee-testing / security на GitHub.
Код
Код для тестирования включает в себя сущность и службу EJB следующим образом.
Книжная сущность
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
@Entity public class Book { @Id @GeneratedValue (strategy = GenerationType.IDENTITY) private Integer id; private String isbn; private String title; public Book() { } public Book(String isbn, String title) { this .isbn = isbn; this .title = title; } // getters and setters omitted for brevity } |
Книжная полка EJB Service
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@Stateless public class BookshelfService { @PersistenceContext (unitName = "bookshelfManager" ) private EntityManager entityManager; @RolesAllowed ({ "User" , "Manager" }) public void addBook(Book book) { entityManager.persist(book); } @RolesAllowed ({ "Manager" }) public void deleteBook(Book book) { entityManager.remove(book); } @PermitAll @TransactionAttribute (TransactionAttributeType.SUPPORTS) public List<Book> getBooks() { TypedQuery<Book> query = entityManager.createQuery( "SELECT b from Book as b" , Book. class ); return query.getResultList(); } } |
Тестовый класс использует Arquillian для интеграционных тестов и утверждает, что роли безопасности, определенные в нашем EJB, соблюдаются.
Сервисные тесты на книжной полке
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
@RunWith (Arquillian. class ) public class BookshelfServiceIT { @Inject private BookshelfService bookshelfService; @Inject private BookshelfManager manager; @Inject private BookshelfUser user; @Deployment public static JavaArchive createDeployment() throws IOException { return ShrinkWrap.create(JavaArchive. class , "javaee-testing-security.jar" ) .addClasses(Book. class , BookshelfService. class , BookshelfManager. class , BookshelfUser. class ) .addAsManifestResource( "META-INF/persistence.xml" , "persistence.xml" ) .addAsManifestResource(EmptyAsset.INSTANCE, ArchivePaths.create( "beans.xml" )); } @Test public void testAsManager() throws Exception { manager.call( new Callable<Book>() { @Override public Book call() throws Exception { bookshelfService.addBook( new Book( "978-1-4302-4626-8" , "Beginning Java EE 7" )); bookshelfService.addBook( new Book( "978-1-4493-2829-0" , "Continuous Enterprise Development in Java" )); List<Book> books = bookshelfService.getBooks(); Assert.assertEquals( "List.size()" , 2 , books.size()); for (Book book : books) { bookshelfService.deleteBook(book); } Assert.assertEquals( "BookshelfService.getBooks()" , 0 , bookshelfService.getBooks().size()); return null ; } }); } @Test public void testAsUser() throws Exception { user.call( new Callable<Book>() { @Override public Book call() throws Exception { bookshelfService.addBook( new Book( "978-1-4302-4626-8" , "Beginning Java EE 7" )); bookshelfService.addBook( new Book( "978-1-4493-2829-0" , "Continuous Enterprise Development in Java" )); List<Book> books = bookshelfService.getBooks(); Assert.assertEquals( "List.size()" , 2 , books.size()); for (Book book : books) { try { bookshelfService.deleteBook(book); Assert.fail( "Users should not be allowed to delete" ); } catch (EJBAccessException e) { // Good, users cannot delete things } } // The list should not be empty Assert.assertEquals( "BookshelfService.getBooks()" , 2 , bookshelfService.getBooks().size()); return null ; } }); } @Test public void testUnauthenticated() throws Exception { try { bookshelfService.addBook( new Book( "978-1-4302-4626-8" , "Beginning Java EE 7" )); Assert.fail( "Unauthenticated users should not be able to add books" ); } catch (EJBAccessException e) { // Good, unauthenticated users cannot add things } try { bookshelfService.deleteBook( null ); Assert.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<Book> books = bookshelfService.getBooks(); Assert.assertEquals( "BookshelfService.getBooks()" , 0 , books.size()); } catch (EJBAccessException e) { Assert.fail( "Read access should be allowed" ); } } } |
Хитрость заключается в двух вспомогательных EJB-компонентах, которые позволяют нашему тестовому коду выполняться в нужной области безопасности с помощью стандартной аннотации @RunAs
.
Роль менеджера книжной полки
1
2
3
4
5
6
7
8
|
@Stateless @RunAs ( "Manager" ) @PermitAll public class BookshelfManager { public <V> V call(Callable<V> callable) throws Exception { return callable.call(); } } |
Книжная полка Роль пользователя
1
2
3
4
5
6
7
8
|
@Stateless @RunAs ( "User" ) @PermitAll public class BookshelfUser { public <V> V call(Callable<V> callable) throws Exception { return callable.call(); } } |
Бег
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.samaxes.javaeetesting.security.BookshelfServiceIT nov 23, 2014 2:44:48 AM org.xnio.Xnio <clinit> INFO: XNIO version 3.2.0.Beta4 nov 23, 2014 2:44:48 AM org.xnio.nio.NioXnio <clinit> INFO: XNIO NIO Implementation Version 3.2.0.Beta4 nov 23, 2014 2:44:49 AM org.jboss.remoting3.EndpointImpl <clinit> INFO: JBoss Remoting version (unknown) Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 36.69 sec - in com.samaxes.javaeetesting.security.BookshelfServiceIT Results : Tests run: 3, Failures: 0, Errors: 0, Skipped: 0 |
Удачных тестов!
Ссылка: | Тестирование защищенных EJB-компонентов с Arquillian от нашего партнера JCG Сэмюэля Сантоса в блоге Samaxes . |