/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.security.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.logging.Logger;
import org.junit.Assert;
import org.apache.commons.io.FileUtils;
import org.geoserver.security.GeoServerUserGroupService;
import org.geoserver.security.GeoServerUserGroupStore;
import org.geoserver.security.event.UserGroupLoadedEvent;
import org.geoserver.security.event.UserGroupLoadedListener;
import org.geoserver.security.impl.AbstractUserGroupServiceTest;
import org.geoserver.security.impl.GeoServerUser;
import org.geoserver.security.impl.GeoServerUserGroup;
import org.geoserver.security.impl.Util;
import org.geoserver.security.password.GeoServerMultiplexingPasswordEncoder;
import org.geoserver.security.password.PasswordValidator;
import org.geoserver.test.SystemTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@Category(SystemTest.class)
public class XMLUserGroupServiceTest extends AbstractUserGroupServiceTest {
static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.security.xml");
@Override
public GeoServerUserGroupService createUserGroupService(String serviceName) throws Exception {
return createUserGroupService(serviceName,XMLConstants.FILE_UR);
}
@Before
public void clearUserGroupService() throws Exception {
store.clear();
store.store();
}
@Override
protected XMLUserGroupServiceConfig createConfigObject( String name ) {
XMLUserGroupServiceConfig config = new XMLUserGroupServiceConfig();
config.setName(name);
config.setPasswordEncoderName(getPBEPasswordEncoder().getName());
config.setPasswordPolicyName(PasswordValidator.DEFAULT_NAME);
config.setClassName(XMLUserGroupService.class.getName());
config.setCheckInterval(1000);
config.setFileName("users.xml");
config.setValidating(true);
config.setPasswordEncoderName(getPlainTextPasswordEncoder().getName());
config.setPasswordPolicyName(PasswordValidator.DEFAULT_NAME);
return config;
}
protected GeoServerUserGroupService createUserGroupService(String serviceName,String xmlFileName) throws Exception {
XMLUserGroupServiceConfig ugConfig =
(XMLUserGroupServiceConfig) getSecurityManager().loadUserGroupServiceConfig(serviceName);
if (ugConfig == null) {
ugConfig = createConfigObject(serviceName);
ugConfig.setName(serviceName);
}
ugConfig.setClassName(XMLUserGroupService.class.getName());
ugConfig.setCheckInterval(1000);
ugConfig.setFileName(xmlFileName);
ugConfig.setValidating(true);
ugConfig.setPasswordEncoderName(getDigestPasswordEncoder().getName());
ugConfig.setPasswordPolicyName(PasswordValidator.DEFAULT_NAME);
getSecurityManager().saveUserGroupService(ugConfig/*,isNewUGService(serviceName)*/);
GeoServerUserGroupService service = getSecurityManager().loadUserGroupService(serviceName);
service.initializeFromConfig(ugConfig); // create files
return service;
}
@Test
public void testCopyFrom() throws Exception {
GeoServerUserGroupService service1 = createUserGroupService("copyFrom");
GeoServerUserGroupService service2 = createUserGroupService("copyTo");
GeoServerUserGroupStore store1 = createStore(service1);
GeoServerUserGroupStore store2 = createStore(service2);
store1.clear();
checkEmpty(store1);
insertValues(store1);
Util.copyFrom(store1, store2);
store1.clear();
checkEmpty(store1);
checkValuesInserted(store2);
}
@Test
public void testDefault() throws Exception {
GeoServerUserGroupService service = getSecurityManager().loadUserGroupService(
XMLUserGroupService.DEFAULT_NAME);
assertEquals(1, service.getUsers().size());
assertEquals(1, service.getUserCount());
assertEquals(0, service.getUserGroups().size());
assertEquals(0, service.getGroupCount());
GeoServerUser admin = service.getUserByUsername(GeoServerUser.ADMIN_USERNAME);
assertNotNull(admin);
assertEquals(GeoServerUser.AdminEnabled, admin.isEnabled());
GeoServerMultiplexingPasswordEncoder enc = getEncoder(service);
assertTrue(enc.isPasswordValid(admin.getPassword(), GeoServerUser.DEFAULT_ADMIN_PASSWD,
null));
assertEquals(admin.getProperties().size(), 0);
assertEquals(0, service.getGroupsForUser(admin).size());
}
@Test
public void testLocking() throws Exception {
File xmlFile = File.createTempFile("users", ".xml");
try {
FileUtils.copyURLToFile(getClass().getResource("usersTemplate.xml"), xmlFile);
GeoServerUserGroupService service1 = createUserGroupService("locking1",
xmlFile.getCanonicalPath());
GeoServerUserGroupService service2 = createUserGroupService("locking2",
xmlFile.getCanonicalPath());
GeoServerUserGroupStore store1 = createStore(service1);
GeoServerUserGroupStore store2 = createStore(service2);
GeoServerUser user = store1.createUserObject("user", "ps", true);
GeoServerUserGroup group = store2.createGroupObject("group", true);
// obtain a lock
store1.addUser(user);
boolean fail;
String failMessage = "Concurrent lock not allowed";
fail = true;
try {
store2.clear();
} catch (IOException ex) {
fail = false;
}
if (fail)
Assert.fail(failMessage);
// release lock
store1.load();
// get lock
store2.addUser(user);
fail = true;
try {
store1.clear();
} catch (IOException ex) {
fail=false;
}
if (fail)
Assert.fail(failMessage);
// release lock
store2.store();
store1.clear();
store1.store();
// // end of part one, now check all modifying methods
// obtain a lock
store1.addUser(user);
fail = true;
try {
store2.associateUserToGroup(user, group);
} catch (IOException ex) {
try {
store2.disAssociateUserFromGroup(user, group);
} catch (IOException e) {
fail=false;
}
}
if (fail)
Assert.fail(failMessage);
fail = true;
try {
store2.updateUser(user);
} catch (IOException ex) {
try {
store2.removeUser(user);
} catch (IOException ex1) {
try {
store2.addUser(user);
} catch (IOException ex2) {
fail = false;
}
}
}
if (fail)
Assert.fail(failMessage);
fail = true;
try {
store2.updateGroup(group);
} catch (IOException ex) {
try {
store2.removeGroup(group);
} catch (IOException ex1) {
try {
store2.addGroup(group);
} catch (IOException ex2) {
fail = false;
}
}
}
if (fail)
Assert.fail(failMessage);
fail = true;
try {
store2.clear();
} catch (IOException ex) {
try {
store2.store();
} catch (IOException e) {
fail = false;
}
}
if (fail)
Assert.fail(failMessage);
} finally {
xmlFile.delete();
}
}
@Test
public void testDynamicReload() throws Exception {
File xmlFile = File.createTempFile("users", ".xml");
try {
FileUtils.copyURLToFile(getClass().getResource("usersTemplate.xml"), xmlFile);
GeoServerUserGroupService service1 = createUserGroupService("reload1",
xmlFile.getCanonicalPath());
GeoServerUserGroupService service2 = createUserGroupService("reload2",
xmlFile.getCanonicalPath());
GeoServerUserGroupStore store1 = createStore(service1);
GeoServerUserGroup group = store1.createGroupObject("group", true);
checkEmpty(service1);
checkEmpty(service2);
// prepare for syncing
UserGroupLoadedListener listener = new UserGroupLoadedListener() {
@Override
public void usersAndGroupsChanged(UserGroupLoadedEvent event) {
synchronized (this) {
this.notifyAll();
}
}
};
service2.registerUserGroupLoadedListener(listener);
// modifiy store1
store1.addGroup(group);
store1.store();
assertTrue(service1.getUserGroups().size() == 1);
assertTrue(service1.getGroupCount() == 1);
// increment lastmodified adding a second manually, the test is too fast
xmlFile.setLastModified(xmlFile.lastModified() + 2000);
// wait for the listener to unlock when
// service 2 triggers a load event
synchronized (listener) {
listener.wait();
}
// here comes the magic !!!
assertTrue(service2.getUserGroups().size() == 1);
assertTrue(service2.getGroupCount() == 1);
} finally {
xmlFile.delete();
}
}
}