Project

General

Profile

« Previous | Next » 

Revision 97ee0157

Added by Andreas Müller over 8 years ago

Adapt listeners and tests to new pre-insert strategy #5066

View differences:

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.io.FileNotFoundException;
16
import java.util.Collection;
17
import java.util.EnumSet;
18
import java.util.HashSet;
19
import java.util.List;
20
import java.util.Set;
21
import java.util.UUID;
22

  
23
import javax.sql.DataSource;
24

  
25
import org.apache.log4j.Logger;
26
import org.junit.Assert;
27
import org.junit.Ignore;
28
import org.junit.Test;
29
import org.springframework.security.access.AccessDeniedException;
30
import org.springframework.security.authentication.AuthenticationManager;
31
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
32
import org.springframework.security.authentication.dao.SaltSource;
33
import org.springframework.security.authentication.encoding.PasswordEncoder;
34
import org.springframework.security.core.Authentication;
35
import org.springframework.security.core.GrantedAuthority;
36
import org.springframework.security.core.context.SecurityContext;
37
import org.springframework.security.core.context.SecurityContextHolder;
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.database.PermissionDeniedException;
45
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
46
import eu.etaxonomy.cdm.model.common.User;
47
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
48
import eu.etaxonomy.cdm.model.description.Feature;
49
import eu.etaxonomy.cdm.model.description.TaxonDescription;
50
import eu.etaxonomy.cdm.model.description.TextData;
51
import eu.etaxonomy.cdm.model.name.BotanicalName;
52
import eu.etaxonomy.cdm.model.name.Rank;
53
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
54
import eu.etaxonomy.cdm.model.name.ZoologicalName;
55
import eu.etaxonomy.cdm.model.reference.Reference;
56
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
57
import eu.etaxonomy.cdm.model.taxon.Classification;
58
import eu.etaxonomy.cdm.model.taxon.Synonym;
59
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
60
import eu.etaxonomy.cdm.model.taxon.Taxon;
61
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
62
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
63
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
64
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
65
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionClass;
66
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator;
67
import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;
68
import eu.etaxonomy.cdm.persistence.query.MatchMode;
69

  
70

  
71
@DataSet
72
public class SecurityTest extends AbstractSecurityTestBase{
73

  
74

  
75
    private static final Logger logger = Logger.getLogger(SecurityTest.class);
76

  
77
    @SpringBeanByType
78
    private ITaxonService taxonService;
79

  
80
    @SpringBeanByType
81
    private INameService nameService;
82

  
83
    @SpringBeanByType
84
    private IReferenceService referenceService;
85

  
86
    @SpringBeanByType
87
    private ITaxonNodeService taxonNodeService;
88

  
89
    @SpringBeanByType
90
    private IDescriptionService descriptionService;
91

  
92
    @SpringBeanByType
93
    private IUserService userService;
94

  
95
    @SpringBeanByType
96
    private IClassificationService classificationService;
97

  
98
    @SpringBeanByType
99
    private AuthenticationManager authenticationManager;
100

  
101
    @SpringBeanByType
102
    private SaltSource saltSource;
103

  
104
    @SpringBeanByType
105
    private PasswordEncoder passwordEncoder;
106

  
107
    @SpringBean("cdmPermissionEvaluator")
108
    private CdmPermissionEvaluator permissionEvaluator;
109

  
110
    @TestDataSource
111
    protected DataSource dataSource;
112

  
113
    private Authentication authentication;
114

  
115

  
116
    /**
117
     * no assertions in this test, since it is only used to create password hashes for test data
118
     */
119
    @Test
120
    public void testEncryptPassword(){
121

  
122
        String password = PASSWORD_ADMIN;
123
        User user = User.NewInstance("userManager", "");
124

  
125
        Object salt = this.saltSource.getSalt(user);
126
        String passwordEncrypted = passwordEncoder.encodePassword(password, salt);
127
        logger.info("encrypted password: " + passwordEncrypted );
128
    }
129

  
130
    @Test
131
    @DataSet
132
    public void testHasPermission(){
133

  
134
        Taxon taxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()),null);
135

  
136
        authentication = authenticationManager.authenticate(tokenForTaxonomist);
137
        boolean hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.UPDATE);
138
        assertTrue(hasPermission);
139

  
140
        authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
141
        hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.UPDATE);
142
        assertFalse(hasPermission);
143
    }
144

  
145
    @Test
146
    @DataSet
147
    public void testListByUsernameAllow(){
148

  
149
        authentication = authenticationManager.authenticate(tokenForTaxonomist);
150
        SecurityContext context = SecurityContextHolder.getContext();
151
        context.setAuthentication(authentication);
152

  
153
        List<User> userList = userService.listByUsername("Editor", MatchMode.ANYWHERE, null, null, 0, null, null);
154
        Assert.assertTrue("The user list must have elements", userList.size() > 0 );
155
    }
156

  
157
    @Test
158
    @DataSet
159
    public void testUserService_CreateDeny(){
160

  
161
        authentication = authenticationManager.authenticate(tokenForTaxonomist);
162
        SecurityContext context = SecurityContextHolder.getContext();
163
        context.setAuthentication(authentication);
164

  
165
        RuntimeException exception = null;
166
        try {
167
            userService.createUser(User.NewInstance("new guy", "alkjdsfalkj"));
168
            commitAndStartNewTransaction(null);
169
        } catch (AccessDeniedException e){
170
            logger.debug("Expected failure of evaluation.", e);
171
            exception = e;
172
        } catch (RuntimeException e){
173
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
174
            logger.debug("Expected failure of evaluation.", e);
175
        } finally {
176
            // needed in case saveOrUpdate was interrupted by the RuntimeException
177
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
178
            endTransaction();
179
            startNewTransaction();
180
        }
181
        Assert.assertNotNull("Must fail here!", exception);
182

  
183
    }
184

  
185
    @Test
186
    @DataSet
187
    public void testUserService_CreateAllow(){
188

  
189
        authentication = authenticationManager.authenticate(tokenForUserManager);
190
        SecurityContext context = SecurityContextHolder.getContext();
191
        context.setAuthentication(authentication);
192

  
193
        RuntimeException exception = null;
194
        try {
195
            userService.createUser(User.NewInstance("new guy", "alkjdsfalkj"));
196
            commitAndStartNewTransaction(null);
197
        } catch (AccessDeniedException e){
198
            logger.error("Unexpected failure of evaluation.", e);
199
            exception = e;
200
        } catch (RuntimeException e){
201
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
202
            logger.error("unexpected failure of evaluation.", exception);
203
        } finally {
204
            // needed in case saveOrUpdate was interrupted by the RuntimeException
205
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
206
            endTransaction();
207
            startNewTransaction();
208
        }
209
        Assert.assertNull("Must not fail here!", exception);
210

  
211
    }
212

  
213

  
214
    @Test
215
    @DataSet
216
    @Ignore // FIXME http://dev.e-taxonomy.eu/trac/ticket/3098
217
    public void testHasPermissions(){
218

  
219
        Taxon taxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()),null);
220

  
221
        authentication = authenticationManager.authenticate(tokenForTaxonomist);
222
        boolean hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.ALL);
223
        assertTrue(hasPermission);
224
    }
225

  
226

  
227
    /**
228
     * Test method for {@link eu.etaxonomy.cdm.api.service.TaxonServiceImpl#saveTaxon(eu.etaxonomy.cdm.model.taxon.TaxonBase)}.
229
     */
230
    @Test
231
    public final void testSaveTaxon() {
232

  
233
        authentication = authenticationManager.authenticate(tokenForAdmin);
234
        SecurityContext context = SecurityContextHolder.getContext();
235
        context.setAuthentication(authentication);
236

  
237
        Taxon expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);
238
        expectedTaxon.getName().setTitleCache("Newby admin", true);
239
        UUID uuid = taxonService.save(expectedTaxon).getUuid();
240
        commitAndStartNewTransaction(null);
241
        TaxonBase<?> actualTaxon = taxonService.load(uuid);
242
        assertEquals(expectedTaxon, actualTaxon);
243

  
244
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
245
        context = SecurityContextHolder.getContext();
246
        context.setAuthentication(authentication);
247
        expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()), null);
248
        expectedTaxon.getName().setTitleCache("Newby taxonEditor", true);
249
        uuid = taxonService.saveOrUpdate(expectedTaxon);
250
        commitAndStartNewTransaction(null);
251
        actualTaxon = taxonService.load(uuid);
252
        assertEquals(expectedTaxon, actualTaxon);
253

  
254
    }
255

  
256
    @Test
257
    public final void testSaveNameAllow() {
258

  
259
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
260
        SecurityContext context = SecurityContextHolder.getContext();
261
        context.setAuthentication(authentication);
262

  
263
        ZoologicalName newName = ZoologicalName.NewInstance(Rank.SPECIES());
264
        newName.setTitleCache("Newby taxonEditor", true);
265
        UUID uuid = nameService.saveOrUpdate(newName);
266
        commitAndStartNewTransaction(null);
267
        TaxonNameBase savedName = nameService.load(uuid);
268
        assertEquals(newName, savedName);
269
    }
270

  
271

  
272
    @Test
273
    public final void testReuseNameAllow() {
274

  
275
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
276
        SecurityContext context = SecurityContextHolder.getContext();
277
        context.setAuthentication(authentication);
278

  
279
        TaxonBase taxon = taxonService.find(UUID_ACHERONTIA_STYX);
280
        TaxonNameBase n_acherontia_thetis = taxon.getName();
281

  
282
        Taxon newTaxon = Taxon.NewInstance(n_acherontia_thetis, ReferenceFactory.newGeneric());
283
        Exception exception = null;
284
        try {
285
            UUID uuid = taxonService.save(newTaxon).getUuid();
286
            commitAndStartNewTransaction(null);
287
        } catch (AccessDeniedException e){
288
            logger.error("Unexpected failure of evaluation.", e);
289
            exception = e;
290
        } catch (RuntimeException e){
291
            logger.error("Unexpected failure of evaluation.", e);
292
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
293
        } finally {
294
            // needed in case saveOrUpdate was interrupted by the RuntimeException
295
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
296
            endTransaction();
297
            startNewTransaction();
298
        }
299
        Assert.assertNull("must not fail here!", exception);
300
    }
301

  
302
    @Test
303
    public final void testMakeTaxonNodeASynonymOfAnotherTaxonNodeAllow_1() {
304

  
305
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
306
        SecurityContext context = SecurityContextHolder.getContext();
307
        context.setAuthentication(authentication);
308

  
309
        Reference book = referenceService.load(BOOK1_UUID);
310

  
311
        TaxonNode n_acherontia_styx = taxonNodeService.find(ACHERONTIA_STYX_NODE_UUID);
312
        TaxonNode n_acherontia_lachersis = taxonNodeService.find(ACHERONTIA_LACHESIS_NODE_UUID);
313

  
314
        Exception exception = null;
315
        try {
316
            taxonNodeService.makeTaxonNodeASynonymOfAnotherTaxonNode(n_acherontia_styx, n_acherontia_lachersis, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), book , "33");
317
            commitAndStartNewTransaction(null);
318
        } catch (AccessDeniedException e){
319
            logger.error("Unexpected failure of evaluation.", e);
320
            exception = e;
321
        } catch (RuntimeException e){
322
            logger.error("Unexpected failure of evaluation.", e);
323
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
324
        }finally {
325
            // needed in case saveOrUpdate was interrupted by the RuntimeException
326
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
327
            endTransaction();
328
            startNewTransaction();
329
        }
330
        Assert.assertNull("must not fail here!", exception);
331
    }
332

  
333
    @Test
334
    public final void testMakeTaxonNodeASynonymOfAnotherTaxonNodeAllow_2() {
335

  
336
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
337
        SecurityContext context = SecurityContextHolder.getContext();
338
        context.setAuthentication(authentication);
339

  
340
        Reference book = referenceService.load(BOOK1_UUID);
341

  
342
        TaxonNode n_acherontia_styx = taxonNodeService.find(ACHERONTIA_STYX_NODE_UUID);
343
        TaxonNode n_acherontia_lachersis = taxonNodeService.find(ACHERONTIA_LACHESIS_NODE_UUID);
344

  
345
        Exception exception = null;
346
        try {
347
            taxonNodeService.makeTaxonNodeASynonymOfAnotherTaxonNode(n_acherontia_lachersis, n_acherontia_styx, SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF(), book , "33");
348
            commitAndStartNewTransaction(null);
349
        } catch (AccessDeniedException e){
350
            logger.error("Unexpected failure of evaluation.", e);
351
            exception = e;
352
        } catch (RuntimeException e){
353
            logger.error("Unexpected failure of evaluation.", e);
354
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
355
        }  finally {
356
            // needed in case saveOrUpdate was interrupted by the RuntimeException
357
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
358
            endTransaction();
359
            startNewTransaction();
360
        }
361
        Assert.assertNull("must not fail here!", exception);
362
    }
363

  
364
    @Test
365
    public final void testUpdateReferenceAllow() throws ParsingException {
366

  
367

  
368
        authentication = authenticationManager.authenticate(tokenForUserManager);
369
        SecurityContext context = SecurityContextHolder.getContext();
370
        context.setAuthentication(authentication);
371

  
372
        // add REFERENCE[UPDATE] to taxonEditor
373
        User taxonEditor = userService.load(TAXON_EDITOR_UUID);
374
        Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();
375
        grantedAuthorities.addAll(taxonEditor.getGrantedAuthorities());
376
        GrantedAuthorityImpl referenceUpdate_ga = new CdmAuthority(CdmPermissionClass.REFERENCE, null, EnumSet.of(CRUD.UPDATE), null).asNewGrantedAuthority();
377
        grantedAuthorities.add(referenceUpdate_ga);
378
        taxonEditor.setGrantedAuthorities(grantedAuthorities);
379
        userService.saveOrUpdate(taxonEditor);
380
        commitAndStartNewTransaction(null);
381

  
382
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
383
        context = SecurityContextHolder.getContext();
384
        context.setAuthentication(authentication);
385

  
386
        Reference book = referenceService.load(BOOK1_UUID);
387
        book.setTitleCache("Mobydick", true);
388
        Exception exception = null;
389
        try {
390
            referenceService.saveOrUpdate(book);
391
            commitAndStartNewTransaction(null);
392
        } catch (AccessDeniedException e){
393
            logger.error("Unexpected failure of evaluation.", e);
394
            exception = e;
395
        } catch (RuntimeException e){
396
            logger.error("Unexpected failure of evaluation.", e);
397
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
398
        } finally {
399
            // needed in case saveOrUpdate was interrupted by the RuntimeException
400
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
401
            endTransaction();
402
            startNewTransaction();
403
        }
404
        Assert.assertNull("must not fail here!", exception);
405
        book = referenceService.load(BOOK1_UUID);
406
        Assert.assertEquals("Mobydick", book.getTitleCache());
407
    }
408

  
409
    @Test
410
    public final void testUpateReferenceDeny() {
411

  
412
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
413
        SecurityContext context = SecurityContextHolder.getContext();
414
        context.setAuthentication(authentication);
415

  
416
        TaxonBase taxon = taxonService.find(UUID_ACHERONTIA_STYX);
417
        taxon.getName().getNomenclaturalReference().setTitleCache("Mobydick", true);
418
        Exception exception = null;
419
        try {
420
            UUID uuid = taxonService.saveOrUpdate(taxon);
421
            commitAndStartNewTransaction(null);
422
        } catch (AccessDeniedException e){
423
            logger.debug("Expected failure of evaluation.", e);
424
            exception  = e;
425
        } catch (RuntimeException e){
426
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
427
            logger.debug("Expected failure of evaluation.", e);
428
        } finally {
429
            // needed in case saveOrUpdate was interrupted by the RuntimeException
430
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
431
            endTransaction();
432
            startNewTransaction();
433
        }
434
        Assert.assertNotNull("must fail here!", exception);
435
    }
436

  
437
    @Test
438
    public void testChangeOwnPassword(){
439

  
440
        SecurityContext context = SecurityContextHolder.getContext();
441
        // authenticate as admin
442
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
443
        context.setAuthentication(authentication);
444

  
445
//        User currentUser =  (User) context.getAuthentication().getPrincipal();
446

  
447
        String newPass = "poiweorijo";
448
        userService.changePassword(PASSWORD_TAXON_EDITOR, newPass);
449
        commitAndStartNewTransaction(null);
450

  
451
        // try to re-authenticate user with changed password
452
        UsernamePasswordAuthenticationToken newTokenForTaxonEditor = new UsernamePasswordAuthenticationToken("taxonEditor", newPass);
453
        authentication = authenticationManager.authenticate(newTokenForTaxonEditor);
454
    }
455

  
456
    @Test
457
    public void testChangeOthersPasswordAllow(){
458

  
459
        SecurityContext context = SecurityContextHolder.getContext();
460
        RuntimeException exception = null;
461

  
462
        // (1) authenticate as admin
463
        authentication = authenticationManager.authenticate(tokenForAdmin);
464
        context.setAuthentication(authentication);
465

  
466

  
467
        try{
468
            userService.changePasswordForUser("taxonomist", "zuaisd");
469
            commitAndStartNewTransaction(null);
470
        } catch (AccessDeniedException e){
471
            logger.error("Unexpected failure of evaluation.", e);
472
            exception = e;
473
        } catch (RuntimeException e){
474
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
475
            logger.error("Unexpected failure of evaluation.", exception);
476
        } finally {
477
            // needed in case saveOrUpdate was interrupted by the RuntimeException
478
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
479
            endTransaction();
480
            startNewTransaction();
481
        }
482
        Assert.assertNull("must not fail here!", exception);
483

  
484
        // ok, now try authenticating taxonomist with new password
485
        UsernamePasswordAuthenticationToken newToken = new UsernamePasswordAuthenticationToken("taxonomist", "zuaisd");
486
        authentication = authenticationManager.authenticate(newToken);
487
    }
488

  
489
    @Test
490
    public void testChangeOthersPasswordDeny(){
491

  
492
        SecurityContext context = SecurityContextHolder.getContext();
493
        RuntimeException exception = null;
494

  
495
        // (2) authenticate as under privileged user - not an admin !!!
496
        authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
497
        context.setAuthentication(authentication);
498

  
499
        // check test preconditions user name and authorities
500
        Assert.assertEquals("descriptionEditor", context.getAuthentication().getName());
501
        Collection<? extends GrantedAuthority> authorities = context.getAuthentication().getAuthorities();
502
        for(GrantedAuthority authority: authorities){
503
            // role prefix 'ROLE_' is defined in org.springframework.security.access.vote.RoleVoter !!!
504
            Assert.assertNotSame("user must not have authority 'ROLE_ADMIN'", "ROLE_ADMIN", authority.getAuthority());
505
        }
506
        // finally perform the test :
507
        try{
508
            userService.changePasswordForUser("partEditor", "poiweorijo");
509
            commitAndStartNewTransaction(null);
510
        } catch (AccessDeniedException e){
511
            logger.debug("Expected failure of evaluation.", e);
512
            exception = e;
513
        } catch (RuntimeException e){
514
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
515
            logger.debug("Expected failure of evaluation.", e);
516
        } finally {
517
            // needed in case saveOrUpdate was interrupted by the RuntimeException
518
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
519
            endTransaction();
520
            startNewTransaction();
521
        }
522
        Assert.assertNotNull("must fail here!", exception);
523
    }
524

  
525
    @Test
526
    public void testUpdateUser(){
527

  
528
        authentication = authenticationManager.authenticate(tokenForAdmin);
529
        SecurityContext context = SecurityContextHolder.getContext();
530
        context.setAuthentication(authentication);
531
        String username = "standardUser";
532
        String password = "pw";
533
        User user = User.NewInstance(username, password);
534

  
535
        userService.createUser(user);
536
        user.setEmailAddress("test@bgbm.org");
537

  
538
        userService.updateUser(user);
539
        userService.update(user);
540
        userService.saveOrUpdate(user);
541
        commitAndStartNewTransaction(null);
542

  
543
    }
544

  
545
    /**
546
     * test with admin account - should succeed
547
     */
548
    @Test
549
    public final void testTaxonSaveOrUpdateAllow_1() {
550

  
551
        SecurityContext context = SecurityContextHolder.getContext();
552

  
553
        authentication = authenticationManager.authenticate(tokenForAdmin);
554
        context.setAuthentication(authentication);
555
        RuntimeException securityException= null;
556

  
557
        TaxonBase<?> taxon = taxonService.find(UUID_ACHERONTIA_STYX);
558
        Assert.assertFalse(taxon.isDoubtful());
559
        taxon.setDoubtful(true);
560
        try{
561
            taxonService.saveOrUpdate(taxon);
562
            commitAndStartNewTransaction(null);
563
        } catch (RuntimeException e){
564
            securityException  = findSecurityRuntimeException(e);
565
            logger.error("Unexpected failure of evaluation.", e);
566
        } finally {
567
            // needed in case saveOrUpdate was interrupted by the RuntimeException
568
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
569
            endTransaction();
570
            startNewTransaction();
571
        }
572
        Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
573
        // reload taxon
574
        taxon = taxonService.find(UUID_ACHERONTIA_STYX);
575
        Assert.assertTrue("The change must be persisted", taxon.isDoubtful());
576
    }
577

  
578
    /**
579
     * test with taxonEditor account - should succeed
580
     */
581
    @Test
582
    public final void testTaxonSaveOrUpdateAllow_2() {
583

  
584

  
585
        RuntimeException securityException= null;
586
        SecurityContext context = SecurityContextHolder.getContext();
587

  
588
         // taxonEditor account - should succeed
589
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
590

  
591
        context.setAuthentication(authentication);
592

  
593
        TaxonBase<?>  taxon = taxonService.find(UUID_ACHERONTIA_STYX);
594
        Assert.assertFalse(taxon.isDoubtful());
595
        taxon.setDoubtful(true);
596
        try{
597
            taxonService.saveOrUpdate(taxon);
598
            commitAndStartNewTransaction(null);
599
        } catch (RuntimeException e){
600
            securityException  = findSecurityRuntimeException(e);
601
            logger.error("Unexpected failure of evaluation.", e);
602
        } finally {
603
            // needed in case saveOrUpdate was interrupted by the RuntimeException
604
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
605
            endTransaction();
606
            startNewTransaction();
607
        }
608
        Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
609
        // reload taxon
610
        taxon = taxonService.find(UUID_ACHERONTIA_STYX);
611
        Assert.assertTrue("The change must be persited", taxon.isDoubtful());
612
    }
613

  
614
    /**
615
     * test with tokenForDescriptionEditor account - should fail
616
     */
617
    @Test
618
    public final void testTaxonSaveOrUpdateDeny_2() {
619

  
620
        SecurityContext context = SecurityContextHolder.getContext();
621
        RuntimeException securityException = null;
622

  
623
        authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
624
        context.setAuthentication(authentication);
625

  
626
        TaxonBase<?> taxon = taxonService.find(UUID_ACHERONTIA_STYX);
627

  
628
        Assert.assertFalse(taxon.isDoubtful());
629
        taxon.setDoubtful(true);
630
        try {
631
            taxonService.saveOrUpdate(taxon);
632
            commitAndStartNewTransaction(null);
633
        } catch (RuntimeException e){
634
            securityException = findSecurityRuntimeException(e);
635
            logger.debug("Expected failure of evaluation.", securityException);
636
        } finally {
637
            // needed in case saveOrUpdate was interrupted by the RuntimeException
638
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
639
            endTransaction();
640
            startNewTransaction();
641
        }
642

  
643
        Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);
644
        // reload taxon
645
        taxon = taxonService.find(UUID_ACHERONTIA_STYX);
646
        Assert.assertFalse("The change must not be persited", taxon.isDoubtful());
647
    }
648

  
649
    @Test
650
    public final void testTaxonPublishAllow_ROLE_ADMIN() {
651

  
652
        SecurityContext context = SecurityContextHolder.getContext();
653

  
654
        authentication = authenticationManager.authenticate(tokenForAdmin);
655
        context.setAuthentication(authentication);
656
        RuntimeException securityException= null;
657

  
658
        Taxon taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
659

  
660
        boolean lastIsPublish = taxon.isPublish();
661
        taxon.setPublish(!lastIsPublish);
662
        try{
663
            taxonService.saveOrUpdate(taxon);
664
            commitAndStartNewTransaction(null);
665
        } catch (RuntimeException e){
666
            securityException  = findSecurityRuntimeException(e);
667
            logger.error("Unexpected failure of evaluation.", e);
668
        } finally {
669
            // needed in case saveOrUpdate was interrupted by the RuntimeException
670
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
671
            endTransaction();
672
            startNewTransaction();
673
        }
674
        Assert.assertNull("evaluation must not fail since the user has ROLE_ADMIN, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
675
        // reload taxon
676
        taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
677
        Assert.assertTrue("The change must be persisted", taxon.isPublish() != lastIsPublish);
678
    }
679

  
680

  
681
    /**
682
     * test with Taxonomist account which has the ROLE_PUBLISH
683
     */
684
    @Test
685
    public final void testTaxonPublishAllow_ROLE_PUBLISH() {
686

  
687
        SecurityContext context = SecurityContextHolder.getContext();
688

  
689
        authentication = authenticationManager.authenticate(tokenForTaxonomist);
690
        context.setAuthentication(authentication);
691
        RuntimeException securityException= null;
692

  
693
        Taxon taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
694

  
695
        boolean lastIsPublish = taxon.isPublish();
696
        taxon.setPublish(!lastIsPublish);
697
        try{
698
            taxonService.saveOrUpdate(taxon);
699
            commitAndStartNewTransaction(null);
700
        } catch (RuntimeException e){
701
            securityException  = findSecurityRuntimeException(e);
702
            logger.error("Unexpected failure of evaluation.", e);
703
        } finally {
704
            // needed in case saveOrUpdate was interrupted by the RuntimeException
705
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
706
            endTransaction();
707
            startNewTransaction();
708
        }
709
        Assert.assertNull("evaluation must not fail since the user has ROLE_ADMIN, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
710
        // reload taxon
711
        taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
712
        Assert.assertTrue("The change must be persisted", taxon.isPublish() != lastIsPublish);
713
    }
714

  
715
    /**
716
     * test with TaxonEditor account which has not the ROLE_PUBLISH
717
     */
718
    @Test
719
    public final void testTaxonPublishDeny() {
720

  
721
        SecurityContext context = SecurityContextHolder.getContext();
722

  
723
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
724
        context.setAuthentication(authentication);
725
        RuntimeException securityException= null;
726

  
727
        Taxon taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
728

  
729
        boolean lastIsPublish = taxon.isPublish();
730
        taxon.setPublish(!lastIsPublish);
731
        try {
732
            taxonService.saveOrUpdate(taxon);
733
            commitAndStartNewTransaction(null);
734
        } catch (RuntimeException e){
735
            securityException = findSecurityRuntimeException(e);
736
            logger.debug("Expected failure of evaluation.", securityException);
737
        } finally {
738
            // needed in case saveOrUpdate was interrupted by the RuntimeException
739
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
740
            endTransaction();
741
            startNewTransaction();
742
        }
743

  
744
        Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);
745
        // reload taxon
746
        taxon = (Taxon) taxonService.find(UUID_ACHERONTIA_STYX);
747
        Assert.assertTrue("The taxon must be unchanged", taxon.isPublish() == lastIsPublish);
748
    }
749

  
750
    /**
751
     * test with admin account - should succeed
752
     */
753
    @Test
754
    public final void testTaxonDeleteAllow_1() {
755

  
756
        SecurityContext context = SecurityContextHolder.getContext();
757

  
758
        authentication = authenticationManager.authenticate(tokenForAdmin);
759
        context.setAuthentication(authentication);
760
        RuntimeException securityException= null;
761

  
762
        TaxonBase<?> taxon = taxonService.load(UUID_LACTUCA);
763
        taxonService.delete(taxon);
764
        commitAndStartNewTransaction(null);
765

  
766

  
767

  
768

  
769
        Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
770
        // reload taxon
771
        taxon = taxonService.load(UUID_LACTUCA);
772
        Assert.assertNull("The taxon must be deleted", taxon);
773
    }
774

  
775
    /**
776
     * test with admin account - should succeed
777
     */
778
    @Test
779
   public final void testTaxonDeleteAllow_2() {
780

  
781
        SecurityContext context = SecurityContextHolder.getContext();
782

  
783
        authentication = authenticationManager.authenticate(tokenForAdmin);
784
        context.setAuthentication(authentication);
785
        RuntimeException securityException= null;
786

  
787
        Taxon taxon = (Taxon)taxonService.load(UUID_ACHERONTINII);
788
        try{
789
           // try {
790
        	DeleteResult result = taxonService.deleteTaxon(taxon.getUuid(), null, null);
791
            /*} catch (DataChangeNoRollbackException e) {
792
                Assert.fail();
793
            }*/
794
            if (!result.isOk()){
795
            	Assert.fail();
796
            }
797
            commitAndStartNewTransaction(null);
798
        } catch (RuntimeException e){
799
            securityException  = findSecurityRuntimeException(e);
800
            logger.error("Unexpected failure of evaluation.", e);
801
        } finally {
802
            // needed in case saveOrUpdate was interrupted by the RuntimeException
803
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
804
            endTransaction();
805
            startNewTransaction();
806
        }
807
        Assert.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + (securityException != null ? securityException.getMessage() : ""), securityException);
808
        // reload taxon
809

  
810
        taxon = (Taxon)taxonService.find(UUID_ACHERONTINII);
811
        Assert.assertNull("The taxon must be deleted", taxon);
812
    }
813

  
814

  
815
    /**
816
     * test with tokenForDescriptionEditor account - should fail
817
     */
818
    @Test
819
    public final void testTaxonDeleteDeny() {
820

  
821
        SecurityContext context = SecurityContextHolder.getContext();
822
        RuntimeException securityException = null;
823

  
824
        authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
825
        context.setAuthentication(authentication);
826

  
827
        Taxon taxon = (Taxon)taxonService.load(UUID_LACTUCA);
828
        try{
829
        DeleteResult result = taxonService.deleteTaxon(taxon.getUuid(), null, null);
830
        Assert.fail();
831
        }catch(PermissionDeniedException e){
832

  
833
        }
834
       endTransaction();
835
       startNewTransaction();
836

  
837

  
838
        //Assert.assertNotNull("evaluation must fail since the user is not permitted", securityException);
839
        // reload taxon
840
        taxon = (Taxon)taxonService.load(UUID_LACTUCA);
841

  
842
        Assert.assertNotNull("The change must still exist", taxon);
843
        Assert.assertNotNull("The name must still exist",taxon.getName());
844
    }
845

  
846

  
847
    @Test
848
    @Ignore //FIXME: adding taxa to a description must be protected at the side of the Description itself!!
849
            //        => protecting method TaxonDescription.setTaxon() ?
850
    public void testAddDescriptionToTaxon(){
851

  
852
        SecurityContext context = SecurityContextHolder.getContext();
853
        authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
854
        context.setAuthentication(authentication);
855

  
856
        RuntimeException securityException = null;
857

  
858
        Taxon taxon = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);
859

  
860
        TaxonDescription description = TaxonDescription.NewInstance(taxon);
861
        description.setTitleCache("test");
862
        try {
863
            descriptionService.saveOrUpdate(description);
864
            commitAndStartNewTransaction(null);
865
        } catch (RuntimeException e){
866
            securityException = findSecurityRuntimeException(e);
867
            logger.debug("Expected failure of evaluation.", securityException);
868
        } finally {
869
            // needed in case saveOrUpdate was interrupted by the RuntimeException
870
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
871
            endTransaction();
872
            startNewTransaction();
873
        }
874
        /*
875
         * Expectation:
876
         * The user should not be granted to add the Description to a taxon
877
         */
878
        Assert.assertNotNull("evaluation should fail since the user is not permitted to edit Taxa", securityException);
879
        taxon = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);
880
        assertTrue(taxon.getDescriptions().contains(description));
881
    }
882

  
883
    @Test
884
    public void testMoveDescriptionElement(){
885

  
886
        SecurityContext context = SecurityContextHolder.getContext();
887
        authentication = authenticationManager.authenticate(tokenForTaxonomist);
888
        context.setAuthentication(authentication);
889

  
890
        RuntimeException securityException = null;
891

  
892
        Taxon t_acherontia_lachesis = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);
893
        Taxon t_acherontia_styx = (Taxon)taxonService.load(UUID_ACHERONTIA_STYX);
894

  
895
        TaxonDescription description_acherontia_styx = t_acherontia_styx.getDescriptions().iterator().next();
896
        TaxonDescription description_acherontia_lachesis = t_acherontia_lachesis.getDescriptions().iterator().next();
897

  
898
        try {
899
            descriptionService.moveDescriptionElementsToDescription(description_acherontia_styx.getElements(), description_acherontia_lachesis, false);
900
            commitAndStartNewTransaction(null);
901
        } catch (RuntimeException e){
902
            securityException = findSecurityRuntimeException(e);
903
            logger.debug("Unexpected failure of evaluation.", securityException);
904
        } finally {
905
            // needed in case saveOrUpdate was interrupted by the RuntimeException
906
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
907
            endTransaction();
908
            startNewTransaction();
909
        }
910
        /*
911
         * Expectation:
912
         */
913
        Assert.assertNull("evaluation should not fail since the user has sufficient permissions", securityException);
914

  
915
    }
916

  
917
//    @Ignore // FIXME http://dev.e-taxonomy.eu/trac/ticket/4081 : #4081 (TaxonNodeServiceImpl.makeTaxonNodeASynonymOfAnotherTaxonNode() requires TAXONNAMEBASE.[UPDATE])
918
    @Test
919
    public void testAcceptedTaxonToSynomym(){
920

  
921
        SecurityContext context = SecurityContextHolder.getContext();
922
        authentication = authenticationManager.authenticate(tokenForPartEditor);
923
        context.setAuthentication(authentication);
924

  
925
        RuntimeException securityException = null;
926

  
927
        Taxon t_acherontia_lachesis = (Taxon)taxonService.load(ACHERONTIA_LACHESIS_UUID);
928
        UUID name_acherontia_lachesis_uuid = t_acherontia_lachesis.getName().getUuid();
929
        Taxon t_acherontia_styx = (Taxon)taxonService.load(UUID_ACHERONTIA_STYX);
930
        int countSynsBefore = t_acherontia_styx.getSynonyms().size();
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

  
939
        try {
940
            DeleteResult result = taxonNodeService.makeTaxonNodeASynonymOfAnotherTaxonNode(n_acherontia_lachesis, n_acherontia_styx, SynonymRelationshipType.SYNONYM_OF(), null, null);
941
//            synonymUuid = synonym.getUuid();
942
//            taxonService.saveOrUpdate(synonym);
943
            commitAndStartNewTransaction(null);
944
        } catch (RuntimeException e){
945
            securityException = findSecurityRuntimeException(e);
946
            logger.error("Unexpected Exception ", e);
947
            Assert.fail("Unexpected Exception: " + e.getMessage());
948
        } finally {
949
            // needed in case saveOrUpdate was interrupted by the RuntimeException
950
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
951
            endTransaction();
952
            startNewTransaction();
953
        }
954
        /*
955
         * Expectation:
956
         */
957
        Assert.assertNull("evaluation should not fail since the user has sufficient permissions", securityException);
958

  
959
        // reload from db and check assertions
960
        t_acherontia_styx = (Taxon)taxonService.load(UUID_ACHERONTIA_STYX);
961
        Assert.assertEquals(numOfSynonymsBefore_styx +1 + numOfSynonymsBefore_lachesis, t_acherontia_styx.getSynonyms().size());
962

  
963
        Assert.assertNotNull(nameService.load(name_acherontia_lachesis_uuid) );
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
    /* (non-Javadoc)
1210
     * @see eu.etaxonomy.cdm.test.integration.CdmIntegrationTest#createTestData()
1211
     */
1212
    @Override
1213
    public void createTestDataSet() throws FileNotFoundException {
1214
        // TODO Auto-generated method stub
1215

  
1216
    }
1217

  
1218
}
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.io.FileNotFoundException;
16
import java.util.Collection;
17
import java.util.EnumSet;
18
import java.util.HashSet;
19
import java.util.List;
20
import java.util.Set;
21
import java.util.UUID;
22

  
23
import javax.sql.DataSource;
24

  
25
import org.apache.log4j.Logger;
26
import org.junit.Assert;
27
import org.junit.Ignore;
28
import org.junit.Test;
29
import org.springframework.security.access.AccessDeniedException;
30
import org.springframework.security.authentication.AuthenticationManager;
31
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
32
import org.springframework.security.authentication.dao.SaltSource;
33
import org.springframework.security.authentication.encoding.PasswordEncoder;
34
import org.springframework.security.core.Authentication;
35
import org.springframework.security.core.GrantedAuthority;
36
import org.springframework.security.core.context.SecurityContext;
37
import org.springframework.security.core.context.SecurityContextHolder;
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.database.PermissionDeniedException;
45
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
46
import eu.etaxonomy.cdm.model.common.User;
47
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
48
import eu.etaxonomy.cdm.model.description.Feature;
49
import eu.etaxonomy.cdm.model.description.TaxonDescription;
50
import eu.etaxonomy.cdm.model.description.TextData;
51
import eu.etaxonomy.cdm.model.name.BotanicalName;
52
import eu.etaxonomy.cdm.model.name.Rank;
53
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
54
import eu.etaxonomy.cdm.model.name.ZoologicalName;
55
import eu.etaxonomy.cdm.model.reference.Reference;
56
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
57
import eu.etaxonomy.cdm.model.taxon.Classification;
58
import eu.etaxonomy.cdm.model.taxon.Synonym;
59
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
60
import eu.etaxonomy.cdm.model.taxon.Taxon;
61
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
62
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
63
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
64
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
65
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionClass;
66
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionEvaluator;
67
import eu.etaxonomy.cdm.persistence.hibernate.permission.Operation;
68
import eu.etaxonomy.cdm.persistence.query.MatchMode;
69

  
70

  
71
@DataSet
72
public class SecurityTest extends AbstractSecurityTestBase{
73

  
74

  
75
    private static final Logger logger = Logger.getLogger(SecurityTest.class);
76

  
77
    @SpringBeanByType
78
    private ITaxonService taxonService;
79

  
80
    @SpringBeanByType
81
    private INameService nameService;
82

  
83
    @SpringBeanByType
84
    private IReferenceService referenceService;
85

  
86
    @SpringBeanByType
87
    private ITaxonNodeService taxonNodeService;
88

  
89
    @SpringBeanByType
90
    private IDescriptionService descriptionService;
91

  
92
    @SpringBeanByType
93
    private IUserService userService;
94

  
95
    @SpringBeanByType
96
    private IClassificationService classificationService;
97

  
98
    @SpringBeanByType
99
    private AuthenticationManager authenticationManager;
100

  
101
    @SpringBeanByType
102
    private SaltSource saltSource;
103

  
104
    @SpringBeanByType
105
    private PasswordEncoder passwordEncoder;
106

  
107
    @SpringBean("cdmPermissionEvaluator")
108
    private CdmPermissionEvaluator permissionEvaluator;
109

  
110
    @TestDataSource
111
    protected DataSource dataSource;
112

  
113
    private Authentication authentication;
114

  
115

  
116
    /**
117
     * no assertions in this test, since it is only used to create password hashes for test data
118
     */
119
    @Test
120
    public void testEncryptPassword(){
121

  
122
        String password = PASSWORD_ADMIN;
123
        User user = User.NewInstance("userManager", "");
124

  
125
        Object salt = this.saltSource.getSalt(user);
126
        String passwordEncrypted = passwordEncoder.encodePassword(password, salt);
127
        logger.info("encrypted password: " + passwordEncrypted );
128
    }
129

  
130
    @Test
131
    @DataSet
132
    public void testHasPermission(){
133

  
134
        Taxon taxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()),null);
135

  
136
        authentication = authenticationManager.authenticate(tokenForTaxonomist);
137
        boolean hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.UPDATE);
138
        assertTrue(hasPermission);
139

  
140
        authentication = authenticationManager.authenticate(tokenForDescriptionEditor);
141
        hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.UPDATE);
142
        assertFalse(hasPermission);
143
    }
144

  
145
    @Test
146
    @DataSet
147
    public void testListByUsernameAllow(){
148

  
149
        authentication = authenticationManager.authenticate(tokenForTaxonomist);
150
        SecurityContext context = SecurityContextHolder.getContext();
151
        context.setAuthentication(authentication);
152

  
153
        List<User> userList = userService.listByUsername("Editor", MatchMode.ANYWHERE, null, null, 0, null, null);
154
        Assert.assertTrue("The user list must have elements", userList.size() > 0 );
155
    }
156

  
157
    @Test
158
    @DataSet
159
    public void testUserService_CreateDeny(){
160

  
161
        authentication = authenticationManager.authenticate(tokenForTaxonomist);
162
        SecurityContext context = SecurityContextHolder.getContext();
163
        context.setAuthentication(authentication);
164

  
165
        RuntimeException exception = null;
166
        try {
167
            userService.createUser(User.NewInstance("new guy", "alkjdsfalkj"));
168
            commitAndStartNewTransaction(null);
169
        } catch (AccessDeniedException e){
170
            logger.debug("Expected failure of evaluation.", e);
171
            exception = e;
172
        } catch (RuntimeException e){
173
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
174
            logger.debug("Expected failure of evaluation.", e);
175
        } finally {
176
            // needed in case saveOrUpdate was interrupted by the RuntimeException
177
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
178
            endTransaction();
179
            startNewTransaction();
180
        }
181
        Assert.assertNotNull("Must fail here!", exception);
182

  
183
    }
184

  
185
    @Test
186
    @DataSet
187
    public void testUserService_CreateAllow(){
188

  
189
        authentication = authenticationManager.authenticate(tokenForUserManager);
190
        SecurityContext context = SecurityContextHolder.getContext();
191
        context.setAuthentication(authentication);
192

  
193
        RuntimeException exception = null;
194
        try {
195
            userService.createUser(User.NewInstance("new guy", "alkjdsfalkj"));
196
            commitAndStartNewTransaction(null);
197
        } catch (AccessDeniedException e){
198
            logger.error("Unexpected failure of evaluation.", e);
199
            exception = e;
200
        } catch (RuntimeException e){
201
            exception = findThrowableOfTypeIn(PermissionDeniedException.class, e);
202
            logger.error("unexpected failure of evaluation.", exception);
203
        } finally {
204
            // needed in case saveOrUpdate was interrupted by the RuntimeException
205
            // commitAndStartNewTransaction() would raise an UnexpectedRollbackException
206
            endTransaction();
207
            startNewTransaction();
208
        }
209
        Assert.assertNull("Must not fail here!", exception);
210

  
211
    }
212

  
213

  
214
    @Test
215
    @DataSet
216
    @Ignore // FIXME http://dev.e-taxonomy.eu/trac/ticket/3098
217
    public void testHasPermissions(){
218

  
219
        Taxon taxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()),null);
220

  
221
        authentication = authenticationManager.authenticate(tokenForTaxonomist);
222
        boolean hasPermission = permissionEvaluator.hasPermission(authentication, taxon, Operation.ALL);
223
        assertTrue(hasPermission);
224
    }
225

  
226

  
227
    /**
228
     * Test method for {@link eu.etaxonomy.cdm.api.service.TaxonServiceImpl#saveTaxon(eu.etaxonomy.cdm.model.taxon.TaxonBase)}.
229
     */
230
    @Test
231
    public final void testSaveTaxon() {
232

  
233
        authentication = authenticationManager.authenticate(tokenForAdmin);
234
        SecurityContext context = SecurityContextHolder.getContext();
235
        context.setAuthentication(authentication);
236

  
237
        Taxon expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);
238
        expectedTaxon.getName().setTitleCache("Newby admin", true);
239
        UUID uuid = taxonService.save(expectedTaxon).getUuid();
240
        commitAndStartNewTransaction(null);
241
        TaxonBase<?> actualTaxon = taxonService.load(uuid);
242
        assertEquals(expectedTaxon, actualTaxon);
243

  
244
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
245
        context = SecurityContextHolder.getContext();
246
        context.setAuthentication(authentication);
247
        expectedTaxon = Taxon.NewInstance(BotanicalName.NewInstance(Rank.GENUS()), null);
248
        expectedTaxon.getName().setTitleCache("Newby taxonEditor", true);
249
        uuid = taxonService.saveOrUpdate(expectedTaxon);
250
        commitAndStartNewTransaction(null);
251
        actualTaxon = taxonService.load(uuid);
252
        assertEquals(expectedTaxon, actualTaxon);
253

  
254
    }
255

  
256
    @Test
257
    public final void testSaveNameAllow() {
258

  
259
        authentication = authenticationManager.authenticate(tokenForTaxonEditor);
260
        SecurityContext context = SecurityContextHolder.getContext();
261
        context.setAuthentication(authentication);
262

  
263
        ZoologicalName newName = ZoologicalName.NewInstance(Rank.SPECIES());
264
        newName.setTitleCache("Newby taxonEditor", true);
265
        UUID uuid = nameService.saveOrUpdate(newName);
266
        commitAndStartNewTransaction(null);
267
        TaxonNameBase savedName = nameService.load(uuid);
268
        assertEquals(newName, savedName);
269
    }
270

  
271

  
272
    @Test
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff