merge-update from trunk
[cdmlib.git] / cdmlib-services / src / test / java / eu / etaxonomy / cdm / api / service / SecurityTest.java
1 /**
2 * Copyright (C) 2011 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.api.service;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertFalse;
13 import static org.junit.Assert.assertTrue;
14
15 import java.util.Collection;
16 import java.util.EnumSet;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.UUID;
21
22 import javax.sql.DataSource;
23
24 import org.apache.log4j.Logger;
25 import org.junit.Assert;
26 import org.junit.Ignore;
27 import org.junit.Test;
28 import org.springframework.security.access.AccessDeniedException;
29 import org.springframework.security.authentication.AuthenticationManager;
30 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
31 import org.springframework.security.authentication.dao.SaltSource;
32 import org.springframework.security.authentication.encoding.PasswordEncoder;
33 import org.springframework.security.core.Authentication;
34 import org.springframework.security.core.GrantedAuthority;
35 import org.springframework.security.core.context.SecurityContext;
36 import org.springframework.security.core.context.SecurityContextHolder;
37 import org.springframework.transaction.PlatformTransactionManager;
38 import org.unitils.database.annotations.TestDataSource;
39 import org.unitils.dbunit.annotation.DataSet;
40 import org.unitils.spring.annotation.SpringBean;
41 import org.unitils.spring.annotation.SpringBeanByType;
42
43 import sun.security.provider.PolicyParser.ParsingException;
44 import eu.etaxonomy.cdm.api.service.DeleteResult.DeleteStatus;
45 import eu.etaxonomy.cdm.api.service.exception.DataChangeNoRollbackException;
46 import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
47 import eu.etaxonomy.cdm.database.PermissionDeniedException;
48 import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
49 import eu.etaxonomy.cdm.model.common.User;
50 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
51 import eu.etaxonomy.cdm.model.description.Feature;
52 import eu.etaxonomy.cdm.model.description.TaxonDescription;
53 import eu.etaxonomy.cdm.model.description.TextData;
54 import eu.etaxonomy.cdm.model.name.BotanicalName;
55 import eu.etaxonomy.cdm.model.name.Rank;
56 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
57 import eu.etaxonomy.cdm.model.name.ZoologicalName;
58 import eu.etaxonomy.cdm.model.reference.Reference;
59 import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
60 import eu.etaxonomy.cdm.model.taxon.Classification;
61 import eu.etaxonomy.cdm.model.taxon.Synonym;
62 import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
63 import eu.etaxonomy.cdm.model.taxon.Taxon;
64 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
65 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
66 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
67 import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
68 import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionClass;
69 import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator;
70 import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;
71 import eu.etaxonomy.cdm.persistence.query.MatchMode;
72
73
74 @DataSet
75 public class SecurityTest extends AbstractSecurityTestBase{
76
77
78 private static final Logger logger = Logger.getLogger(SecurityTest.class);
79
80 @SpringBeanByType
81 private ITaxonService taxonService;
82
83 @SpringBeanByType
84 private INameService nameService;
85
86 @SpringBeanByType
87 private IReferenceService referenceService;
88
89 @SpringBeanByType
90 private ITaxonNodeService taxonNodeService;
91
92 @SpringBeanByType
93 private IDescriptionService descriptionService;
94
95 @SpringBeanByType
96 private IUserService userService;
97
98 @SpringBeanByType
99 private IClassificationService classificationService;
100
101 @SpringBeanByType
102 private AuthenticationManager authenticationManager;
103
104 @SpringBeanByType
105 private SaltSource saltSource;
106
107 @SpringBeanByType
108 private PasswordEncoder passwordEncoder;
109
110 @SpringBean("cdmPermissionEvaluator")
111 private CdmPermissionEvaluator permissionEvaluator;
112
113 @TestDataSource
114 protected DataSource dataSource;
115
116 private Authentication authentication;
117
118
119 /**
120 * no assertions in this test, since it is only used to create password hashes for test data
121 */
122 @Test
123 public void testEncryptPassword(){
124
125 String password = PASSWORD_ADMIN;
126 User user = User.NewInstance("userManager", "");
127
128 Object salt = this.saltSource.getSalt(user);
129 String passwordEncrypted = passwordEncoder.encodePassword(password, salt);
130 logger.info("encrypted password: " + passwordEncrypted );
131 }
132
133 @Test
134 @DataSet
135 public void testHasPermission(){
136
137 Taxon taxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()),null);
138
139 authentication = authenticationManager.authenticate(tokenForTaxonomist);
140 boolean hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.UPDATE);
141 assertTrue(hasPermission);
142
143 authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
144 hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.UPDATE);
145 assertFalse(hasPermission);
146 }
147
148 @Test
149 @DataSet
150 public void testListByUsernameAllow(){
151
152 authentication = authenticationManager.authenticate(tokenForTaxonomist);
153 SecurityContext context = SecurityContextHolder.getContext();
154 context.setAuthentication(authentication);
155
156 List<User> userList = userService.listByUsername("Editor", MatchMode.ANYWHERE, null, null, 0, null, null);
157 Assert.assertTrue("The user list must have elements", userList.size() > 0 );
158 }
159
160 @Test
161 @DataSet
162 public void testUserService_CreateDeny(){
163
164 authentication = authenticationManager.authenticate(tokenForTaxonomist);
165 SecurityContext context = SecurityContextHolder.getContext();
166 context.setAuthentication(authentication);
167
168 RuntimeException exception = null;
169 try {
170 userService.createUser(User.NewInstance("new guy", "alkjdsfalkj"));
171 commitAndStartNewTransaction(null);
172 } catch (AccessDeniedException e){
173 logger.debug("Expected failure of evaluation.", e);
174 exception = e;
175 } catch (RuntimeException e){
176 exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
177 logger.debug("Expected failure of evaluation.", e);
178 } finally {
179 // needed in case saveOrUpdate was interrupted by the RuntimeException
180 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
181 endTransaction();
182 startNewTransaction();
183 }
184 Assert.assertNotNull("Must fail here!", exception);
185
186 }
187
188 @Test
189 @DataSet
190 public void testUserService_CreateAllow(){
191
192 authentication = authenticationManager.authenticate(tokenForUserManager);
193 SecurityContext context = SecurityContextHolder.getContext();
194 context.setAuthentication(authentication);
195
196 RuntimeException exception = null;
197 try {
198 userService.createUser(User.NewInstance("new guy", "alkjdsfalkj"));
199 commitAndStartNewTransaction(null);
200 } catch (AccessDeniedException e){
201 logger.error("Unexpected failure of evaluation.", e);
202 exception = e;
203 } catch (RuntimeException e){
204 exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
205 logger.error("unexpected failure of evaluation.", exception);
206 } finally {
207 // needed in case saveOrUpdate was interrupted by the RuntimeException
208 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
209 endTransaction();
210 startNewTransaction();
211 }
212 Assert.assertNull("Must not fail here!", exception);
213
214 }
215
216
217 @Test
218 @DataSet
219 @Ignore // FIXME http://dev.e-taxonomy.eu/trac/ticket/3098
220 public void testHasPermissions(){
221
222 Taxon taxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()),null);
223
224 authentication = authenticationManager.authenticate(tokenForTaxonomist);
225 boolean hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.ALL);
226 assertTrue(hasPermission);
227 }
228
229
230 /**
231 * Test method for {@link eu.etaxonomy.cdm.api.service.TaxonServiceImpl#saveTaxon(eu.etaxonomy.cdm.model.taxon.TaxonBase)}.
232 */
233 @Test
234 public final void testSaveTaxon() {
235
236 authentication = authenticationManager.authenticate(tokenForAdmin);
237 SecurityContext context = SecurityContextHolder.getContext();
238 context.setAuthentication(authentication);
239
240 Taxon expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);
241 expectedTaxon.getName().setTitleCache("Newby admin", true);
242 UUID uuid = taxonService.save(expectedTaxon);
243 commitAndStartNewTransaction(null);
244 TaxonBase<?> actualTaxon = taxonService.load(uuid);
245 assertEquals(expectedTaxon, actualTaxon);
246
247 authentication = authenticationManager.authenticate(tokenForTaxonEditor);
248 context = SecurityContextHolder.getContext();
249 context.setAuthentication(authentication);
250 expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()), null);
251 expectedTaxon.getName().setTitleCache("Newby taxonEditor", true);
252 uuid = taxonService.saveOrUpdate(expectedTaxon);
253 commitAndStartNewTransaction(null);
254 actualTaxon = taxonService.load(uuid);
255 assertEquals(expectedTaxon, actualTaxon);
256
257 }
258
259 @Test
260 public final void testSaveNameAllow() {
261
262 authentication = authenticationManager.authenticate(tokenForTaxonEditor);
263 SecurityContext context = SecurityContextHolder.getContext();
264 context.setAuthentication(authentication);
265
266 ZoologicalName newName = ZoologicalName.NewInstance(Rank.SPECIES());
267 newName.setTitleCache("Newby taxonEditor", true);
268 UUID uuid = nameService.saveOrUpdate(newName);
269 commitAndStartNewTransaction(null);
270 TaxonNameBase savedName = nameService.load(uuid);
271 assertEquals(newName, savedName);
272 }
273
274
275 @Test
276 public final void testReuseNameAllow() {
277
278 authentication = authenticationManager.authenticate(tokenForTaxonEditor);
279 SecurityContext context = SecurityContextHolder.getContext();
280 context.setAuthentication(authentication);
281
282 TaxonBase taxon = taxonService.find(UUID_ACHERONTIA_STYX);
283 TaxonNameBase n_acherontia_thetis = taxon.getName();
284
285 Taxon newTaxon = Taxon.NewInstance(n_acherontia_thetis, ReferenceFactory.newGeneric());
286 Exception exception = null;
287 try {
288 UUID uuid = taxonService.save(newTaxon);
289 commitAndStartNewTransaction(null);
290 } catch (AccessDeniedException e){
291 logger.error("Unexpected failure of evaluation.", e);
292 exception = e;
293 } catch (RuntimeException e){
294 logger.error("Unexpected failure of evaluation.", e);
295 exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
296 } finally {
297 // needed in case saveOrUpdate was interrupted by the RuntimeException
298 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
299 endTransaction();
300 startNewTransaction();
301 }
302 Assert.assertNull("must not fail here!", exception);
303 }
304
305 @Test
306 public final void testMakeTaxonNodeASynonymOfAnotherTaxonNodeAllow_1() {
307
308 authentication = authenticationManager.authenticate(tokenForTaxonEditor);
309 SecurityContext context = SecurityContextHolder.getContext();
310 context.setAuthentication(authentication);
311
312 Reference book = referenceService.load(BOOK1_UUID);
313
314 TaxonNode n_acherontia_styx = taxonNodeService.find(ACHERONTIA_STYX_NODE_UUID);
315 TaxonNode n_acherontia_lachersis = taxonNodeService.find(ACHERONTIA_LACHESIS_NODE_UUID);
316
317 Exception exception = null;
318 try {
319 taxonNodeService.makeTaxonNodeASynonymOfAnotherTaxonNode(n_acherontia_styx, n_acherontia_lachersis, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), book , "33");
320 commitAndStartNewTransaction(null);
321 } catch (AccessDeniedException e){
322 logger.error("Unexpected failure of evaluation.", e);
323 exception = e;
324 } catch (RuntimeException e){
325 logger.error("Unexpected failure of evaluation.", e);
326 exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
327 }finally {
328 // needed in case saveOrUpdate was interrupted by the RuntimeException
329 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
330 endTransaction();
331 startNewTransaction();
332 }
333 Assert.assertNull("must not fail here!", exception);
334 }
335
336 @Test
337 public final void testMakeTaxonNodeASynonymOfAnotherTaxonNodeAllow_2() {
338
339 authentication = authenticationManager.authenticate(tokenForTaxonEditor);
340 SecurityContext context = SecurityContextHolder.getContext();
341 context.setAuthentication(authentication);
342
343 Reference book = referenceService.load(BOOK1_UUID);
344
345 TaxonNode n_acherontia_styx = taxonNodeService.find(ACHERONTIA_STYX_NODE_UUID);
346 TaxonNode n_acherontia_lachersis = taxonNodeService.find(ACHERONTIA_LACHESIS_NODE_UUID);
347
348 Exception exception = null;
349 try {
350 taxonNodeService.makeTaxonNodeASynonymOfAnotherTaxonNode(n_acherontia_lachersis, n_acherontia_styx, SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF(), book , "33");
351 commitAndStartNewTransaction(null);
352 } catch (AccessDeniedException e){
353 logger.error("Unexpected failure of evaluation.", e);
354 exception = e;
355 } catch (RuntimeException e){
356 logger.error("Unexpected failure of evaluation.", e);
357 exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
358 } finally {
359 // needed in case saveOrUpdate was interrupted by the RuntimeException
360 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
361 endTransaction();
362 startNewTransaction();
363 }
364 Assert.assertNull("must not fail here!", exception);
365 }
366
367 @Test
368 public final void testUpdateReferenceAllow() throws ParsingException {
369
370
371 authentication = authenticationManager.authenticate(tokenForUserManager);
372 SecurityContext context = SecurityContextHolder.getContext();
373 context.setAuthentication(authentication);
374
375 // add REFERENCE[UPDATE] to taxonEditor
376 User taxonEditor = userService.load(TAXON_EDITOR_UUID);
377 Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();
378 grantedAuthorities.addAll(taxonEditor.getGrantedAuthorities());
379 GrantedAuthorityImpl referenceUpdate_ga = new CdmAuthority(CdmPermissionClass.REFERENCE, null, EnumSet.of(CRUD.UPDATE), null).asNewGrantedAuthority();
380 grantedAuthorities.add(referenceUpdate_ga);
381 taxonEditor.setGrantedAuthorities(grantedAuthorities);
382 userService.saveOrUpdate(taxonEditor);
383 commitAndStartNewTransaction(null);
384
385 authentication = authenticationManager.authenticate(tokenForTaxonEditor);
386 context = SecurityContextHolder.getContext();
387 context.setAuthentication(authentication);
388
389 Reference book = referenceService.load(BOOK1_UUID);
390 book.setTitleCache("Mobydick", true);
391 Exception exception = null;
392 try {
393 referenceService.saveOrUpdate(book);
394 commitAndStartNewTransaction(null);
395 } catch (AccessDeniedException e){
396 logger.error("Unexpected failure of evaluation.", e);
397 exception = e;
398 } catch (RuntimeException e){
399 logger.error("Unexpected failure of evaluation.", e);
400 exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
401 } finally {
402 // needed in case saveOrUpdate was interrupted by the RuntimeException
403 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
404 endTransaction();
405 startNewTransaction();
406 }
407 Assert.assertNull("must not fail here!", exception);
408 book = referenceService.load(BOOK1_UUID);
409 Assert.assertEquals("Mobydick", book.getTitleCache());
410 }
411
412 @Test
413 public final void testUpateReferenceDeny() {
414
415 authentication = authenticationManager.authenticate(tokenForTaxonEditor);
416 SecurityContext context = SecurityContextHolder.getContext();
417 context.setAuthentication(authentication);
418
419 TaxonBase taxon = taxonService.find(UUID_ACHERONTIA_STYX);
420 taxon.getName().getNomenclaturalReference().setTitleCache("Mobydick", true);
421 Exception exception = null;
422 try {
423 UUID uuid = taxonService.saveOrUpdate(taxon);
424 commitAndStartNewTransaction(null);
425 } catch (AccessDeniedException e){
426 logger.debug("Expected failure of evaluation.", e);
427 exception = e;
428 } catch (RuntimeException e){
429 exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
430 logger.debug("Expected failure of evaluation.", e);
431 } finally {
432 // needed in case saveOrUpdate was interrupted by the RuntimeException
433 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
434 endTransaction();
435 startNewTransaction();
436 }
437 Assert.assertNotNull("must fail here!", exception);
438 }
439
440 @Test
441 public void testChangeOwnPassword(){
442
443 SecurityContext context = SecurityContextHolder.getContext();
444 // authenticate as admin
445 authentication = authenticationManager.authenticate(tokenForTaxonEditor);
446 context.setAuthentication(authentication);
447
448 // User currentUser = (User) context.getAuthentication().getPrincipal();
449
450 String newPass = "poiweorijo";
451 userService.changePassword(PASSWORD_TAXON_EDITOR, newPass);
452 commitAndStartNewTransaction(null);
453
454 // try to re-authenticate user with changed password
455 UsernamePasswordAuthenticationToken newTokenForTaxonEditor = new UsernamePasswordAuthenticationToken("taxonEditor", newPass);
456 authentication = authenticationManager.authenticate(newTokenForTaxonEditor);
457 }
458
459 @Test
460 public void testChangeOthersPasswordAllow(){
461
462 SecurityContext context = SecurityContextHolder.getContext();
463 RuntimeException exception = null;
464
465 // (1) authenticate as admin
466 authentication = authenticationManager.authenticate(tokenForAdmin);
467 context.setAuthentication(authentication);
468
469
470 try{
471 userService.changePasswordForUser("taxonomist", "zuaisd");
472 commitAndStartNewTransaction(null);
473 } catch (AccessDeniedException e){
474 logger.error("Unexpected failure of evaluation.", e);
475 exception = e;
476 } catch (RuntimeException e){
477 exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
478 logger.error("Unexpected failure of evaluation.", exception);
479 } finally {
480 // needed in case saveOrUpdate was interrupted by the RuntimeException
481 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
482 endTransaction();
483 startNewTransaction();
484 }
485 Assert.assertNull("must not fail here!", exception);
486
487 // ok, now try authenticating taxonomist with new password
488 UsernamePasswordAuthenticationToken newToken = new UsernamePasswordAuthenticationToken("taxonomist", "zuaisd");
489 authentication = authenticationManager.authenticate(newToken);
490 }
491
492 @Test
493 public void testChangeOthersPasswordDeny(){
494
495 SecurityContext context = SecurityContextHolder.getContext();
496 RuntimeException exception = null;
497
498 // (2) authenticate as under privileged user - not an admin !!!
499 authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
500 context.setAuthentication(authentication);
501
502 // check test preconditions user name and authorities
503 Assert.assertEquals("descriptionEditor", context.getAuthentication().getName());
504 Collection<? extends GrantedAuthority> authorities = context.getAuthentication().getAuthorities();
505 for(GrantedAuthority authority: authorities){
506 // role prefix 'ROLE_' is defined in org.springframework.security.access.vote.RoleVoter !!!
507 Assert.assertNotSame("user must not have authority 'ROLE_ADMIN'", "ROLE_ADMIN", authority.getAuthority());
508 }
509 // finally perform the test :
510 try{
511 userService.changePasswordForUser("partEditor", "poiweorijo");
512 commitAndStartNewTransaction(null);
513 } catch (AccessDeniedException e){
514 logger.debug("Expected failure of evaluation.", e);
515 exception = e;
516 } catch (RuntimeException e){
517 exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
518 logger.debug("Expected failure of evaluation.", e);
519 } finally {
520 // needed in case saveOrUpdate was interrupted by the RuntimeException
521 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
522 endTransaction();
523 startNewTransaction();
524 }
525 Assert.assertNotNull("must fail here!", exception);
526 }
527
528 @Test
529 public void testUpdateUser(){
530
531 authentication = authenticationManager.authenticate(tokenForAdmin);
532 SecurityContext context = SecurityContextHolder.getContext();
533 context.setAuthentication(authentication);
534 String username = "standardUser";
535 String password = "pw";
536 User user = User.NewInstance(username, password);
537
538 userService.createUser(user);
539 user.setEmailAddress("test@bgbm.org");
540
541 userService.updateUser(user);
542 userService.update(user);
543 userService.saveOrUpdate(user);
544 commitAndStartNewTransaction(null);
545
546 }
547
548 /**
549 * test with admin account - should succeed
550 */
551 @Test
552 public final void testTaxonSaveOrUpdateAllow_1() {
553
554 SecurityContext context = SecurityContextHolder.getContext();
555
556 authentication = authenticationManager.authenticate(tokenForAdmin);
557 context.setAuthentication(authentication);
558 RuntimeException securityException= null;
559
560 TaxonBase<?> taxon = taxonService.find(UUID_ACHERONTIA_STYX);
561 Assert.assertFalse(taxon.isDoubtful());
562 taxon.setDoubtful(true);
563 try{
564 taxonService.saveOrUpdate(taxon);
565 commitAndStartNewTransaction(null);
566 } catch (RuntimeException e){
567 securityException = findSecurityRuntimeException(e);
568 logger.error("Unexpected failure of evaluation.", e);
569 } finally {
570 // needed in case saveOrUpdate was interrupted by the RuntimeException
571 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
572 endTransaction();
573 startNewTransaction();
574 }
575 Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
576 // reload taxon
577 taxon = taxonService.find(UUID_ACHERONTIA_STYX);
578 Assert.assertTrue("The change must be persisted", taxon.isDoubtful());
579 }
580
581 /**
582 * test with taxonEditor account - should succeed
583 */
584 @Test
585 public final void testTaxonSaveOrUpdateAllow_2() {
586
587
588 RuntimeException securityException= null;
589 SecurityContext context = SecurityContextHolder.getContext();
590
591 // taxonEditor account - should succeed
592 authentication = authenticationManager.authenticate(tokenForTaxonEditor);
593
594 context.setAuthentication(authentication);
595
596 TaxonBase<?> taxon = taxonService.find(UUID_ACHERONTIA_STYX);
597 Assert.assertFalse(taxon.isDoubtful());
598 taxon.setDoubtful(true);
599 try{
600 taxonService.saveOrUpdate(taxon);
601 commitAndStartNewTransaction(null);
602 } catch (RuntimeException e){
603 securityException = findSecurityRuntimeException(e);
604 logger.error("Unexpected failure of evaluation.", e);
605 } finally {
606 // needed in case saveOrUpdate was interrupted by the RuntimeException
607 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
608 endTransaction();
609 startNewTransaction();
610 }
611 Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
612 // reload taxon
613 taxon = taxonService.find(UUID_ACHERONTIA_STYX);
614 Assert.assertTrue("The change must be persited", taxon.isDoubtful());
615 }
616
617 /**
618 * test with tokenForDescriptionEditor account - should fail
619 */
620 @Test
621 public final void testTaxonSaveOrUpdateDeny_2() {
622
623 SecurityContext context = SecurityContextHolder.getContext();
624 RuntimeException securityException = null;
625
626 authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
627 context.setAuthentication(authentication);
628
629 TaxonBase<?> taxon = taxonService.find(UUID_ACHERONTIA_STYX);
630
631 Assert.assertFalse(taxon.isDoubtful());
632 taxon.setDoubtful(true);
633 try {
634 taxonService.saveOrUpdate(taxon);
635 commitAndStartNewTransaction(null);
636 } catch (RuntimeException e){
637 securityException = findSecurityRuntimeException(e);
638 logger.debug("Expected failure of evaluation.", securityException);
639 } finally {
640 // needed in case saveOrUpdate was interrupted by the RuntimeException
641 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
642 endTransaction();
643 startNewTransaction();
644 }
645
646 Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);
647 // reload taxon
648 taxon = taxonService.find(UUID_ACHERONTIA_STYX);
649 Assert.assertFalse("The change must not be persited", taxon.isDoubtful());
650 }
651
652 @Test
653 public final void testTaxonPublishAllow_ROLE_ADMIN() {
654
655 SecurityContext context = SecurityContextHolder.getContext();
656
657 authentication = authenticationManager.authenticate(tokenForAdmin);
658 context.setAuthentication(authentication);
659 RuntimeException securityException= null;
660
661 Taxon taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
662
663 boolean lastIsPublish = taxon.isPublish();
664 taxon.setPublish(!lastIsPublish);
665 try{
666 taxonService.saveOrUpdate(taxon);
667 commitAndStartNewTransaction(null);
668 } catch (RuntimeException e){
669 securityException = findSecurityRuntimeException(e);
670 logger.error("Unexpected failure of evaluation.", e);
671 } finally {
672 // needed in case saveOrUpdate was interrupted by the RuntimeException
673 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
674 endTransaction();
675 startNewTransaction();
676 }
677 Assert.assertNull("evaluation must not fail since the user has ROLE_ADMIN, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
678 // reload taxon
679 taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
680 Assert.assertTrue("The change must be persisted", taxon.isPublish() != lastIsPublish);
681 }
682
683
684 /**
685 * test with Taxonomist account which has the ROLE_PUBLISH
686 */
687 @Test
688 public final void testTaxonPublishAllow_ROLE_PUBLISH() {
689
690 SecurityContext context = SecurityContextHolder.getContext();
691
692 authentication = authenticationManager.authenticate(tokenForTaxonomist);
693 context.setAuthentication(authentication);
694 RuntimeException securityException= null;
695
696 Taxon taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
697
698 boolean lastIsPublish = taxon.isPublish();
699 taxon.setPublish(!lastIsPublish);
700 try{
701 taxonService.saveOrUpdate(taxon);
702 commitAndStartNewTransaction(null);
703 } catch (RuntimeException e){
704 securityException = findSecurityRuntimeException(e);
705 logger.error("Unexpected failure of evaluation.", e);
706 } finally {
707 // needed in case saveOrUpdate was interrupted by the RuntimeException
708 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
709 endTransaction();
710 startNewTransaction();
711 }
712 Assert.assertNull("evaluation must not fail since the user has ROLE_ADMIN, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
713 // reload taxon
714 taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
715 Assert.assertTrue("The change must be persisted", taxon.isPublish() != lastIsPublish);
716 }
717
718 /**
719 * test with TaxonEditor account which has not the ROLE_PUBLISH
720 */
721 @Test
722 public final void testTaxonPublishDeny() {
723
724 SecurityContext context = SecurityContextHolder.getContext();
725
726 authentication = authenticationManager.authenticate(tokenForTaxonEditor);
727 context.setAuthentication(authentication);
728 RuntimeException securityException= null;
729
730 Taxon taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
731
732 boolean lastIsPublish = taxon.isPublish();
733 taxon.setPublish(!lastIsPublish);
734 try {
735 taxonService.saveOrUpdate(taxon);
736 commitAndStartNewTransaction(null);
737 } catch (RuntimeException e){
738 securityException = findSecurityRuntimeException(e);
739 logger.debug("Expected failure of evaluation.", securityException);
740 } finally {
741 // needed in case saveOrUpdate was interrupted by the RuntimeException
742 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
743 endTransaction();
744 startNewTransaction();
745 }
746
747 Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);
748 // reload taxon
749 taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
750 Assert.assertTrue("The taxon must be unchanged", taxon.isPublish() == lastIsPublish);
751 }
752
753 /**
754 * test with admin account - should succeed
755 */
756 @Test
757 public final void testTaxonDeleteAllow_1() {
758
759 SecurityContext context = SecurityContextHolder.getContext();
760
761 authentication = authenticationManager.authenticate(tokenForAdmin);
762 context.setAuthentication(authentication);
763 RuntimeException securityException= null;
764
765 TaxonBase<?> taxon = taxonService.load(UUID_LACTUCA);
766 taxonService.delete(taxon);
767 commitAndStartNewTransaction(null);
768
769
770
771
772 Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
773 // reload taxon
774 taxon = taxonService.load(UUID_LACTUCA);
775 Assert.assertNull("The taxon must be deleted", taxon);
776 }
777
778 /**
779 * test with admin account - should succeed
780 */
781 @Test
782 public final void testTaxonDeleteAllow_2() {
783
784 SecurityContext context = SecurityContextHolder.getContext();
785
786 authentication = authenticationManager.authenticate(tokenForAdmin);
787 context.setAuthentication(authentication);
788 RuntimeException securityException= null;
789
790 Taxon taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);
791 try{
792 // try {
793 DeleteResult result = taxonService.deleteTaxon(taxon, null, null);
794 /*} catch (DataChangeNoRollbackException e) {
795 Assert.fail();
796 }*/
797 if (!result.isOk()){
798 Assert.fail();
799 }
800 commitAndStartNewTransaction(null);
801 } catch (RuntimeException e){
802 securityException = findSecurityRuntimeException(e);
803 logger.error("Unexpected failure of evaluation.", e);
804 } finally {
805 // needed in case saveOrUpdate was interrupted by the RuntimeException
806 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
807 endTransaction();
808 startNewTransaction();
809 }
810 Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
811 // reload taxon
812
813 taxon = (Taxon)taxonService.find(UUID_ACHERONTINII);
814 Assert.assertNull("The taxon must be deleted", taxon);
815 }
816
817
818 /**
819 * test with tokenForDescriptionEditor account - should fail
820 */
821 @Test
822 public final void testTaxonDeleteDeny() {
823
824 SecurityContext context = SecurityContextHolder.getContext();
825 RuntimeException securityException = null;
826
827 authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
828 context.setAuthentication(authentication);
829
830 Taxon taxon = (Taxon)taxonService.load(UUID_LACTUCA);
831 DeleteResult result = taxonService.deleteTaxon(taxon, null, null);
832 if (!result.isError()) {
833 Assert.fail();
834 }
835 endTransaction();
836 startNewTransaction();
837
838
839 //Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);
840 // reload taxon
841 taxon = (Taxon)taxonService.load(UUID_LACTUCA);
842
843 Assert.assertNotNull("The change must still exist", taxon);
844 Assert.assertNotNull("The name must still exist",taxon.getName());
845 }
846
847
848 @Test
849 @Ignore //FIXME: adding taxa to a description must be protected at the side of the Description itself!!
850 // => protecting method TaxonDescription.setTaxon() ?
851 public void testAddDescriptionToTaxon(){
852
853 SecurityContext context = SecurityContextHolder.getContext();
854 authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
855 context.setAuthentication(authentication);
856
857 RuntimeException securityException = null;
858
859 Taxon taxon = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);
860
861 TaxonDescription description = TaxonDescription.NewInstance(taxon);
862 description.setTitleCache("test");
863 try {
864 descriptionService.saveOrUpdate(description);
865 commitAndStartNewTransaction(null);
866 } catch (RuntimeException e){
867 securityException = findSecurityRuntimeException(e);
868 logger.debug("Expected failure of evaluation.", securityException);
869 } finally {
870 // needed in case saveOrUpdate was interrupted by the RuntimeException
871 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
872 endTransaction();
873 startNewTransaction();
874 }
875 /*
876 * Expectation:
877 * The user should not be granted to add the Description to a taxon
878 */
879 Assert.assertNotNull("evaluation should fail since the user is not permitted to edit Taxa", securityException);
880 taxon = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);
881 assertTrue(taxon.getDescriptions().contains(description));
882 }
883
884 @Test
885 public void testMoveDescriptionElement(){
886
887 SecurityContext context = SecurityContextHolder.getContext();
888 authentication = authenticationManager.authenticate(tokenForTaxonomist);
889 context.setAuthentication(authentication);
890
891 RuntimeException securityException = null;
892
893 Taxon t_acherontia_lachesis = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);
894 Taxon t_acherontia_styx = (Taxon)taxonService.load(UUID_ACHERONTIA_STYX);
895
896 TaxonDescription description_acherontia_styx = t_acherontia_styx.getDescriptions().iterator().next();
897 TaxonDescription description_acherontia_lachesis = t_acherontia_lachesis.getDescriptions().iterator().next();
898
899 try {
900 descriptionService.moveDescriptionElementsToDescription(description_acherontia_styx.getElements(), description_acherontia_lachesis, false);
901 commitAndStartNewTransaction(null);
902 } catch (RuntimeException e){
903 securityException = findSecurityRuntimeException(e);
904 logger.debug("Unexpected failure of evaluation.", securityException);
905 } finally {
906 // needed in case saveOrUpdate was interrupted by the RuntimeException
907 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
908 endTransaction();
909 startNewTransaction();
910 }
911 /*
912 * Expectation:
913 */
914 Assert.assertNull("evaluation should not fail since the user has sufficient permissions", securityException);
915
916 }
917
918 // @Ignore // FIXME http://dev.e-taxonomy.eu/trac/ticket/4081 : #4081 (TaxonNodeServiceImpl.makeTaxonNodeASynonymOfAnotherTaxonNode() requires TAXONNAMEBASE.[UPDATE])
919 @Test
920 public void testAcceptedTaxonToSynomym(){
921
922 SecurityContext context = SecurityContextHolder.getContext();
923 authentication = authenticationManager.authenticate(tokenForPartEditor);
924 context.setAuthentication(authentication);
925
926 RuntimeException securityException = null;
927
928 Taxon t_acherontia_lachesis = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);
929 Taxon t_acherontia_styx = (Taxon)taxonService.load(UUID_ACHERONTIA_STYX);
930
931
932 TaxonNode n_acherontia_lachesis = t_acherontia_lachesis.getTaxonNodes().iterator().next();
933 TaxonNode n_acherontia_styx = t_acherontia_styx.getTaxonNodes().iterator().next();
934
935 int numOfSynonymsBefore_styx = t_acherontia_styx.getSynonyms().size();
936 int numOfSynonymsBefore_lachesis = t_acherontia_lachesis.getSynonyms().size();
937
938 UUID synonymUuid = null; // UUID.randomUUID();
939
940 try {
941 Synonym synonym = taxonNodeService.makeTaxonNodeASynonymOfAnotherTaxonNode(n_acherontia_lachesis, n_acherontia_styx, SynonymRelationshipType.SYNONYM_OF(), null, null);
942 synonymUuid = synonym.getUuid();
943 taxonService.saveOrUpdate(synonym);
944 commitAndStartNewTransaction(null);
945 } catch (RuntimeException e){
946 securityException = findSecurityRuntimeException(e);
947 logger.error("Unexpected Exception ", e);
948 Assert.fail("Unexpected Exception: " + e.getMessage());
949 } finally {
950 // needed in case saveOrUpdate was interrupted by the RuntimeException
951 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
952 endTransaction();
953 startNewTransaction();
954 }
955 /*
956 * Expectation:
957 */
958 Assert.assertNull("evaluation should not fail since the user has sufficient permissions", securityException);
959
960 // reload from db and check assertions
961 t_acherontia_styx = (Taxon)taxonService.load(UUID_ACHERONTIA_STYX);
962 Assert.assertEquals("Acherontia styx now must have a synonym", numOfSynonymsBefore_styx + numOfSynonymsBefore_lachesis + 1, t_acherontia_styx.getSynonyms().size());
963 Assert.assertTrue("Acherontia lachesis now must be a synonym", taxonService.load(synonymUuid) instanceof Synonym);
964 Assert.assertNull("The old TaxonNode should no longer exist", taxonNodeService.find(n_acherontia_lachesis.getUuid()));
965 }
966
967 @Test
968 public void testCreateDescriptionWithElement(){
969
970 SecurityContext context = SecurityContextHolder.getContext();
971 authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
972 context.setAuthentication(authentication);
973
974 TaxonDescription description = null;
975 RuntimeException securityException = null;
976 Taxon taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);
977 Assert.assertTrue("taxon must not yet have descriptions", taxon.getDescriptions().size() == 0);
978
979
980 // 1) test for failure - description element but no feature
981 description = TaxonDescription.NewInstance(taxon);
982 DescriptionElementBase textdataNoFeature = TextData.NewInstance();
983 description.addElement(textdataNoFeature);
984
985 assertTrue(permissionEvaluator.hasPermission(authentication, description, "UPDATE"));
986 try{
987 descriptionService.saveOrUpdate(description);
988 commitAndStartNewTransaction(null);
989 } catch (RuntimeException e){
990 securityException = findSecurityRuntimeException(e);
991 logger.error("RuntimeException caught");
992 logger.debug("Expected failure of evaluation.", securityException);
993 } finally {
994 // needed in case saveOrUpdate was interrupted by the RuntimeException
995 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
996 endTransaction();
997 startNewTransaction();
998 }
999
1000 Assert.assertNotNull("evaluation should fail", securityException);
1001 taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);
1002 Set<TaxonDescription> descriptions = taxon.getDescriptions();
1003 assertTrue("taxon must not have any description", descriptions.size() == 0);
1004
1005 }
1006
1007 @Test
1008 public void testCreateDescriptionWithElementDeny_1(){
1009
1010 SecurityContext context = SecurityContextHolder.getContext();
1011 authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
1012 context.setAuthentication(authentication);
1013
1014 TaxonDescription description = null;
1015 RuntimeException securityException = null;
1016 Taxon taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);
1017 Assert.assertTrue("taxon must not yet have descriptions", taxon.getDescriptions().size() == 0);
1018
1019 // 2) test for failure - description element but not granted feature
1020 description = TaxonDescription.NewInstance(taxon);
1021 DescriptionElementBase descriptionText = TextData.NewInstance(Feature.DESCRIPTION());
1022 description.addElement(descriptionText);
1023
1024 securityException = null;
1025 assertTrue(permissionEvaluator.hasPermission(authentication, description, "UPDATE"));
1026 try{
1027 descriptionService.saveOrUpdate(description);
1028 commitAndStartNewTransaction(null);
1029 } catch (RuntimeException e){
1030 securityException = findSecurityRuntimeException(e);
1031 logger.debug("Expected failure of evaluation.", securityException);
1032 } finally {
1033 // needed in case saveOrUpdate was interrupted by the RuntimeException
1034 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
1035 endTransaction();
1036 startNewTransaction();
1037 }
1038
1039 Assert.assertNotNull("evaluation should fail", securityException);
1040 taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);
1041 Set<TaxonDescription> descriptions = taxon.getDescriptions();
1042 assertTrue("taxon must not have any description", descriptions.size() == 0);
1043
1044 }
1045
1046 @Test
1047 public void testCreateDescriptionWithElementDeny_2(){
1048
1049 SecurityContext context = SecurityContextHolder.getContext();
1050 authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
1051 context.setAuthentication(authentication);
1052
1053 TaxonDescription description = null;
1054 RuntimeException securityException = null;
1055 Taxon taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);
1056 Assert.assertTrue("taxon must not yet have descriptions", taxon.getDescriptions().size() == 0);
1057
1058 // 3) test for failure
1059 description = TaxonDescription.NewInstance(taxon);
1060 DescriptionElementBase ecologyText = TextData.NewInstance(Feature.ECOLOGY());
1061 description.addElement(ecologyText);
1062
1063 securityException = null;
1064 assertTrue(permissionEvaluator.hasPermission(authentication, description, "UPDATE"));
1065 try{
1066 descriptionService.saveOrUpdate(description);
1067 commitAndStartNewTransaction(null);
1068 } catch (RuntimeException e){
1069 securityException = findSecurityRuntimeException(e);
1070 logger.error("Unexpected failure of evaluation.", e);
1071 } finally {
1072 // needed in case saveOrUpdate was interrupted by the RuntimeException
1073 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
1074 endTransaction();
1075 startNewTransaction();
1076 }
1077
1078 Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
1079 taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);
1080 Set<TaxonDescription> descriptions = taxon.getDescriptions();
1081 assertTrue("taxon must now have one description", descriptions.size() == 1);
1082 assertTrue("description should have one description element", descriptions.iterator().next().getElements().size() == 1);
1083 }
1084
1085 @Test
1086 public void testSaveSynonymAllow(){
1087
1088 SecurityContext context = SecurityContextHolder.getContext();
1089 RuntimeException securityException = null;
1090
1091 // 1) test for success
1092 authentication = authenticationManager.authenticate(tokenForTaxonomist);
1093 context.setAuthentication(authentication);
1094
1095 Synonym syn = Synonym.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);
1096 UUID synUuid = UUID.randomUUID();
1097 syn.setUuid(synUuid);
1098 try{
1099 taxonService.saveOrUpdate(syn);
1100 logger.debug("will commit ...");
1101 commitAndStartNewTransaction(null);
1102 } catch (RuntimeException e){
1103 securityException = findSecurityRuntimeException(e);
1104 logger.error("Unexpected failure of evaluation.", e);
1105 } finally {
1106 // needed in case saveOrUpdate was interrupted by the RuntimeException
1107 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
1108 endTransaction();
1109 startNewTransaction();
1110 }
1111 Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
1112 Assert.assertNotNull("The new Synonym must be persited", taxonService.find(synUuid));
1113 }
1114
1115 @Test
1116 public void testSaveSynonymDenial(){
1117
1118 SecurityContext context = SecurityContextHolder.getContext();
1119 RuntimeException securityException = null;
1120 // 2) test for denial
1121 authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
1122 context.setAuthentication(authentication);
1123 securityException = null;
1124 Synonym syn = Synonym.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);
1125 UUID synUuid = syn.getUuid();
1126 try{
1127 taxonService.saveOrUpdate(syn);
1128 logger.debug("will commit ...");
1129 commitAndStartNewTransaction(null);
1130 } catch (RuntimeException e){
1131 securityException = findSecurityRuntimeException(e);
1132 logger.debug("Expected failure of evaluation: " + securityException.getClass());
1133 } finally {
1134 // needed in case saveOrUpdate was interrupted by the RuntimeException
1135 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
1136 endTransaction();
1137 startNewTransaction();
1138 }
1139
1140 Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);
1141 Assert.assertNull("The Synonym must not be persited", taxonService.find(synUuid));
1142 }
1143
1144 @Test
1145 public void testEditPartOfClassificationAllow(){
1146
1147 authentication = authenticationManager.authenticate(tokenForPartEditor);
1148 SecurityContext context = SecurityContextHolder.getContext();
1149 context.setAuthentication(authentication);
1150 RuntimeException securityException = null;
1151 Classification classification = classificationService.load(UUID.fromString("aeee7448-5298-4991-b724-8d5b75a0a7a9"));
1152 // test for success
1153 TaxonNode acherontia_node = taxonNodeService.load(ACHERONTIA_NODE_UUID);
1154 long numOfChildNodes = acherontia_node.getChildNodes().size();
1155 TaxonNode childNode = acherontia_node.addChildTaxon(Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null), null, null);
1156
1157 try{
1158 taxonNodeService.saveOrUpdate(acherontia_node);
1159 commitAndStartNewTransaction(null);
1160 } catch (RuntimeException e){
1161 securityException = findSecurityRuntimeException(e);
1162 logger.error("Unexpected failure of evaluation.", securityException);
1163 } finally {
1164 // needed in case saveOrUpdate was interrupted by the RuntimeException
1165 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
1166 endTransaction();
1167 startNewTransaction();
1168 }
1169
1170 acherontia_node = taxonNodeService.load(ACHERONTIA_NODE_UUID);
1171 Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
1172 Assert.assertEquals("the acherontia_node must now have one more child node ", numOfChildNodes + 1 , acherontia_node.getChildNodes().size());
1173 }
1174
1175 @Test
1176 public void testEditPartOfClassificationDeny(){
1177
1178 authentication = authenticationManager.authenticate(tokenForPartEditor);
1179 SecurityContext context = SecurityContextHolder.getContext();
1180 context.setAuthentication(authentication);
1181 RuntimeException securityException = null;
1182
1183 // test for denial
1184 securityException = null;
1185 TaxonNode acherontiini_node = taxonNodeService.load(ACHERONTIINI_NODE_UUID);
1186 int numOfChildNodes = acherontiini_node.getCountChildren();
1187 acherontiini_node.addChildTaxon(Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()), null), null, null);
1188
1189 try{
1190 logger.debug("==============================");
1191 taxonNodeService.saveOrUpdate(acherontiini_node);
1192 commitAndStartNewTransaction(null);
1193 } catch (RuntimeException e){
1194 securityException = findSecurityRuntimeException(e);
1195 logger.debug("Expected failure of evaluation.", securityException);
1196 } finally {
1197 // needed in case saveOrUpdate was interrupted by the RuntimeException
1198 // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
1199 endTransaction();
1200 startNewTransaction();
1201 }
1202
1203 acherontiini_node = taxonNodeService.load(ACHERONTIINI_NODE_UUID);
1204 Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);
1205 Assert.assertEquals("the number of child nodes must be unchanged ", numOfChildNodes , acherontiini_node.getChildNodes().size());
1206
1207 }
1208
1209 }