/* (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.impl;
import static org.junit.Assert.*;
import java.io.File;
import java.io.FileInputStream;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import org.junit.Assert;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.config.GeoServerPersister;
import org.geoserver.config.util.XStreamPersister;
import org.geoserver.config.util.XStreamPersisterFactory;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.security.GeoServerRoleService;
import org.geoserver.security.GeoServerSecurityManager;
import org.geoserver.security.GeoServerUserGroupService;
import org.geoserver.security.GeoServerUserGroupStore;
import org.geoserver.security.config.SecurityManagerConfig;
import org.geoserver.security.config.impl.MemoryRoleServiceConfigImpl;
import org.geoserver.security.config.impl.MemoryUserGroupServiceConfigImpl;
import org.geoserver.security.password.DecodingUserDetailsService;
import org.geoserver.security.password.GeoServerPasswordEncoder;
import org.geoserver.security.password.PasswordValidator;
import org.geoserver.test.SystemTest;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.springframework.security.core.userdetails.UserDetails;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@Category(SystemTest.class)
public class MemoryUserDetailsServiceTest extends AbstractUserDetailsServiceTest {
static final String plainTextRole = "plainrole";
static final String plainTextUserGroup = "plainuserGroup";
@Override
public GeoServerRoleService createRoleService(String name) throws Exception {
MemoryRoleServiceConfigImpl config = getRoleConfig(name);
GeoServerRoleService service = new MemoryRoleService();
service.setSecurityManager(GeoServerExtensions.bean(GeoServerSecurityManager.class));
service.initializeFromConfig(config);
getSecurityManager().saveRoleService(config/*,isNewRoleService(name)*/);
return service;
}
public MemoryRoleServiceConfigImpl getRoleConfig(String name) {
MemoryRoleServiceConfigImpl config = new MemoryRoleServiceConfigImpl();
config.setName(name);
config.setClassName(MemoryRoleService.class.getName());
config.setToBeEncrypted(plainTextRole);
return config;
}
@Override
public GeoServerUserGroupService createUserGroupService(String name) throws Exception {
return createUserGroupService(name, getPBEPasswordEncoder().getName());
}
public GeoServerUserGroupService createUserGroupService(String name,String passwordEncoderName) throws Exception {
MemoryUserGroupServiceConfigImpl config = getUserGroupConfg(name, passwordEncoderName);
GeoServerUserGroupService service = new MemoryUserGroupService();
service.setSecurityManager(GeoServerExtensions.bean(GeoServerSecurityManager.class));
service.initializeFromConfig(config);
getSecurityManager().saveUserGroupService(config/*,isNewUGService(name)*/);
return service;
}
public MemoryUserGroupServiceConfigImpl getUserGroupConfg(String name, String passwordEncoderName) {
MemoryUserGroupServiceConfigImpl config = new MemoryUserGroupServiceConfigImpl();
config.setName(name);
config.setClassName(MemoryUserGroupService.class.getName());
config.setPasswordEncoderName(passwordEncoderName);
config.setPasswordPolicyName(PasswordValidator.DEFAULT_NAME);
config.setToBeEncrypted(plainTextUserGroup);
return config;
}
@Test
public void testDecodingUserDetailsService() throws Exception {
GeoServerUserGroupService service = createUserGroupService("test");
DecodingUserDetailsService decService = DecodingUserDetailsService.newInstance(service);
GeoServerUserGroupStore store = createStore(service);
insertValues(store);
store.store();
String plainpassword = "geoserver";
UserDetails admin = service.loadUserByUsername(GeoServerUser.ADMIN_USERNAME);
assertFalse(plainpassword.equals(admin.getPassword()));
UserDetails admin2 = decService.loadUserByUsername(GeoServerUser.ADMIN_USERNAME);
assertTrue(plainpassword.equals(admin2.getPassword()));
}
@Test
public void testCopyFrom() throws Exception {
// from crypt tp crytp
GeoServerUserGroupService service1 = createUserGroupService("copyFrom");
GeoServerUserGroupService service2 = createUserGroupService("copyTo");
copyFrom(service1,service2);
// from plain to plain
service1 = createUserGroupService("copyFrom1",getPlainTextPasswordEncoder().getName());
service2 = createUserGroupService("copyTo1",getPlainTextPasswordEncoder().getName());
copyFrom(service1,service2);
// cypt to digest
service1 = createUserGroupService("copyFrom2");
service2 = createUserGroupService("copyTo2",getDigestPasswordEncoder().getName());
copyFrom(service1,service2);
// digest to digest
service1 = createUserGroupService("copyFrom3",getDigestPasswordEncoder().getName());
service2 = createUserGroupService("copyTo3",getDigestPasswordEncoder().getName());
copyFrom(service1,service2);
// digest to crypt
service1 = createUserGroupService("copyFrom4",getDigestPasswordEncoder().getName());
service2 = createUserGroupService("copyTo4");
copyFrom(service1,service2);
}
protected void copyFrom(GeoServerUserGroupService service1, GeoServerUserGroupService service2 ) throws Exception{
GeoServerUserGroupStore store1 = createStore(service1);
GeoServerUserGroupStore store2 = createStore(service2);
store1.clear();
checkEmpty(store1);
insertValues(store1);
Util.copyFrom(store1, store2);
store1.clear();
checkEmpty(store1);
checkValuesInserted(store2);
store2.clear();
checkEmpty(store2);
}
@Test
public void testEncryption() throws Exception {
SecurityManagerConfig config = getSecurityManager().getSecurityConfig();
GeoServerPasswordEncoder encoder = getPlainTextPasswordEncoder();
String plainprefix=encoder.getPrefix()+GeoServerPasswordEncoder.PREFIX_DELIMTER;
config.setConfigPasswordEncrypterName(encoder.getName());
getSecurityManager().saveSecurityConfig(config);
String serviceName = "testEncrypt";
String cryptprefix = getPBEPasswordEncoder().getPrefix()+GeoServerPasswordEncoder.PREFIX_DELIMTER;
MemoryRoleServiceConfigImpl roleConfig = getRoleConfig(serviceName);
MemoryUserGroupServiceConfigImpl ugConfig = getUserGroupConfg(serviceName,
getPlainTextPasswordEncoder().getName());
getSecurityManager().saveRoleService(roleConfig);
getSecurityManager().saveUserGroupService(ugConfig);
File roleDir= new File(getSecurityManager().get("security/role").dir(),serviceName);
File ugDir= new File(getSecurityManager().get("security/usergroup").dir(),serviceName);
File roleFile = new File(roleDir,GeoServerSecurityManager.CONFIG_FILENAME);
File ugFile = new File(ugDir,GeoServerSecurityManager.CONFIG_FILENAME);
assertTrue(roleFile.exists());
assertTrue(ugFile.exists());
Document ugDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(ugFile);
Document roleDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(roleFile);
Element roleElem =(Element) roleDoc.getDocumentElement().getElementsByTagName("toBeEncrypted").item(0);
Element ugElem =(Element) ugDoc.getDocumentElement().getElementsByTagName("toBeEncrypted").item(0);
// check file
assertEquals(plainprefix+plainTextRole,roleElem.getTextContent());
assertEquals(plainprefix+plainTextUserGroup,ugElem.getTextContent());
// reload and check
MemoryRoleService roleService = (MemoryRoleService) getSecurityManager().loadRoleService(serviceName);
assertEquals(plainTextRole, roleService.getToBeEncrypted());
MemoryUserGroupService ugService = (MemoryUserGroupService) getSecurityManager().loadUserGroupService(serviceName);
assertEquals(plainTextUserGroup, ugService.getToBeEncrypted());
// SWITCH TO ENCRYPTION
config = getSecurityManager().getSecurityConfig();
config.setConfigPasswordEncrypterName(getPBEPasswordEncoder().getName());
getSecurityManager().saveSecurityConfig(config);
getSecurityManager().updateConfigurationFilesWithEncryptedFields();
ugDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(ugFile);
roleDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(roleFile);
roleElem =(Element) roleDoc.getDocumentElement().getElementsByTagName("toBeEncrypted").item(0);
ugElem =(Element) ugDoc.getDocumentElement().getElementsByTagName("toBeEncrypted").item(0);
// check file
assertTrue(roleElem.getTextContent().startsWith(cryptprefix));
assertTrue(ugElem.getTextContent().startsWith(cryptprefix));
roleService = (MemoryRoleService) getSecurityManager().loadRoleService(serviceName);
assertEquals(plainTextRole, roleService.getToBeEncrypted());
ugService = (MemoryUserGroupService) getSecurityManager().loadUserGroupService(serviceName);
assertEquals(plainTextUserGroup, ugService.getToBeEncrypted());
}
@Test
public void testEncryption2() throws Exception {
SecurityManagerConfig config = getSecurityManager().getSecurityConfig();
config.setConfigPasswordEncrypterName(getPBEPasswordEncoder().getName());
getSecurityManager().saveSecurityConfig(config);
String serviceName = "testEncrypt2";
String prefix =getPBEPasswordEncoder().getPrefix()+GeoServerPasswordEncoder.PREFIX_DELIMTER;
MemoryRoleServiceConfigImpl roleConfig = getRoleConfig(serviceName);
MemoryUserGroupServiceConfigImpl ugConfig = getUserGroupConfg(serviceName,
getPlainTextPasswordEncoder().getName());
getSecurityManager().saveRoleService(roleConfig);
getSecurityManager().saveUserGroupService(ugConfig);
File roleDir= new File(getSecurityManager().get("security/role").dir(),serviceName);
File ugDir= new File(getSecurityManager().get("security/usergroup").dir(),serviceName);
File roleFile = new File(roleDir,GeoServerSecurityManager.CONFIG_FILENAME);
File ugFile = new File(ugDir,GeoServerSecurityManager.CONFIG_FILENAME);
assertTrue(roleFile.exists());
assertTrue(ugFile.exists());
Document ugDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(ugFile);
Document roleDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(roleFile);
Element roleElem =(Element) roleDoc.getDocumentElement().getElementsByTagName("toBeEncrypted").item(0);
Element ugElem =(Element) ugDoc.getDocumentElement().getElementsByTagName("toBeEncrypted").item(0);
// check file
assertTrue(roleElem.getTextContent().startsWith(prefix));
assertTrue(ugElem.getTextContent().startsWith(prefix));
// reload and check
MemoryRoleService roleService = (MemoryRoleService) getSecurityManager().loadRoleService(serviceName);
assertEquals(plainTextRole, roleService.getToBeEncrypted());
MemoryUserGroupService ugService = (MemoryUserGroupService) getSecurityManager().loadUserGroupService(serviceName);
assertEquals(plainTextUserGroup, ugService.getToBeEncrypted());
// SWITCH TO PLAINTEXT
config.setConfigPasswordEncrypterName(getPlainTextPasswordEncoder().getName());
String plainprefix=getPlainTextPasswordEncoder().getPrefix()+GeoServerPasswordEncoder.PREFIX_DELIMTER;
getSecurityManager().saveSecurityConfig(config);
getSecurityManager().updateConfigurationFilesWithEncryptedFields();
ugDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(ugFile);
roleDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(roleFile);
roleElem =(Element) roleDoc.getDocumentElement().getElementsByTagName("toBeEncrypted").item(0);
ugElem =(Element) ugDoc.getDocumentElement().getElementsByTagName("toBeEncrypted").item(0);
// check file
// check file
assertEquals(plainprefix+plainTextRole,roleElem.getTextContent());
assertEquals(plainprefix+plainTextUserGroup,ugElem.getTextContent());
roleService = (MemoryRoleService) getSecurityManager().loadRoleService(serviceName);
assertEquals(plainTextRole, roleService.getToBeEncrypted());
ugService = (MemoryUserGroupService) getSecurityManager().loadUserGroupService(serviceName);
assertEquals(plainTextUserGroup, ugService.getToBeEncrypted());
}
@Test
public void testPasswordPersistence() throws Exception {
Catalog cat = getCatalog();
SecurityManagerConfig config = getSecurityManager().getSecurityConfig();
GeoServerPasswordEncoder encoder = getPlainTextPasswordEncoder();
String prefix=encoder.getPrefix()+GeoServerPasswordEncoder.PREFIX_DELIMTER;
config.setConfigPasswordEncrypterName(encoder.getName());
getSecurityManager().saveSecurityConfig(config);
GeoServerPersister p =
new GeoServerPersister( getResourceLoader(), new XStreamPersisterFactory().createXMLPersister() );
cat.addListener( p );
WorkspaceInfo ws = cat.getFactory().createWorkspace();
ws.setName("password");
cat.add(ws);
DataStoreInfo ds = cat.getFactory().createDataStore();
ds.setName("password");
ds.getConnectionParameters().put("user", "testuser");
ds.getConnectionParameters().put("passwd", "secret");
ds.getConnectionParameters().put("host", "localhost");
ds.getConnectionParameters().put("port", "5432");
ds.getConnectionParameters().put("database", "testdb");
ds.getConnectionParameters().put("dbtype", "postgisng");
ds.setWorkspace(ws);
cat.add(ds);
// TODO Justin, this does not work ?
// DataStore dataStore = DataStoreFinder.getDataStore(ds.getConnectionParameters());
// assertNotNull(dataStore);
// dataStore.dispose();
//MockData data = getTestData();
File store = new File(getDataDirectory().root(),"workspaces/password/password/datastore.xml");
Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(store);
XPath xpath = XPathFactory.newInstance().newXPath();
String encrypted = xpath.evaluate("//entry[@key='passwd']", dom.getDocumentElement());
assertTrue((prefix+"secret").equals(encrypted));
XStreamPersister xs = new XStreamPersisterFactory().createXMLPersister();
FileInputStream fin = new FileInputStream(store);
DataStoreInfo load = xs.load(fin, DataStoreInfo.class);
fin.close();
assertEquals("secret",load.getConnectionParameters().get("passwd"));
// now encrypt
config.setConfigPasswordEncrypterName(getPBEPasswordEncoder().getName());
getSecurityManager().saveSecurityConfig(config);
getSecurityManager().updateConfigurationFilesWithEncryptedFields();
// FileInputStream fi = new FileInputStream(store);
// BufferedReader r = new BufferedReader(new InputStreamReader(fi));
// String line;
// while ((line= r.readLine())!=null)
// System.out.println(line);
// fi.close();
dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(store);
xpath = XPathFactory.newInstance().newXPath();
encrypted = xpath.evaluate("//entry[@key='passwd']", dom.getDocumentElement());
// TODO, assertion does not pass with mvn clean install
// but it passes with mvn test -Dtest=org.geoserver.security.impl.MemoryUserDetailsServiceTest
// ???????
// assertFalse("secret".equals(encrypted));
xs = new XStreamPersisterFactory().createXMLPersister();
fin = new FileInputStream(store);
load = xs.load(fin, DataStoreInfo.class);
assertEquals("secret",load.getConnectionParameters().get("passwd"));
fin.close();
}
}