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