/* (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 java.io.IOException;
import java.util.Arrays;
import org.geoserver.security.GeoServerSecurityManager;
import org.geoserver.security.GeoServerUserGroupService;
import org.geoserver.security.KeyStoreProviderImpl;
import org.geoserver.security.KeyStoreProvider;
import org.jasypt.encryption.pbe.StandardPBEByteEncryptor;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.spring.security3.PBEPasswordEncoder;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.crypto.codec.Base64;
import static org.geoserver.security.SecurityUtils.scramble;
import static org.geoserver.security.SecurityUtils.toBytes;
import static org.geoserver.security.SecurityUtils.toChars;
/**
* Password Encoder using symmetric encryption
*
* The salt parameter is not used, this implementation
* computes a random salt as default.
*
* {@link #isPasswordValid(String, String, Object)}
* {@link #encodePassword(String, Object)}
*
* @author christian
*
*/
public class GeoServerPBEPasswordEncoder extends AbstractGeoserverPasswordEncoder {
StandardPBEStringEncryptor stringEncrypter;
StandardPBEByteEncryptor byteEncrypter;
private String providerName,algorithm;
private String keyAliasInKeyStore = KeyStoreProviderImpl.CONFIGPASSWORDKEY;
private KeyStoreProvider keystoreProvider;
@Override
public void initialize(GeoServerSecurityManager securityManager)
throws IOException {
this.keystoreProvider = securityManager.getKeyStoreProvider();
}
@Override
public void initializeFor(GeoServerUserGroupService service) throws IOException {
if (!keystoreProvider.hasUserGroupKey(service.getName())) {
throw new IOException("No key alias: " +
keystoreProvider.aliasForGroupService(service.getName())+ " in key store: " +
keystoreProvider.getResource().path());
}
keyAliasInKeyStore = keystoreProvider.aliasForGroupService(service.getName());
}
public String getProviderName() {
return providerName;
}
public void setProviderName(String providerName) {
this.providerName = providerName;
}
public String getAlgorithm() {
return algorithm;
}
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
public String getKeyAliasInKeyStore() {
return keyAliasInKeyStore;
}
@Override
protected PasswordEncoder createStringEncoder() {
byte[] password = lookupPasswordFromKeyStore();
char[] chars = toChars(password);
try {
stringEncrypter = new StandardPBEStringEncryptor();
stringEncrypter.setPasswordCharArray(chars);
if (getProviderName()!=null && !getProviderName().isEmpty()) {
stringEncrypter.setProviderName(getProviderName());
}
stringEncrypter.setAlgorithm(getAlgorithm());
PBEPasswordEncoder encoder = new PBEPasswordEncoder();
encoder.setPbeStringEncryptor(stringEncrypter);
return encoder;
}
finally {
scramble(password);
scramble(chars);
}
}
@Override
protected CharArrayPasswordEncoder createCharEncoder() {
byte[] password = lookupPasswordFromKeyStore();
char[] chars = toChars(password);
byteEncrypter = new StandardPBEByteEncryptor();
byteEncrypter.setPasswordCharArray(chars);
if (getProviderName()!=null && !getProviderName().isEmpty()) {
byteEncrypter.setProviderName(getProviderName());
}
byteEncrypter.setAlgorithm(getAlgorithm());
return new CharArrayPasswordEncoder() {
@Override
public boolean isPasswordValid(String encPass, char[] rawPass, Object salt) {
byte [] decoded = Base64.decode(encPass.getBytes());
byte[] decrypted = byteEncrypter.decrypt(decoded);
char[] chars = toChars(decrypted);
try {
return Arrays.equals(chars, rawPass);
}
finally {
scramble(decrypted);
scramble(chars);
}
}
@Override
public String encodePassword(char[] rawPass, Object salt) {
byte[] bytes = toBytes(rawPass);
try {
return new String(Base64.encode(byteEncrypter.encrypt(bytes)));
}
finally {
scramble(bytes);
}
}
};
}
byte[] lookupPasswordFromKeyStore() {
try {
if (!keystoreProvider.containsAlias(getKeyAliasInKeyStore())) {
throw new RuntimeException("Keystore: " + keystoreProvider.getResource().path() + " does not" +
" contain alias: " + getKeyAliasInKeyStore());
}
return keystoreProvider.getSecretKey(getKeyAliasInKeyStore()).getEncoded();
} catch (IOException e) {
throw new RuntimeException( "Cannot find alias: "+getKeyAliasInKeyStore() +
" in "+ keystoreProvider.getResource().path());
}
}
@Override
public PasswordEncodingType getEncodingType() {
return PasswordEncodingType.ENCRYPT;
}
public String decode(String encPass) throws UnsupportedOperationException {
if (stringEncrypter == null) {
//not initialized
getStringEncoder();
}
return stringEncrypter.decrypt(removePrefix(encPass));
}
@Override
public char[] decodeToCharArray(String encPass)
throws UnsupportedOperationException {
if (byteEncrypter == null) {
//not initialized
getCharEncoder();
}
byte[] decoded = Base64.decode(removePrefix(encPass).getBytes());
byte[] bytes = byteEncrypter.decrypt(decoded);
try {
return toChars(bytes);
}
finally {
scramble(bytes);
}
}
}