1 package eu
.etaxonomy
.cdm
.api
.service
;
3 import static org
.junit
.Assert
.assertEquals
;
4 import static org
.junit
.Assert
.assertFalse
;
5 import static org
.junit
.Assert
.assertTrue
;
8 import java
.util
.ArrayList
;
9 import java
.util
.Collection
;
10 import java
.util
.Iterator
;
11 import java
.util
.List
;
13 import java
.util
.UUID
;
15 import javax
.sql
.DataSource
;
17 import org
.apache
.log4j
.Logger
;
19 import org
.junit
.Assert
;
20 import org
.junit
.Before
;
21 import org
.junit
.Ignore
;
22 import org
.junit
.Test
;
23 import org
.junit
.runner
.RunWith
;
25 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
26 import org
.springframework
.orm
.hibernate3
.HibernateSystemException
;
27 import org
.springframework
.security
.access
.vote
.RoleVoter
;
28 import org
.springframework
.security
.authentication
.AuthenticationManager
;
29 import org
.springframework
.security
.authentication
.UsernamePasswordAuthenticationToken
;
30 import org
.springframework
.security
.authentication
.dao
.ReflectionSaltSource
;
31 import org
.springframework
.security
.authentication
.encoding
.Md5PasswordEncoder
;
32 import org
.springframework
.security
.core
.Authentication
;
33 import org
.springframework
.security
.core
.GrantedAuthority
;
34 import org
.springframework
.security
.core
.context
.SecurityContext
;
35 import org
.springframework
.security
.core
.context
.SecurityContextHolder
;
36 import org
.springframework
.test
.annotation
.ExpectedException
;
37 import org
.springframework
.transaction
.PlatformTransactionManager
;
40 import org
.unitils
.database
.annotations
.Transactional
;
41 import org
.unitils
.UnitilsJUnit4TestClassRunner
;
42 import org
.unitils
.database
.annotations
.TestDataSource
;
43 import org
.unitils
.database
.util
.TransactionMode
;
44 import org
.unitils
.dbunit
.annotation
.DataSet
;
45 import org
.unitils
.spring
.annotation
.SpringApplicationContext
;
46 import org
.unitils
.spring
.annotation
.SpringBeanByName
;
47 import org
.unitils
.spring
.annotation
.SpringBeanByType
;
50 import eu
.etaxonomy
.cdm
.api
.service
.config
.IFindTaxaAndNamesConfigurator
;
51 import eu
.etaxonomy
.cdm
.api
.service
.config
.FindTaxaAndNamesConfiguratorImpl
;
52 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
53 import eu
.etaxonomy
.cdm
.database
.EvaluationFailedException
;
54 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
55 import eu
.etaxonomy
.cdm
.model
.common
.User
;
58 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
59 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
60 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
61 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
62 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
64 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
65 import eu
.etaxonomy
.cdm
.model
.name
.BotanicalName
;
66 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
67 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
69 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
70 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
71 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
72 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
73 import eu
.etaxonomy
.cdm
.persistence
.dao
.BeanInitializer
;
74 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.permission
.CdmPermissionEvaluator
;
75 import eu
.etaxonomy
.cdm
.test
.integration
.CdmTransactionalIntegrationTest
;
76 import eu
.etaxonomy
.cdm
.test
.integration
.CdmTransactionalIntegrationTestWithSecurity
;
77 import eu
.etaxonomy
.cdm
.test
.unitils
.CleanSweepInsertLoadStrategy
;
81 public class SecurityTest
extends CdmTransactionalIntegrationTestWithSecurity
{
83 private static final UUID ACHERONTIA_NODE_UUID
= UUID
.fromString("20c8f083-5870-4cbd-bf56-c5b2b98ab6a7");
85 private static final UUID ACHERONTIINI_NODE_UUID
= UUID
.fromString("cecfa77f-f26a-4476-9d87-a8d993cb55d9");
87 private static final UUID ACHERONTIA_LACHESIS_UUID
= UUID
.fromString("bc09aca6-06fd-4905-b1e7-cbf7cc65d783");
89 private static final Logger logger
= Logger
.getLogger(SecurityTest
.class);
92 * The transaction manager to use
95 PlatformTransactionManager transactionManager
;
98 private ITaxonService taxonService
;
101 private ITaxonNodeService taxonNodeService
;
104 private IDescriptionService descriptionService
;
107 private IUserService userService
;
111 protected DataSource dataSource
;
113 private Authentication authentication
;
116 private AuthenticationManager authenticationManager
;
120 private UsernamePasswordAuthenticationToken token
;
125 token
= new UsernamePasswordAuthenticationToken("ben", "sPePhAz6");
130 * Test method for {@link eu.etaxonomy.cdm.api.service.TaxonServiceImpl#saveTaxon(eu.etaxonomy.cdm.model.taxon.TaxonBase)}.
133 public final void testSaveTaxon() {
135 Md5PasswordEncoder encoder =new Md5PasswordEncoder();
136 ReflectionSaltSource saltSource = new ReflectionSaltSource();
137 saltSource.setUserPropertyToUse("getUsername");
138 User user = User.NewInstance("partEditor", "test4");
139 System.err.println(encoder.encodePassword("test4", saltSource.getSalt(user)));
142 authentication
= authenticationManager
.authenticate(token
);
143 SecurityContext context
= SecurityContextHolder
.getContext();
144 context
.setAuthentication(authentication
);
146 Taxon expectedTaxon
= Taxon
.NewInstance(BotanicalName
.NewInstance(Rank
.SPECIES()), null);
147 UUID uuid
= taxonService
.save(expectedTaxon
);
148 //taxonService.getSession().flush();
149 TaxonBase
<?
> actualTaxon
= taxonService
.load(uuid
);
150 assertEquals(expectedTaxon
, actualTaxon
);
152 token
= new UsernamePasswordAuthenticationToken("taxonEditor", "test2");
153 authentication
= authenticationManager
.authenticate(token
);
154 context
= SecurityContextHolder
.getContext();
155 context
.setAuthentication(authentication
);
156 expectedTaxon
= Taxon
.NewInstance(BotanicalName
.NewInstance(Rank
.GENUS()), null);
157 taxonService
.saveOrUpdate(actualTaxon
);
162 public void testUpdateUser(){
164 authentication
= authenticationManager
.authenticate(token
);
165 SecurityContext context
= SecurityContextHolder
.getContext();
166 context
.setAuthentication(authentication
);
167 String username
= "standardUser";
168 String password
= "pw";
169 User user
= User
.NewInstance(username
, password
);
171 userService
.createUser(user
);
172 user
.setEmailAddress("test@bgbm.org");
174 userService
.updateUser(user
);
175 userService
.update(user
);
176 userService
.saveOrUpdate(user
);
181 public final void testSaveOrUpdateTaxon() {
182 authentication
= authenticationManager
.authenticate(token
);
183 SecurityContext context
= SecurityContextHolder
.getContext();
184 context
.setAuthentication(authentication
);
185 Taxon expectedTaxon
= Taxon
.NewInstance(null, null);
186 UUID uuid
= taxonService
.save(expectedTaxon
);
187 TaxonBase
<?
> actualTaxon
= taxonService
.load(uuid
);
188 assertEquals(expectedTaxon
, actualTaxon
);
190 actualTaxon
.setName(BotanicalName
.NewInstance(Rank
.SPECIES()));
191 taxonService
.saveOrUpdate(actualTaxon
);
193 token
= new UsernamePasswordAuthenticationToken("taxonEditor", "test2");
194 authentication
= authenticationManager
.authenticate(token
);
195 context
= SecurityContextHolder
.getContext();
196 context
.setAuthentication(authentication
);
197 actualTaxon
= taxonService
.load(uuid
);
199 actualTaxon
.setDoubtful(true);
200 taxonService
.saveOrUpdate(actualTaxon
);
205 public void testCascadingInSpringSecurityAccesDenied(){
206 /*authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("partEditor", "test4"));
207 SecurityContext context = SecurityContextHolder.getContext();
208 context.setAuthentication(authentication);
211 authentication
= authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("taxonEditor", "test2"));
212 SecurityContext context
= SecurityContextHolder
.getContext();
213 context
.setAuthentication(authentication
);
214 CdmPermissionEvaluator permissionEvaluator
= new CdmPermissionEvaluator();
216 Taxon taxon
=(Taxon
) taxonService
.load(ACHERONTIA_LACHESIS_UUID
);
217 taxon
.setDoubtful(false);
218 assertTrue(permissionEvaluator
.hasPermission(authentication
, taxon
, "UPDATE"));
219 taxonService
.save(taxon
);
221 commitAndStartNewTransaction(null);
223 //during cascading the permissions are not evaluated, but with hibernate listener every database transaction can be interrupted, but how to manage it,
224 //when someone has the rights to save descriptions, but not taxa (the editor always saves everything by saving the taxon)
225 //taxonService.saveOrUpdate(taxon);
228 authentication
= authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("descriptionEditor", "test"));
229 context
= SecurityContextHolder
.getContext();
230 context
.setAuthentication(authentication
);
232 //taxonService.saveOrUpdate(taxon);
234 taxon
=(Taxon
) taxonService
.load(ACHERONTIA_LACHESIS_UUID
);
236 TaxonDescription description
= TaxonDescription
.NewInstance(taxon
);
237 description
.setTitleCache("test");
238 descriptionService
.saveOrUpdate(description
);
239 commitAndStartNewTransaction(null);
240 taxon
= (Taxon
)taxonService
.load(ACHERONTIA_LACHESIS_UUID
);
241 assertTrue(taxon
.getDescriptions().contains(description
));
245 public void testCascadingInSpring(){
246 authentication
= authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("descriptionEditor", "test"));
247 SecurityContext context
= SecurityContextHolder
.getContext();
248 context
.setAuthentication(authentication
);
250 Taxon taxon
= (Taxon
)taxonService
.load(UUID
.fromString("928a0167-98cd-4555-bf72-52116d067625"));
251 TaxonDescription description
= TaxonDescription
.NewInstance(taxon
);
252 description
.addElement(Distribution
.NewInstance());
253 CdmPermissionEvaluator permissionEvaluator
= new CdmPermissionEvaluator();
254 assertTrue(permissionEvaluator
.hasPermission(authentication
, description
, "UPDATE"));
256 descriptionService
.saveOrUpdate(description
);
258 taxon
= (Taxon
)taxonService
.load(UUID
.fromString("928a0167-98cd-4555-bf72-52116d067625"));
259 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
260 assertTrue(descriptions
.contains(description
));
265 public void testSaveSynonym(){
266 authentication
= authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("taxonomist", "test4"));
267 SecurityContext context
= SecurityContextHolder
.getContext();
268 context
.setAuthentication(authentication
);
270 Synonym syn
= Synonym
.NewInstance(BotanicalName
.NewInstance(Rank
.SPECIES()), null);
271 taxonService
.saveOrUpdate(syn
);
275 @Ignore //FIXME test must not fail !!!!!
276 public void testEditPartOfClassification(){
278 * the user 'partEditor' has the following authorities:
280 * - TAXONNODE.CREATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}
281 * - TAXONNODE.UPDATE{20c8f083-5870-4cbd-bf56-c5b2b98ab6a7}
283 * that is 'partEditor' is granted to edit the subtree of
284 * which ACHERONTIA_NODE_UUID [20c8f083-5870-4cbd-bf56-c5b2b98ab6a7] is the root node.
286 authentication
= authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("partEditor", "test4"));
287 SecurityContext context
= SecurityContextHolder
.getContext();
288 context
.setAuthentication(authentication
);
291 TaxonNode acherontia_node
= taxonNodeService
.load(ACHERONTIA_NODE_UUID
);
292 long numOfChildNodes
= acherontia_node
.getChildNodes().size();
293 TaxonNode childNode
= acherontia_node
.addChildTaxon(Taxon
.NewInstance(BotanicalName
.NewInstance(Rank
.SPECIES()), null), null, null, null);
294 EvaluationFailedException evaluationFailedException
= null;
296 taxonNodeService
.saveOrUpdate(acherontia_node
);
297 commitAndStartNewTransaction(null);
298 } catch (RuntimeException e
){
299 evaluationFailedException
= findEvaluationFailedExceptionIn(e
);
301 Assert
.assertNull("evaluation must not fail since the user is permitted, CAUSE :" + evaluationFailedException
.getMessage(), evaluationFailedException
);
302 Assert
.assertEquals("the acherontia_node must now have one more child node ", numOfChildNodes
+ 1 , acherontia_node
.getChildNodes().size());
305 evaluationFailedException
= null;
306 TaxonNode acherontiini_node
= taxonNodeService
.load(ACHERONTIINI_NODE_UUID
);
307 numOfChildNodes
= acherontiini_node
.getCountChildren();
308 acherontiini_node
.addChildTaxon(Taxon
.NewInstance(BotanicalName
.NewInstance(Rank
.GENUS()), null), null, null, null);
310 taxonNodeService
.saveOrUpdate(acherontiini_node
);
311 commitAndStartNewTransaction(null);
312 } catch (RuntimeException e
){
313 evaluationFailedException
= findEvaluationFailedExceptionIn(e
);
315 Assert
.assertNotNull("evaluation must fail since the user is not permitted", evaluationFailedException
);
316 Assert
.assertEquals("the number of child nodes must be unchanged ", numOfChildNodes
, acherontiini_node
.getChildNodes().size());
320 public static void main(String
[] args
){
321 Md5PasswordEncoder encoder
=new Md5PasswordEncoder();
323 ReflectionSaltSource saltSource
= new ReflectionSaltSource();
324 saltSource
.setUserPropertyToUse("getUsername");
325 User user
= User
.NewInstance("taxonomist", "test4");
326 System
.err
.println(encoder
.encodePassword("test4", saltSource
.getSalt(user
)));