Moved over some of the security stuff from Photos.
[utils] / security / src / test / java / org / wamblee / usermgt / UserAdministrationImplTest.java
1 /*
2  * Copyright 2005 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.wamblee.usermgt;
18
19 import java.util.Set;
20
21 import org.apache.log4j.Logger;
22 import org.wamblee.persistence.hibernate.HibernateMappingFiles;
23 import org.wamblee.security.encryption.Md5HexMessageDigester;
24 import org.wamblee.test.SpringConfigFiles;
25 import org.wamblee.test.SpringTestCase;
26 import org.wamblee.usermgt.UserMgtException.Reason;
27
28 /**
29  * Test of user administration implementation.
30  */
31 public class UserAdministrationImplTest extends SpringTestCase {
32
33     private static final Logger LOGGER = Logger
34             .getLogger(UserAdministrationImplTest.class);
35
36     private static final String USER1 = "piet";
37
38     private static final String PASS1 = "passpiet";
39
40     private static final String USER2 = "kees";
41
42     private static final String PASS2 = "passkees";
43
44     private static final String GROUP1 = "cyclists";
45
46     private static final String GROUP2 = "runners";
47
48     private UserAdministration _admin;
49
50     public UserAdministrationImplTest() {
51         super(SpringConfigFiles.class, HibernateMappingFiles.class);
52     }
53
54     public UserAdministrationImplTest(
55             Class<? extends SpringConfigFiles> aSprings,
56             Class<? extends HibernateMappingFiles> aMappings) {
57         super(aSprings, aMappings);
58     }
59
60     /*
61      * (non-Javadoc)
62      * 
63      * @see junit.framework.TestCase#setUp()
64      */
65     @Override
66     protected void setUp() throws Exception {
67         super.setUp();
68         _admin = createAdmin();
69     }
70
71     protected UserAdministration createAdmin() {
72         UserSet users = new InMemoryUserSet(   new RegexpNameValidator(RegexpNameValidator.PASSWORD_PATTERN, Reason.INVALID_PASSWORD, "Password must contain at least 6 characters"),
73                 new Md5HexMessageDigester());
74         GroupSet groups = new InMemoryGroupSet();
75         return new UserAdministrationImpl(users, groups,
76                 new RegexpNameValidator(RegexpNameValidator.ID_PATTERN,
77                         Reason.INVALID_USERNAME, "Invalid user"),
78                 new RegexpNameValidator(RegexpNameValidator.ID_PATTERN,
79                         Reason.INVALID_GROUPNAME, "Invalid group"));
80     }
81     
82     protected User createUser(String aName, String aPassword, Group aGroup) throws UserMgtException { 
83         return UsermgtTestUtils.createUser(aName, aPassword, aGroup);
84     }
85
86     /**
87      * Constructs the admin, verify it contains no users and no groups.
88      */
89     public void testConstruct() {
90         assertEquals(0, _admin.getUsers().size());
91         assertEquals(0, _admin.getGroups().size());
92         assertEquals(0, _admin.getUserCount());
93         assertEquals(0, _admin.getGroupCount());
94     }
95
96     /**
97      * Creates a new group. Verifies the group is created correctly and that the
98      * user is added.
99      * 
100      */
101     public void testCreateGroup() throws UserMgtException {
102         Group group = _admin.createGroup(GROUP1);
103         assertNotNull(group);
104         assertEquals(GROUP1, group.getName());
105
106         Set<Group> groups = _admin.getGroups();
107         assertEquals(1, groups.size());
108         assertEquals(1, _admin.getGroupCount());
109         assertTrue(groups.contains(group));
110     }
111
112     private void createInvalidGroup(String aUsername) {
113         try {
114             _admin.createGroup(aUsername);
115             fail();
116         } catch (UserMgtException e) {
117             assertEquals(UserMgtException.Reason.INVALID_GROUPNAME, e
118                     .getReason());
119             assertEquals(0, _admin.getGroupCount());
120         }
121     }
122
123     /**
124      * Creates a new group with an invalid name. Verifies that the appropriate
125      * exception is thrown.
126      * 
127      * @throws UserMgtException
128      */
129     public void testCreateInvalidGroupName() throws UserMgtException {
130         createInvalidGroup("");
131         createInvalidGroup("0abc"); // should not start with digits
132         createInvalidGroup("a b"); // should not contain spaces
133         createInvalidGroup(" aa");
134         createInvalidGroup("aa ");
135     }
136
137     /**
138      * Creates a new group which conflicts with an existing one. Verifies that
139      * the UserMgtException is thrown and that no group is added.
140      * 
141      */
142     public void testCreateDuplicateGroup() throws UserMgtException {
143         _admin.createGroup(GROUP1);
144         try {
145             _admin.createGroup(GROUP1);
146         } catch (UserMgtException e) {
147             assertEquals(UserMgtException.Reason.DUPLICATE_GROUP, e.getReason());
148             assertEquals(1, _admin.getGroupCount());
149             return;
150         }
151         fail();
152     }
153
154     /**
155      * Creates a new user. Verifies the user is created correctly and that the
156      * user is added.
157      * 
158      */
159     public void testCreateUser() throws UserMgtException {
160         Group group = _admin.createGroup(GROUP1);
161         User user = _admin.createUser(USER1, PASS1, group);
162         assertNotNull(user);
163         assertEquals(USER1, user.getName());
164         user.checkPassword(PASS1);
165
166         Set<User> users = _admin.getUsers();
167         assertEquals(1, users.size());
168         assertEquals(1, _admin.getUserCount());
169         assertTrue(users.contains(user));
170     }
171
172     private void createInvalidUser(String aUsername, Group aGroup) {
173         try {
174             _admin.createUser(aUsername, "pass", aGroup);
175             fail();
176         } catch (UserMgtException e) {
177             assertEquals(UserMgtException.Reason.INVALID_USERNAME, e
178                     .getReason());
179             assertEquals(0, _admin.getUserCount());
180         }
181     }
182
183     /**
184      * Constructs users with invalid names. Verifies that the appropriate
185      * exception is thrown.
186      * 
187      */
188     public void testCreateInvalidUserName() throws UserMgtException {
189         Group group = _admin.createGroup(GROUP1);
190         createInvalidUser("", group);
191         createInvalidUser("0abc", group); // should not start with digits
192         createInvalidUser("a b", group); // should not contain spaces
193         createInvalidUser(" aa", group);
194         createInvalidUser("aa ", group);
195     }
196
197     /**
198      * Creates a new user which conflicts with an existing one. Verifies that
199      * the UserMgtException is thrown and that no user is added.
200      * 
201      */
202     public void testCreateDuplicateUser() throws UserMgtException {
203         Group group = _admin.createGroup(GROUP1);
204         _admin.createUser(USER1, PASS1, group);
205         try {
206             _admin.createUser(USER1, PASS2, group);
207             fail();
208         } catch (UserMgtException e) {
209             assertEquals(UserMgtException.Reason.DUPLICATE_USER, e.getReason());
210             assertEquals(1, _admin.getUserCount());
211         }
212     }
213
214     /**
215      * Gets a known user by name. Verifies the correct user is obtained.
216      * Verifies that null is returned when trying to obtain an unknown user.
217      * 
218      */
219     public void testGetUser() throws UserMgtException {
220         Group group = _admin.createGroup(GROUP1);
221         User user = _admin.createUser(USER1, PASS1, group);
222         User user2 = _admin.getUser(USER1);
223         assertTrue(user.equals(user2));
224         assertNull(_admin.getUser(USER2));
225     }
226
227     /**
228      * Gets a known group by name. Verifies the correct group is obtained.
229      * Verifies that null is returned when the group is not known.
230      * 
231      */
232     public void testGetGroup() throws UserMgtException {
233         Group group = _admin.createGroup(GROUP1);
234         Group group2 = _admin.getGroup(GROUP1);
235         assertTrue(group.equals(group2));
236         assertNull(_admin.getGroup(GROUP2));
237     }
238
239     /**
240      * Adds a user to a group. Verifies that the user is added using several API
241      * calls. Verifies that an exception occurs if the user is not already part
242      * of the group.
243      * 
244      */
245     public void testAddUserToGroup() throws UserMgtException {
246
247         Group group = _admin.createGroup(GROUP1);
248         User user = _admin.createUser(USER1, PASS1, group);
249         Group group2 = _admin.createGroup(GROUP2);
250         assertTrue(user.isInGroup(group));
251         assertFalse(user.isInGroup(group2));
252         _admin.addUserToGroup(user, group2);
253         assertTrue(user.isInGroup(group));
254         assertTrue(user.isInGroup(group2));
255         Set<User> users = _admin.getUsers(group2);
256         assertNotNull(users);
257         assertEquals(1, users.size());
258         assertTrue(users.contains(user));
259
260         try {
261             _admin.addUserToGroup(user, group);
262         } catch (UserMgtException e) {
263             assertEquals(UserMgtException.Reason.USER_ALREADY_IN_GROUP, e
264                     .getReason());
265             return;
266         }
267         fail();
268     }
269
270     /**
271      * Adds a user to a group where the user does not exist. Verifies that an
272      * exception occurs.
273      * 
274      */
275     public void testAddUserToGroupUnknownUser() throws UserMgtException {
276         Group group = _admin.createGroup(GROUP1);
277         User user = createUser(USER1, PASS1, group);
278         try {
279             _admin.addUserToGroup(user, group);
280         } catch (UserMgtException e) {
281             assertEquals(UserMgtException.Reason.UNKNOWN_USER, e.getReason());
282             return;
283         }
284         fail();
285     }
286
287     /**
288      * Adds a user to a group where the user does not exist. Verifies that an
289      * exception occurs.
290      * 
291      */
292     public void testAddUserToGroupUnknownGroup() throws UserMgtException {
293         Group group = _admin.createGroup(GROUP1);
294         User user = _admin.createUser(USER1, PASS1, group);
295         Group group2 = new Group(GROUP2);
296         try {
297             _admin.addUserToGroup(user, group2);
298         } catch (UserMgtException e) {
299             assertEquals(UserMgtException.Reason.UNKNOWN_GROUP, e.getReason());
300             return;
301         }
302         fail();
303     }
304
305     /**
306      * Removes a user from a group. Verifies that the user is removed from the
307      * group using several API calls. Verifies that an exception occurs if the
308      * user not part of the group or if the user is only part of one group.
309      */
310     public void testRemoveUserFromGroup() throws UserMgtException {
311         Group group = _admin.createGroup(GROUP1);
312
313         User user = _admin.createUser(USER1, PASS1, group);
314         Group group2 = _admin.createGroup(GROUP2);
315         _admin.addUserToGroup(user, group2);
316         Set<Group> groups = user.getGroups();
317         assertEquals(2, groups.size());
318         assertTrue(groups.contains(group));
319         assertTrue(groups.contains(group2));
320
321         _admin.removeUserFromGroup(user, group);
322         groups = user.getGroups();
323         assertEquals(1, groups.size());
324         assertTrue(groups.contains(group2));
325         assertFalse(groups.contains(group));
326     }
327
328     /**
329      * Removes a user from a group where the user is not known. Verifies that an
330      * exception is thrown.
331      * 
332      */
333     public void testRemoveUserFromGroupUnknownUser() throws UserMgtException {
334         Group group = _admin.createGroup(GROUP1);
335         User user = createUser(USER1, GROUP1, group);
336         try {
337             _admin.removeUserFromGroup(user, group);
338         } catch (UserMgtException e) {
339             assertEquals(UserMgtException.Reason.UNKNOWN_USER, e.getReason());
340         }
341     }
342
343     /**
344      * Removes a user from a group where the group is not known. Verifies that
345      * an exception is thrown.
346      * 
347      */
348     public void testRemoveUserFromGroupUnknownGroup() throws UserMgtException {
349         Group group = _admin.createGroup(GROUP1);
350         User user = _admin.createUser(USER1, PASS1, group);
351         Group group2 = new Group(GROUP2);
352         try {
353             _admin.removeUserFromGroup(user, group2);
354         } catch (UserMgtException e) {
355             assertEquals(UserMgtException.Reason.UNKNOWN_GROUP, e.getReason());
356         }
357     }
358
359     /**
360      * Removes a user from a group where the user is only part of one group.
361      * Verifies that an exception is thrown.
362      */
363     public void testRemoveUserFromGroupOnlyGroup() throws UserMgtException {
364         Group group = _admin.createGroup(GROUP1);
365         User user = _admin.createUser(USER1, PASS1, group);
366         try {
367             _admin.removeUserFromGroup(user, group);
368         } catch (UserMgtException e) {
369             assertEquals(UserMgtException.Reason.USER_MUST_BE_IN_A_GROUP, e
370                     .getReason());
371         }
372     }
373
374     /**
375      * Gets the list of users and groups. Verifies that the correct suers and
376      * groups are returned. Verifies also that the relations from user to group
377      * are correct.
378      * 
379      */
380     public void testGetUsersAndGroups() throws UserMgtException {
381         Group group1 = _admin.createGroup(GROUP1);
382         Group group2 = _admin.createGroup(GROUP2);
383
384         User user1 = _admin.createUser(USER1, PASS1, group1);
385         _admin.addUserToGroup(user1, group2);
386         User user2 = _admin.createUser(USER2, PASS2, group2);
387
388         Set<User> users = _admin.getUsers();
389         assertEquals(2, users.size());
390         assertTrue(users.contains(user1));
391         assertTrue(users.contains(user2));
392
393         Set<Group> groups = _admin.getGroups();
394         assertEquals(2, groups.size());
395         assertTrue(groups.contains(group1));
396         assertTrue(groups.contains(group2));
397
398         assertTrue(user1.isInGroup(group1));
399         assertTrue(user1.isInGroup(group2));
400         assertFalse(user2.isInGroup(group1));
401         assertTrue(user2.isInGroup(group2));
402
403         Set<Group> groups1 = user1.getGroups();
404         assertEquals(2, groups1.size());
405
406         Set<Group> groups2 = user2.getGroups();
407         assertEquals(1, groups2.size());
408     }
409
410     /**
411      * Renames a user. Verifies that the user is renamed. Verifies that
412      * exceptions are thrown when an attempt is made to rename the user to
413      * itself or to another existing user, or when the group does not exist.
414      * 
415      */
416     public void testRenameUser() throws UserMgtException {
417         Group group = _admin.createGroup(GROUP1);
418         User user1 = _admin.createUser(USER1, PASS1, group);
419         _admin.renameUser(user1, USER2);
420         assertEquals(USER2, user1.getName());
421         assertEquals(user1, _admin.getUser(USER2));
422
423         _admin.createUser(USER1, PASS1, group);
424
425         try {
426             _admin.renameUser(user1, USER1);
427         } catch (UserMgtException e) {
428             assertEquals(UserMgtException.Reason.DUPLICATE_USER, e.getReason());
429
430             // do a trivial reanem
431             try {
432                 _admin.renameUser(user1, user1.getName());
433             } catch (UserMgtException e2) {
434                 assertEquals(UserMgtException.Reason.TRIVIAL_RENAME, e2
435                         .getReason());
436                 return;
437             }
438             fail();
439         }
440         fail();
441     }
442
443     /**
444      * Renames a user to a user with an invalid username. Verifies that the
445      * appropriate exception is thrown.
446      * 
447      */
448     public void testRenameUserInvalidUsername() throws UserMgtException {
449         Group group = _admin.createGroup(GROUP1);
450         User user1 = _admin.createUser(USER1, PASS1, group);
451         try {
452             _admin.renameUser(user1, USER2);
453         } catch (UserMgtException e) {
454             assertEquals(e.getReason(), Reason.INVALID_USERNAME);
455         }
456     }
457
458     /**
459      * Renames a group. Verifies that the group is renamed. Verifies that
460      * exceptions are thrown when an attempt is made to rename the group to
461      * itself or to another existing group or when the group does not exist.
462      * 
463      */
464     public void testRenameGroup() throws UserMgtException {
465         Group group = _admin.createGroup(GROUP1);
466         _admin.renameGroup(group, GROUP2);
467         assertEquals(GROUP2, group.getName());
468         assertEquals(group, _admin.getGroup(GROUP2));
469
470         _admin.createGroup(GROUP1);
471         try {
472             _admin.renameGroup(group, GROUP1);
473         } catch (UserMgtException e) {
474             assertEquals(UserMgtException.Reason.DUPLICATE_GROUP, e.getReason());
475
476             // do a trivial reanem
477             try {
478                 _admin.renameGroup(group, group.getName());
479             } catch (UserMgtException e2) {
480                 assertEquals(UserMgtException.Reason.TRIVIAL_RENAME, e2
481                         .getReason());
482                 return;
483             }
484             fail();
485             return;
486         }
487         fail();
488     }
489
490     /**
491      * Renames a group to a group with an invalid name. Verifies that the
492      * appropriate exception is thrown.
493      * 
494      */
495     public void testRenameGroupInvalidGroupname() throws UserMgtException {
496         Group group = _admin.createGroup(GROUP1);
497         try {
498             _admin.renameGroup(group, "a b");
499         } catch (UserMgtException e) {
500             assertEquals(e.getReason(), Reason.INVALID_GROUPNAME);
501         }
502     }
503
504     /**
505      * Removes a user. Verifies that the user is removed. Verifies that the an
506      * exception is thrown when the user does not exist.
507      * 
508      */
509     public void testRemoveUser() throws UserMgtException {
510         Group group = _admin.createGroup(GROUP1);
511         User user = _admin.createUser(USER1, PASS1, group);
512
513         assertEquals(1, _admin.getUserCount());
514         _admin.removeUser(user);
515         assertEquals(0, _admin.getUserCount());
516
517         _admin.createUser(USER1, PASS1, group);
518         assertEquals(1, _admin.getUserCount());
519
520         User user2 = createUser(USER2, PASS2, group);
521
522         try {
523             _admin.removeUser(user2);
524         } catch (UserMgtException e) {
525             assertEquals(UserMgtException.Reason.UNKNOWN_USER, e.getReason());
526         }
527     }
528
529     /**
530      * Removes a group. Verifies that the group is removed. Verifies that the an
531      * exception is thrown when the group does not exist or if there are still
532      * users in the group.
533      * 
534      */
535     public void testRemoveGroup() throws UserMgtException {
536         Group group1 = _admin.createGroup(GROUP1);
537         assertEquals(1, _admin.getGroupCount());
538         _admin.removeGroup(group1);
539         assertEquals(0, _admin.getGroupCount());
540         group1 = _admin.createGroup(GROUP1);
541
542         _admin.createUser(USER1, PASS1, group1);
543         try {
544             _admin.removeGroup(group1);
545         } catch (UserMgtException e) {
546             assertEquals(UserMgtException.Reason.GROUP_STILL_OCCUPIED, e
547                     .getReason());
548             return;
549         }
550         fail();
551     }
552
553     /**
554      * Tries to remove an unknown group. Verifies that an exception is thrown.
555      * 
556      */
557     public void testRemoveGroupUnknownGroup() throws UserMgtException {
558         Group group = _admin.createGroup(GROUP1);
559         Group group2 = new Group(GROUP2);
560         try {
561             _admin.removeGroup(group2);
562         } catch (UserMgtException e) {
563             assertEquals(UserMgtException.Reason.UNKNOWN_GROUP, e.getReason());
564         }
565     }
566
567     /**
568      * Changes the password, verifies that this succeeds.
569      * 
570      * @throws UserMgtException
571      */
572     public void testChangePassword() throws UserMgtException {
573         Group group = _admin.createGroup(GROUP1);
574         User user = _admin.createUser(USER1, PASS1, group);
575         user.changePassword(PASS1, PASS2);
576
577         // retrieve the user and verifies the password hasn't changed.
578         User user2 = _admin.getUser(USER1);
579         try {
580             user2.checkPassword(PASS2);
581             fail(); // password should not have changed already.
582         } catch (UserMgtException e) {
583             // ok.
584         }
585
586         // now notify the admin of the change in the user
587         _admin.userModified(user);
588
589         user2 = _admin.getUser(USER1);
590         user2.checkPassword(PASS2); // this time it should succeed.
591
592     }
593
594     /**
595      * Performance test. Finds a user by name.
596      * 
597      */
598     public void testPerformanceFindUserByName() throws UserMgtException {
599         Group group = _admin.createGroup(GROUP1);
600         _admin.createUser(USER1, PASS1, group);
601
602         int n = 1000;
603         long time = System.currentTimeMillis();
604         for (int i = 0; i < n; i++) {
605             _admin.getUser(USER1);
606         }
607         LOGGER.info("Looked up a user " + n + " times in "
608                 + (float) (System.currentTimeMillis() - time) / 1000.0);
609     }
610
611 }