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