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