Тестирование защищенных 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
|
@Entitypublic 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
|
@Statelesspublic 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")@PermitAllpublic 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")@PermitAllpublic 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.BookshelfServiceITnov 23, 2014 2:44:48 AM org.xnio.Xnio <clinit>INFO: XNIO version 3.2.0.Beta4nov 23, 2014 2:44:48 AM org.xnio.nio.NioXnio <clinit>INFO: XNIO NIO Implementation Version 3.2.0.Beta4nov 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.BookshelfServiceITResults :Tests run: 3, Failures: 0, Errors: 0, Skipped: 0 |
Удачных тестов!
| Ссылка: | Тестирование защищенных EJB-компонентов с Arquillian от нашего партнера JCG Сэмюэля Сантоса в блоге Samaxes . |