+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.wamblee.usermgt;
+
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.wamblee.persistence.hibernate.HibernateMappingFiles;
+import org.wamblee.security.encryption.Md5HexMessageDigester;
+import org.wamblee.test.SpringConfigFiles;
+import org.wamblee.test.SpringTestCase;
+import org.wamblee.usermgt.UserMgtException.Reason;
+
+/**
+ * Test of user administration implementation.
+ */
+public class UserAdministrationImplTest extends SpringTestCase {
+
+ private static final Logger LOGGER = Logger
+ .getLogger(UserAdministrationImplTest.class);
+
+ private static final String USER1 = "piet";
+
+ private static final String PASS1 = "passpiet";
+
+ private static final String USER2 = "kees";
+
+ private static final String PASS2 = "passkees";
+
+ private static final String GROUP1 = "cyclists";
+
+ private static final String GROUP2 = "runners";
+
+ private UserAdministration _admin;
+
+ public UserAdministrationImplTest() {
+ super(SpringConfigFiles.class, HibernateMappingFiles.class);
+ }
+
+ public UserAdministrationImplTest(
+ Class<? extends SpringConfigFiles> aSprings,
+ Class<? extends HibernateMappingFiles> aMappings) {
+ super(aSprings, aMappings);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ _admin = createAdmin();
+ }
+
+ protected UserAdministration createAdmin() {
+ UserSet users = new InMemoryUserSet( new RegexpNameValidator(RegexpNameValidator.PASSWORD_PATTERN, Reason.INVALID_PASSWORD, "Password must contain at least 6 characters"),
+ new Md5HexMessageDigester());
+ GroupSet groups = new InMemoryGroupSet();
+ return new UserAdministrationImpl(users, groups,
+ new RegexpNameValidator(RegexpNameValidator.ID_PATTERN,
+ Reason.INVALID_USERNAME, "Invalid user"),
+ new RegexpNameValidator(RegexpNameValidator.ID_PATTERN,
+ Reason.INVALID_GROUPNAME, "Invalid group"));
+ }
+
+ protected User createUser(String aName, String aPassword, Group aGroup) throws UserMgtException {
+ return UsermgtTestUtils.createUser(aName, aPassword, aGroup);
+ }
+
+ /**
+ * Constructs the admin, verify it contains no users and no groups.
+ */
+ public void testConstruct() {
+ assertEquals(0, _admin.getUsers().size());
+ assertEquals(0, _admin.getGroups().size());
+ assertEquals(0, _admin.getUserCount());
+ assertEquals(0, _admin.getGroupCount());
+ }
+
+ /**
+ * Creates a new group. Verifies the group is created correctly and that the
+ * user is added.
+ *
+ */
+ public void testCreateGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ assertNotNull(group);
+ assertEquals(GROUP1, group.getName());
+
+ Set<Group> groups = _admin.getGroups();
+ assertEquals(1, groups.size());
+ assertEquals(1, _admin.getGroupCount());
+ assertTrue(groups.contains(group));
+ }
+
+ private void createInvalidGroup(String aUsername) {
+ try {
+ _admin.createGroup(aUsername);
+ fail();
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.INVALID_GROUPNAME, e
+ .getReason());
+ assertEquals(0, _admin.getGroupCount());
+ }
+ }
+
+ /**
+ * Creates a new group with an invalid name. Verifies that the appropriate
+ * exception is thrown.
+ *
+ * @throws UserMgtException
+ */
+ public void testCreateInvalidGroupName() throws UserMgtException {
+ createInvalidGroup("");
+ createInvalidGroup("0abc"); // should not start with digits
+ createInvalidGroup("a b"); // should not contain spaces
+ createInvalidGroup(" aa");
+ createInvalidGroup("aa ");
+ }
+
+ /**
+ * Creates a new group which conflicts with an existing one. Verifies that
+ * the UserMgtException is thrown and that no group is added.
+ *
+ */
+ public void testCreateDuplicateGroup() throws UserMgtException {
+ _admin.createGroup(GROUP1);
+ try {
+ _admin.createGroup(GROUP1);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.DUPLICATE_GROUP, e.getReason());
+ assertEquals(1, _admin.getGroupCount());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Creates a new user. Verifies the user is created correctly and that the
+ * user is added.
+ *
+ */
+ public void testCreateUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ assertNotNull(user);
+ assertEquals(USER1, user.getName());
+ user.checkPassword(PASS1);
+
+ Set<User> users = _admin.getUsers();
+ assertEquals(1, users.size());
+ assertEquals(1, _admin.getUserCount());
+ assertTrue(users.contains(user));
+ }
+
+ private void createInvalidUser(String aUsername, Group aGroup) {
+ try {
+ _admin.createUser(aUsername, "pass", aGroup);
+ fail();
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.INVALID_USERNAME, e
+ .getReason());
+ assertEquals(0, _admin.getUserCount());
+ }
+ }
+
+ /**
+ * Constructs users with invalid names. Verifies that the appropriate
+ * exception is thrown.
+ *
+ */
+ public void testCreateInvalidUserName() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ createInvalidUser("", group);
+ createInvalidUser("0abc", group); // should not start with digits
+ createInvalidUser("a b", group); // should not contain spaces
+ createInvalidUser(" aa", group);
+ createInvalidUser("aa ", group);
+ }
+
+ /**
+ * Creates a new user which conflicts with an existing one. Verifies that
+ * the UserMgtException is thrown and that no user is added.
+ *
+ */
+ public void testCreateDuplicateUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ _admin.createUser(USER1, PASS1, group);
+ try {
+ _admin.createUser(USER1, PASS2, group);
+ fail();
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.DUPLICATE_USER, e.getReason());
+ assertEquals(1, _admin.getUserCount());
+ }
+ }
+
+ /**
+ * Gets a known user by name. Verifies the correct user is obtained.
+ * Verifies that null is returned when trying to obtain an unknown user.
+ *
+ */
+ public void testGetUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ User user2 = _admin.getUser(USER1);
+ assertTrue(user.equals(user2));
+ assertNull(_admin.getUser(USER2));
+ }
+
+ /**
+ * Gets a known group by name. Verifies the correct group is obtained.
+ * Verifies that null is returned when the group is not known.
+ *
+ */
+ public void testGetGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ Group group2 = _admin.getGroup(GROUP1);
+ assertTrue(group.equals(group2));
+ assertNull(_admin.getGroup(GROUP2));
+ }
+
+ /**
+ * Adds a user to a group. Verifies that the user is added using several API
+ * calls. Verifies that an exception occurs if the user is not already part
+ * of the group.
+ *
+ */
+ public void testAddUserToGroup() throws UserMgtException {
+
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ Group group2 = _admin.createGroup(GROUP2);
+ assertTrue(user.isInGroup(group));
+ assertFalse(user.isInGroup(group2));
+ _admin.addUserToGroup(user, group2);
+ assertTrue(user.isInGroup(group));
+ assertTrue(user.isInGroup(group2));
+ Set<User> users = _admin.getUsers(group2);
+ assertNotNull(users);
+ assertEquals(1, users.size());
+ assertTrue(users.contains(user));
+
+ try {
+ _admin.addUserToGroup(user, group);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.USER_ALREADY_IN_GROUP, e
+ .getReason());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Adds a user to a group where the user does not exist. Verifies that an
+ * exception occurs.
+ *
+ */
+ public void testAddUserToGroupUnknownUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = createUser(USER1, PASS1, group);
+ try {
+ _admin.addUserToGroup(user, group);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_USER, e.getReason());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Adds a user to a group where the user does not exist. Verifies that an
+ * exception occurs.
+ *
+ */
+ public void testAddUserToGroupUnknownGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ Group group2 = new Group(GROUP2);
+ try {
+ _admin.addUserToGroup(user, group2);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_GROUP, e.getReason());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Removes a user from a group. Verifies that the user is removed from the
+ * group using several API calls. Verifies that an exception occurs if the
+ * user not part of the group or if the user is only part of one group.
+ */
+ public void testRemoveUserFromGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+
+ User user = _admin.createUser(USER1, PASS1, group);
+ Group group2 = _admin.createGroup(GROUP2);
+ _admin.addUserToGroup(user, group2);
+ Set<Group> groups = user.getGroups();
+ assertEquals(2, groups.size());
+ assertTrue(groups.contains(group));
+ assertTrue(groups.contains(group2));
+
+ _admin.removeUserFromGroup(user, group);
+ groups = user.getGroups();
+ assertEquals(1, groups.size());
+ assertTrue(groups.contains(group2));
+ assertFalse(groups.contains(group));
+ }
+
+ /**
+ * Removes a user from a group where the user is not known. Verifies that an
+ * exception is thrown.
+ *
+ */
+ public void testRemoveUserFromGroupUnknownUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = createUser(USER1, GROUP1, group);
+ try {
+ _admin.removeUserFromGroup(user, group);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_USER, e.getReason());
+ }
+ }
+
+ /**
+ * Removes a user from a group where the group is not known. Verifies that
+ * an exception is thrown.
+ *
+ */
+ public void testRemoveUserFromGroupUnknownGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ Group group2 = new Group(GROUP2);
+ try {
+ _admin.removeUserFromGroup(user, group2);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_GROUP, e.getReason());
+ }
+ }
+
+ /**
+ * Removes a user from a group where the user is only part of one group.
+ * Verifies that an exception is thrown.
+ */
+ public void testRemoveUserFromGroupOnlyGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ try {
+ _admin.removeUserFromGroup(user, group);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.USER_MUST_BE_IN_A_GROUP, e
+ .getReason());
+ }
+ }
+
+ /**
+ * Gets the list of users and groups. Verifies that the correct suers and
+ * groups are returned. Verifies also that the relations from user to group
+ * are correct.
+ *
+ */
+ public void testGetUsersAndGroups() throws UserMgtException {
+ Group group1 = _admin.createGroup(GROUP1);
+ Group group2 = _admin.createGroup(GROUP2);
+
+ User user1 = _admin.createUser(USER1, PASS1, group1);
+ _admin.addUserToGroup(user1, group2);
+ User user2 = _admin.createUser(USER2, PASS2, group2);
+
+ Set<User> users = _admin.getUsers();
+ assertEquals(2, users.size());
+ assertTrue(users.contains(user1));
+ assertTrue(users.contains(user2));
+
+ Set<Group> groups = _admin.getGroups();
+ assertEquals(2, groups.size());
+ assertTrue(groups.contains(group1));
+ assertTrue(groups.contains(group2));
+
+ assertTrue(user1.isInGroup(group1));
+ assertTrue(user1.isInGroup(group2));
+ assertFalse(user2.isInGroup(group1));
+ assertTrue(user2.isInGroup(group2));
+
+ Set<Group> groups1 = user1.getGroups();
+ assertEquals(2, groups1.size());
+
+ Set<Group> groups2 = user2.getGroups();
+ assertEquals(1, groups2.size());
+ }
+
+ /**
+ * Renames a user. Verifies that the user is renamed. Verifies that
+ * exceptions are thrown when an attempt is made to rename the user to
+ * itself or to another existing user, or when the group does not exist.
+ *
+ */
+ public void testRenameUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user1 = _admin.createUser(USER1, PASS1, group);
+ _admin.renameUser(user1, USER2);
+ assertEquals(USER2, user1.getName());
+ assertEquals(user1, _admin.getUser(USER2));
+
+ _admin.createUser(USER1, PASS1, group);
+
+ try {
+ _admin.renameUser(user1, USER1);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.DUPLICATE_USER, e.getReason());
+
+ // do a trivial reanem
+ try {
+ _admin.renameUser(user1, user1.getName());
+ } catch (UserMgtException e2) {
+ assertEquals(UserMgtException.Reason.TRIVIAL_RENAME, e2
+ .getReason());
+ return;
+ }
+ fail();
+ }
+ fail();
+ }
+
+ /**
+ * Renames a user to a user with an invalid username. Verifies that the
+ * appropriate exception is thrown.
+ *
+ */
+ public void testRenameUserInvalidUsername() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user1 = _admin.createUser(USER1, PASS1, group);
+ try {
+ _admin.renameUser(user1, USER2);
+ } catch (UserMgtException e) {
+ assertEquals(e.getReason(), Reason.INVALID_USERNAME);
+ }
+ }
+
+ /**
+ * Renames a group. Verifies that the group is renamed. Verifies that
+ * exceptions are thrown when an attempt is made to rename the group to
+ * itself or to another existing group or when the group does not exist.
+ *
+ */
+ public void testRenameGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ _admin.renameGroup(group, GROUP2);
+ assertEquals(GROUP2, group.getName());
+ assertEquals(group, _admin.getGroup(GROUP2));
+
+ _admin.createGroup(GROUP1);
+ try {
+ _admin.renameGroup(group, GROUP1);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.DUPLICATE_GROUP, e.getReason());
+
+ // do a trivial reanem
+ try {
+ _admin.renameGroup(group, group.getName());
+ } catch (UserMgtException e2) {
+ assertEquals(UserMgtException.Reason.TRIVIAL_RENAME, e2
+ .getReason());
+ return;
+ }
+ fail();
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Renames a group to a group with an invalid name. Verifies that the
+ * appropriate exception is thrown.
+ *
+ */
+ public void testRenameGroupInvalidGroupname() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ try {
+ _admin.renameGroup(group, "a b");
+ } catch (UserMgtException e) {
+ assertEquals(e.getReason(), Reason.INVALID_GROUPNAME);
+ }
+ }
+
+ /**
+ * Removes a user. Verifies that the user is removed. Verifies that the an
+ * exception is thrown when the user does not exist.
+ *
+ */
+ public void testRemoveUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+
+ assertEquals(1, _admin.getUserCount());
+ _admin.removeUser(user);
+ assertEquals(0, _admin.getUserCount());
+
+ _admin.createUser(USER1, PASS1, group);
+ assertEquals(1, _admin.getUserCount());
+
+ User user2 = createUser(USER2, PASS2, group);
+
+ try {
+ _admin.removeUser(user2);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_USER, e.getReason());
+ }
+ }
+
+ /**
+ * Removes a group. Verifies that the group is removed. Verifies that the an
+ * exception is thrown when the group does not exist or if there are still
+ * users in the group.
+ *
+ */
+ public void testRemoveGroup() throws UserMgtException {
+ Group group1 = _admin.createGroup(GROUP1);
+ assertEquals(1, _admin.getGroupCount());
+ _admin.removeGroup(group1);
+ assertEquals(0, _admin.getGroupCount());
+ group1 = _admin.createGroup(GROUP1);
+
+ _admin.createUser(USER1, PASS1, group1);
+ try {
+ _admin.removeGroup(group1);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.GROUP_STILL_OCCUPIED, e
+ .getReason());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Tries to remove an unknown group. Verifies that an exception is thrown.
+ *
+ */
+ public void testRemoveGroupUnknownGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ Group group2 = new Group(GROUP2);
+ try {
+ _admin.removeGroup(group2);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_GROUP, e.getReason());
+ }
+ }
+
+ /**
+ * Changes the password, verifies that this succeeds.
+ *
+ * @throws UserMgtException
+ */
+ public void testChangePassword() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ user.changePassword(PASS1, PASS2);
+
+ // retrieve the user and verifies the password hasn't changed.
+ User user2 = _admin.getUser(USER1);
+ try {
+ user2.checkPassword(PASS2);
+ fail(); // password should not have changed already.
+ } catch (UserMgtException e) {
+ // ok.
+ }
+
+ // now notify the admin of the change in the user
+ _admin.userModified(user);
+
+ user2 = _admin.getUser(USER1);
+ user2.checkPassword(PASS2); // this time it should succeed.
+
+ }
+
+ /**
+ * Performance test. Finds a user by name.
+ *
+ */
+ public void testPerformanceFindUserByName() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ _admin.createUser(USER1, PASS1, group);
+
+ int n = 1000;
+ long time = System.currentTimeMillis();
+ for (int i = 0; i < n; i++) {
+ _admin.getUser(USER1);
+ }
+ LOGGER.info("Looked up a user " + n + " times in "
+ + (float) (System.currentTimeMillis() - time) / 1000.0);
+ }
+
+}