/* (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.password;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.security.GeoServerUserGroupService;
import org.geoserver.security.KeyStoreProvider;
import org.geoserver.security.xml.XMLUserGroupService;
import org.geoserver.test.GeoServerMockTestSupport;
import org.geotools.util.logging.Logging;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class GeoserverPasswordEncoderTest extends GeoServerMockTestSupport {
protected String testPassword="geoserver";
protected char[] testPasswordArray=testPassword.toCharArray();
protected char[] emptyArray = new char[] {};
static protected Logger LOGGER = Logging.getLogger("org.geoserver.security");
@Test
public void testPlainTextEncoder() {
GeoServerPasswordEncoder encoder = getPlainTextPasswordEncoder();
assertEquals(PasswordEncodingType.PLAIN,encoder.getEncodingType());
assertEquals("plain:"+testPassword,encoder.encodePassword(testPassword, null));
assertTrue(encoder.isResponsibleForEncoding("plain:123"));
assertFalse(encoder.isResponsibleForEncoding("digest1:123"));
String enc = encoder.encodePassword(testPassword, null);
String enc2 = encoder.encodePassword(testPasswordArray, null);
assertTrue(encoder.isPasswordValid(enc, testPassword, null));
assertTrue(encoder.isPasswordValid(enc, testPasswordArray, null));
assertTrue(encoder.isPasswordValid(enc2, testPassword, null));
assertTrue(encoder.isPasswordValid(enc2, testPasswordArray, null));
assertFalse(encoder.isPasswordValid(enc, "plain:blabla", null));
assertFalse(encoder.isPasswordValid(enc, "plain:blabla".toCharArray(), null));
assertFalse(encoder.isPasswordValid(enc2, "plain:blabla", null));
assertFalse(encoder.isPasswordValid(enc2, "plain:blabla".toCharArray(), null));
assertEquals(testPassword, encoder.decode(enc));
assertTrue(Arrays.equals(testPasswordArray, encoder.decodeToCharArray(enc)));
assertEquals(testPassword, encoder.decode(enc2));
assertTrue(Arrays.equals(testPasswordArray, encoder.decodeToCharArray(enc2)));
enc = encoder.encodePassword("", null);
assertTrue(encoder.isPasswordValid(enc, "", null));
enc2 = encoder.encodePassword(emptyArray, null);
assertTrue(encoder.isPasswordValid(enc, emptyArray, null));
}
@Test
public void testConfigPlainTextEncoder() {
GeoServerPasswordEncoder encoder = getPlainTextPasswordEncoder();
GeoServerMultiplexingPasswordEncoder encoder2 = new GeoServerMultiplexingPasswordEncoder(getSecurityManager());
assertEquals(PasswordEncodingType.PLAIN,encoder.getEncodingType());
assertEquals("plain:"+testPassword,encoder.encodePassword(testPassword, null));
assertTrue(encoder.isResponsibleForEncoding("plain:123"));
assertFalse(encoder.isResponsibleForEncoding("digest1:123"));
String enc = encoder.encodePassword(testPassword, null);
String enc2 = encoder.encodePassword(testPasswordArray, null);
assertTrue(encoder.isPasswordValid(enc, testPassword, null));
assertTrue(encoder.isPasswordValid(enc, testPasswordArray, null));
assertTrue(encoder.isPasswordValid(enc2, testPassword, null));
assertTrue(encoder.isPasswordValid(enc2, testPasswordArray, null));
assertTrue(encoder2.isPasswordValid(enc, testPassword, null));
assertTrue(encoder2.isPasswordValid(enc, testPasswordArray, null));
assertTrue(encoder2.isPasswordValid(enc2, testPassword, null));
assertTrue(encoder2.isPasswordValid(enc2, testPasswordArray, null));
assertFalse(encoder.isPasswordValid(enc, "plain:blabla", null));
assertFalse(encoder.isPasswordValid(enc, "plain:blabla".toCharArray(), null));
assertFalse(encoder.isPasswordValid(enc2, "plain:blabla", null));
assertFalse(encoder.isPasswordValid(enc2, "plain:blabla".toCharArray(), null));
assertFalse(encoder2.isPasswordValid(enc, "plain:blabla", null));
assertFalse(encoder2.isPasswordValid(enc, "plain:blabla".toCharArray(), null));
assertFalse(encoder2.isPasswordValid(enc2, "plain:blabla", null));
assertFalse(encoder2.isPasswordValid(enc2, "plain:blabla".toCharArray(), null));
assertEquals(testPassword, encoder.decode(enc));
assertTrue(Arrays.equals(testPasswordArray, encoder.decodeToCharArray(enc)));
assertEquals(testPassword, encoder.decode(enc2));
assertTrue(Arrays.equals(testPasswordArray, encoder.decodeToCharArray(enc2)));
assertEquals(testPassword, encoder2.decode(enc));
assertTrue(Arrays.equals(testPasswordArray, encoder2.decodeToCharArray(enc)));
assertEquals(testPassword, encoder2.decode(enc2));
assertTrue(Arrays.equals(testPasswordArray, encoder2.decodeToCharArray(enc2)));
enc = encoder.encodePassword("", null);
assertTrue(encoder.isPasswordValid(enc, "", null));
assertTrue(encoder2.isPasswordValid(enc, "", null));
enc2 = encoder.encodePassword(emptyArray, null);
assertTrue(encoder.isPasswordValid(enc, emptyArray, null));
assertTrue(encoder2.isPasswordValid(enc, emptyArray, null));
}
@Test
public void testDigestEncoder() {
GeoServerPasswordEncoder encoder = getDigestPasswordEncoder();
GeoServerMultiplexingPasswordEncoder encoder2 = new GeoServerMultiplexingPasswordEncoder(getSecurityManager());
assertEquals(PasswordEncodingType.DIGEST,encoder.getEncodingType());
assertTrue(encoder.encodePassword(testPassword, null).startsWith("digest1:"));
String enc = encoder.encodePassword(testPassword, null);
String enc2 = encoder.encodePassword(testPasswordArray, null);
assertTrue(encoder.isPasswordValid(enc, testPassword, null));
assertTrue(encoder.isPasswordValid(enc, testPasswordArray, null));
assertTrue(encoder.isPasswordValid(enc2, testPassword, null));
assertTrue(encoder.isPasswordValid(enc2, testPasswordArray, null));
assertTrue(encoder2.isPasswordValid(enc, testPassword, null));
assertTrue(encoder2.isPasswordValid(enc, testPasswordArray, null));
assertTrue(encoder2.isPasswordValid(enc2, testPassword, null));
assertTrue(encoder2.isPasswordValid(enc2, testPasswordArray, null));
assertFalse(encoder.isPasswordValid(enc, "plain:blabla", null));
assertFalse(encoder.isPasswordValid(enc, "plain:blabla".toCharArray(), null));
assertFalse(encoder.isPasswordValid(enc2, "plain:blabla", null));
assertFalse(encoder.isPasswordValid(enc2, "plain:blabla".toCharArray(), null));
assertFalse(encoder2.isPasswordValid(enc, "plain:blabla", null));
assertFalse(encoder2.isPasswordValid(enc, "plain:blabla".toCharArray(), null));
assertFalse(encoder2.isPasswordValid(enc2, "plain:blabla", null));
assertFalse(encoder2.isPasswordValid(enc2, "plain:blabla".toCharArray(), null));
enc = encoder.encodePassword("", null);
assertTrue(encoder.isPasswordValid(enc, "", null));
assertTrue(encoder2.isPasswordValid(enc, "", null));
enc2 = encoder.encodePassword(emptyArray, null);
assertTrue(encoder.isPasswordValid(enc, emptyArray, null));
assertTrue(encoder2.isPasswordValid(enc, emptyArray, null));
try {
encoder.decode(enc);
fail("Must fail, digested passwords cannot be decoded");
} catch (UnsupportedOperationException ex) {
}
try {
encoder2.decode(enc);
fail("Must fail, digested passwords cannot be decoded");
} catch (UnsupportedOperationException ex) {
}
// Test if encoding does not change between versions
assertTrue(encoder.isPasswordValid(
"digest1:CTBPxdfHvqy0K0M6uoYlb3+fPFrfMhpTm7+ey5rL/1xGI4s6g8n/OrkXdcyqzJ3D",
testPassword,null));
assertTrue(encoder2.isPasswordValid(
"digest1:CTBPxdfHvqy0K0M6uoYlb3+fPFrfMhpTm7+ey5rL/1xGI4s6g8n/OrkXdcyqzJ3D",
testPassword,null));
}
// @Test public void testDigestEncoderBytes() {
// GeoServerPasswordEncoder encoder = getDigestPasswordEncoder();
// assertEquals(PasswordEncodingType.DIGEST,encoder.getEncodingType());
// assertTrue(encoder.encodePassword(testPassword.toCharArray(), null).startsWith("digest1:"));
//
// String enc = encoder.encodePassword(testPassword.toCharArray(), null);
// assertTrue(encoder.isPasswordValid(enc, testPassword.toCharArray(), null));
// assertFalse(encoder.isPasswordValid(enc, "digest1:blabla".toCharArray(), null));
//
// try {
// encoder.decode(enc);
// fail("Must fail, digested passwords cannot be decoded");
// } catch (UnsupportedOperationException ex) {
// }
//
// enc = encoder.encodePassword("".toCharArray(), null);
// assertTrue(encoder.isPasswordValid(enc, "".toCharArray(), null));
//
// assertTrue(encoder.isPasswordValid(
// "digest1:vimlmdmyH+VoUV1jkM+p8/uIyDY+h+WOtmSYUPT6r3SWtkg26oi5E08Yfo1v7jzz",
// testPassword,null));
// }
@Test
public void testEmptyEncoder() {
GeoServerPasswordEncoder encoder = getSecurityManager().loadPasswordEncoder(GeoServerEmptyPasswordEncoder.class);
assertEquals(PasswordEncodingType.EMPTY, encoder.getEncodingType());
String encodedPassword = encoder.getPrefix()+GeoServerPasswordEncoder.PREFIX_DELIMTER;
assertEquals(encodedPassword,encoder.encodePassword((String)null, null));
assertEquals(encodedPassword,encoder.encodePassword((char[])null, null));
assertEquals(encodedPassword,encoder.encodePassword("", null));
assertEquals(encodedPassword,encoder.encodePassword(new char[]{}, null));
assertEquals(encodedPassword,encoder.encodePassword("blbal", null));
assertEquals(encodedPassword,encoder.encodePassword("blbal".toCharArray(), null));
assertFalse(encoder.isPasswordValid(encodedPassword,"blabla",null));
assertFalse(encoder.isPasswordValid(encodedPassword,"blabla".toCharArray(),null));
assertFalse(encoder.isPasswordValid(encodedPassword,"",null));
assertFalse(encoder.isPasswordValid(encodedPassword,"".toCharArray(),null));
try {
encoder.decode("");
fail("Must fail, empty passwords cannot be decoded");
} catch (UnsupportedOperationException ex) {
}
GeoServerMultiplexingPasswordEncoder encoder2 = new GeoServerMultiplexingPasswordEncoder(getSecurityManager());
assertFalse(encoder2.isPasswordValid(encodedPassword,"blabla",null));
assertFalse(encoder2.isPasswordValid(encodedPassword,"blabla".toCharArray(),null));
assertFalse(encoder2.isPasswordValid(encodedPassword,"",null));
assertFalse(encoder2.isPasswordValid(encodedPassword,"".toCharArray(),null));
try {
encoder2.decode("");
fail("Must fail, empty passwords cannot be decoded");
} catch (UnsupportedOperationException ex) {
}
}
protected List<GeoServerPasswordEncoder> getConfigPBEEncoders() {
List<GeoServerPasswordEncoder> result = new ArrayList<GeoServerPasswordEncoder>();
result.add(getPBEPasswordEncoder());
if (getSecurityManager().isStrongEncryptionAvailable()) {
result.add(getStrongPBEPasswordEncoder());
} else {
LOGGER.warning("Skipping strong encryption tests for configuration passwords");
}
return result;
}
@Test
public void testConfigPBEEncoder() throws Exception {
// TODO runs from eclpise, but not from mnv clean install
//assertTrue("masterpw".equals(MasterPasswordProviderImpl.get().getMasterPassword()));
GeoServerMultiplexingPasswordEncoder encoder2 = new GeoServerMultiplexingPasswordEncoder(getSecurityManager());
for (GeoServerPasswordEncoder encoder: getConfigPBEEncoders()) {
encoder.initialize(getSecurityManager());
assertEquals(PasswordEncodingType.ENCRYPT,encoder.getEncodingType());
assertTrue(encoder.encodePassword(testPassword, null).
startsWith(encoder.getPrefix()+AbstractGeoserverPasswordEncoder.PREFIX_DELIMTER));
String enc = encoder.encodePassword(testPassword, null);
String enc2 = encoder.encodePassword(testPasswordArray, null);
assertTrue(encoder.isPasswordValid(enc, testPassword, null));
assertTrue(encoder.isPasswordValid(enc, testPasswordArray, null));
assertTrue(encoder.isPasswordValid(enc2, testPassword, null));
assertTrue(encoder.isPasswordValid(enc2, testPasswordArray, null));
assertTrue(encoder2.isPasswordValid(enc, testPassword, null));
assertTrue(encoder2.isPasswordValid(enc, testPasswordArray, null));
assertTrue(encoder2.isPasswordValid(enc2, testPassword, null));
assertTrue(encoder2.isPasswordValid(enc2, testPasswordArray, null));
assertFalse(encoder.isPasswordValid(enc, "crypt1:blabla", null));
assertFalse(encoder.isPasswordValid(enc, "crypt1:blabla".toCharArray(), null));
assertFalse(encoder.isPasswordValid(enc2, "crypt1:blabla", null));
assertFalse(encoder.isPasswordValid(enc2, "crypt1:blabla".toCharArray(), null));
assertFalse(encoder2.isPasswordValid(enc, "crypt1:blabla", null));
assertFalse(encoder2.isPasswordValid(enc, "crypt1:blabla".toCharArray(), null));
assertFalse(encoder2.isPasswordValid(enc2, "crypt1:blabla", null));
assertFalse(encoder2.isPasswordValid(enc2, "crypt1:blabla".toCharArray(), null));
assertEquals(testPassword, encoder.decode(enc));
assertTrue(Arrays.equals(testPasswordArray, encoder.decodeToCharArray(enc)));
assertEquals(testPassword, encoder.decode(enc2));
assertTrue(Arrays.equals(testPasswordArray, encoder.decodeToCharArray(enc2)));
assertEquals(testPassword, encoder2.decode(enc));
assertTrue(Arrays.equals(testPasswordArray, encoder2.decodeToCharArray(enc)));
assertEquals(testPassword, encoder2.decode(enc2));
assertTrue(Arrays.equals(testPasswordArray, encoder2.decodeToCharArray(enc2)));
enc = encoder.encodePassword("", null);
assertTrue(encoder.isPasswordValid(enc, "", null));
assertTrue(encoder2.isPasswordValid(enc, "", null));
enc2 = encoder.encodePassword(emptyArray, null);
assertTrue(encoder.isPasswordValid(enc, emptyArray, null));
assertTrue(encoder2.isPasswordValid(enc, emptyArray, null));
}
}
protected List<GeoServerPBEPasswordEncoder> getPBEEncoders() {
List<GeoServerPBEPasswordEncoder> result = new ArrayList<GeoServerPBEPasswordEncoder>();
result.add(getPBEPasswordEncoder());
if (getSecurityManager().isStrongEncryptionAvailable()) {
result.add(getStrongPBEPasswordEncoder());
} else {
LOGGER.warning("Skipping strong encryption tests for user passwords");
}
return result;
}
@Test
public void testUserGroupServiceEncoder() throws Exception {
GeoServerUserGroupService service = getSecurityManager().
loadUserGroupService(XMLUserGroupService.DEFAULT_NAME);
//getPBEPasswordEncoder();
// boolean fail = true;
// try {
// encoder.initializeFor(service);
// } catch (IOException ex){
// fail = false;
// }
// assertFalse(fail);
String password = "testpassword";
char [] passwordArray = password.toCharArray();
KeyStoreProvider keyStoreProvider = getSecurityManager().getKeyStoreProvider();
keyStoreProvider.setUserGroupKey(service.getName(), password.toCharArray());
GeoServerMultiplexingPasswordEncoder encoder3 = new GeoServerMultiplexingPasswordEncoder(getSecurityManager(),service);
for (GeoServerPBEPasswordEncoder encoder: getPBEEncoders()) {
encoder.initializeFor(service);
assertEquals(PasswordEncodingType.ENCRYPT,encoder.getEncodingType());
assertEquals(encoder.getKeyAliasInKeyStore(),
keyStoreProvider.aliasForGroupService(service.getName()));
GeoServerPBEPasswordEncoder encoder2 = (GeoServerPBEPasswordEncoder)
getSecurityManager().loadPasswordEncoder(encoder.getName());
encoder2.initializeFor(service);
assertFalse(encoder==encoder2);
String enc = encoder.encodePassword(password , null);
assertTrue(enc.
startsWith(encoder.getPrefix()+AbstractGeoserverPasswordEncoder.PREFIX_DELIMTER));
String encFromArray = encoder.encodePassword(passwordArray , null);
assertTrue(encFromArray.
startsWith(encoder.getPrefix()+AbstractGeoserverPasswordEncoder.PREFIX_DELIMTER));
assertFalse(enc.equals(password ));
assertFalse(Arrays.equals(encFromArray.toCharArray(),passwordArray));
assertTrue(encoder2.isPasswordValid(enc, password , null));
assertTrue(encoder2.isPasswordValid(encFromArray, password , null));
assertTrue(encoder2.isPasswordValid(enc, passwordArray , null));
assertTrue(encoder2.isPasswordValid(encFromArray, passwordArray , null));
assertTrue(encoder3.isPasswordValid(enc, password , null));
assertTrue(encoder3.isPasswordValid(encFromArray, password , null));
assertTrue(encoder3.isPasswordValid(enc, passwordArray , null));
assertTrue(encoder3.isPasswordValid(encFromArray, passwordArray , null));
assertEquals(password ,encoder2.decode(enc));
assertEquals(password ,encoder3.decode(enc));
assertEquals(password ,encoder.decode(enc));
assertEquals(password ,encoder.decode(encFromArray));
assertTrue(Arrays.equals(passwordArray ,encoder.decodeToCharArray(enc)));
assertTrue(Arrays.equals(passwordArray ,encoder.decodeToCharArray(encFromArray)));
}
}
@Test
public void testCustomPasswordProvider() {
ClassPathXmlApplicationContext appContext =
new ClassPathXmlApplicationContext("classpath*:/passwordSecurityContext.xml");
appContext.refresh();
List<GeoServerPasswordEncoder> encoders =
GeoServerExtensions.extensions(GeoServerPasswordEncoder.class, appContext);
boolean found = false;
for (GeoServerPasswordEncoder enc : encoders) {
if (enc.getPrefix()!= null && enc.getPrefix().equals("plain4711")) {
found=true;
break;
}
}
assertTrue(found);
}
}