/* (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.HashSet;
import java.util.Set;
import java.util.logging.Logger;
import org.geoserver.security.GeoServerSecurityManager;
import org.geoserver.security.GeoServerUserGroupService;
import org.geotools.util.logging.Logging;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.util.StringUtils;
/**
* Multiplexing password encoder.
* <p>
* The purpose of this class is to decode a previously encoded password without knowing before hand which password
* encoder was used. The prefix contained in the encoded password is used to route to the appropriate
* delegate encoder. Therefore only {@link GeoserverPasswordEncoder} implementations that use a
* prefix in the encoded password are valid for this encoder.
* </p>
* <p>
* This class can also encode (although not typically used to do so). Encoding simply returns the first
* avaialble and successful encoder.
* </p>
*
* @author christian
*
*/
public class GeoServerMultiplexingPasswordEncoder implements PasswordEncoder {
static Logger LOG = Logging.getLogger(GeoServerMultiplexingPasswordEncoder.class);
protected Set<GeoServerPasswordEncoder> encoders;
public GeoServerMultiplexingPasswordEncoder(GeoServerSecurityManager secMgr) {
this(secMgr, null);
}
public GeoServerMultiplexingPasswordEncoder(GeoServerSecurityManager secMgr, GeoServerUserGroupService service) {
encoders=new HashSet<GeoServerPasswordEncoder>();
for (GeoServerPasswordEncoder enc : secMgr.loadPasswordEncoders()) {
if (StringUtils.hasLength(enc.getPrefix())) {
if (service!=null) {
try {
if (enc instanceof GeoServerPBEPasswordEncoder) {
if (!secMgr.getKeyStoreProvider().hasUserGroupKey(service.getName())) {
continue; // cannot use pbe encoder, no key
}
}
enc.initializeFor(service);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
encoders.add(enc);
}
}
}
GeoServerPasswordEncoder lookupEncoderForEncodedPassword(String encPass) throws UnsupportedOperationException{
for (GeoServerPasswordEncoder enc : encoders) {
if (enc.isResponsibleForEncoding(encPass))
return enc;
}
throw new UnsupportedOperationException("No password decoder for: "+encPass);
}
@Override
public String encodePassword(String rawPass, Object salt) throws UnsupportedOperationException{
for (GeoServerPasswordEncoder enc : encoders) {
try {
return enc.encodePassword(rawPass, salt);
}
catch(Exception e) {
LOG.fine("Password encode failed with " + enc.getName());
}
}
throw new UnsupportedOperationException();
}
@Override
public boolean isPasswordValid(String encPass, String rawPass, Object salt) throws UnsupportedOperationException {
GeoServerPasswordEncoder enc = lookupEncoderForEncodedPassword(encPass);
return enc.isPasswordValid(encPass, rawPass, salt);
}
public boolean isPasswordValid(String encPass, char[] rawPass, Object salt) throws UnsupportedOperationException {
GeoServerPasswordEncoder enc = lookupEncoderForEncodedPassword(encPass);
return enc.isPasswordValid(encPass, rawPass, salt);
}
public String decode(String encPass) throws UnsupportedOperationException {
GeoServerPasswordEncoder enc = lookupEncoderForEncodedPassword(encPass);
return enc.decode(encPass);
}
public char[] decodeToCharArray(String encPass) throws UnsupportedOperationException {
GeoServerPasswordEncoder enc = lookupEncoderForEncodedPassword(encPass);
return enc.decodeToCharArray(encPass);
}
}