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