mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-15 15:02:20 +00:00
Merged 5.1-MC1 (5.1.0) to HEAD (5.1)
119071 adavis: Merged 5.1.N (5.1.1) to 5.1-MC1 (5.1.0) 117354 adavis: Merged 5.0.2-CLOUD42 (Cloud ) to 5.1.N (5.1.1) 117261 adavis: Merged 5.0.2-CLOUD (Cloud ) to 5.0.2-CLOUD42 (Cloud ) 114795 gjames: BCRYPT RA-609: Ensure system does not double hash encoders if not safe git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@119910 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -26,6 +26,7 @@ import org.alfresco.util.PropertyCheck;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -75,6 +76,48 @@ public class CompositePasswordEncoder
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if its safe to encode the encoding chain. This applies particularly to double-hashing.
|
||||
* BCRYPT uses its own internal salt so its NOT safe to use it more than once in an encoding chain
|
||||
* (because the result will be different each time.) BCRYPT CAN BE USED successfully as the last element in
|
||||
* an encoding chain.
|
||||
*
|
||||
* Anything that implements springframework PasswordEncoder is considered "unsafe"
|
||||
* (because the method takes no salt param).
|
||||
*
|
||||
* @param encodingChain mandatory encoding chain
|
||||
* @return true if it is okay to encode this chain.
|
||||
*/
|
||||
public boolean isSafeToEncodeChain(List<String> encodingChain)
|
||||
{
|
||||
if (encodingChain!= null && encodingChain.size() > 0 )
|
||||
{
|
||||
List<String> unsafeEncoders = new ArrayList<>();
|
||||
for (String encoderKey : encodingChain)
|
||||
{
|
||||
Object encoder = encoders.get(encoderKey);
|
||||
if (encoder == null) throw new AlfrescoRuntimeException("Invalid encoder specified: "+encoderKey);
|
||||
if (encoder instanceof org.springframework.security.crypto.password.PasswordEncoder)
|
||||
{
|
||||
//BCRYPT uses its own internal salt so its NOT safe to use it more than once in an encoding chain.
|
||||
//the Spring PasswordEncoder class doesn't require a salt and BCRYPTEncoder implements this, so
|
||||
//we will count the instances of Spring PasswordEncoder
|
||||
unsafeEncoders.add(encoderKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (unsafeEncoders.isEmpty()) return true;
|
||||
if (unsafeEncoders.size() == 1 && unsafeEncoders.get(0).equals(encodingChain.get(encodingChain.size()-1)))
|
||||
{
|
||||
//The unsafe encoder is used at the end so that's ok.
|
||||
return true;
|
||||
}
|
||||
logger.warn("Unsafe encoders in the encoding chain: "+Arrays.toString(unsafeEncoders.toArray())
|
||||
+". Only 1 unsafe encoder is allowed at the end of the chain: "+Arrays.toString(encodingChain.toArray()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic init method for checking mandatory properties
|
||||
*/
|
||||
|
@@ -281,21 +281,31 @@ public class UpgradePasswordHashWorker implements ApplicationContextAware, Initi
|
||||
// determine if current password hash matches the preferred encoding
|
||||
if (!passwordEncoder.lastEncodingIsPreferred(passwordHash.getFirst()))
|
||||
{
|
||||
String username = (String)properties.get(ContentModel.PROP_USER_USERNAME);
|
||||
|
||||
// We need to double hash
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
String username = (String)properties.get(ContentModel.PROP_USER_USERNAME);
|
||||
logger.trace("Double hashing user '" + username + "'.");
|
||||
}
|
||||
List<String> nowHashed = new ArrayList<String>();
|
||||
nowHashed.addAll(passwordHash.getFirst());
|
||||
nowHashed.add(passwordEncoder.getPreferredEncoding());
|
||||
Object salt = properties.get(ContentModel.PROP_SALT);
|
||||
properties.put(ContentModel.PROP_PASSWORD_HASH, passwordEncoder.encodePreferred(new String(passwordHash.getSecond()), salt));
|
||||
properties.put(ContentModel.PROP_HASH_INDICATOR, (Serializable)nowHashed);
|
||||
properties.remove(ContentModel.PROP_PASSWORD);
|
||||
properties.remove(ContentModel.PROP_PASSWORD_SHA256);
|
||||
return true;
|
||||
|
||||
if (passwordEncoder.isSafeToEncodeChain(nowHashed))
|
||||
{
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("Double hashing user '" + username + "'.");
|
||||
}
|
||||
Object salt = properties.get(ContentModel.PROP_SALT);
|
||||
properties.put(ContentModel.PROP_PASSWORD_HASH, passwordEncoder.encodePreferred(new String(passwordHash.getSecond()), salt));
|
||||
properties.put(ContentModel.PROP_HASH_INDICATOR, (Serializable)nowHashed);
|
||||
properties.remove(ContentModel.PROP_PASSWORD);
|
||||
properties.remove(ContentModel.PROP_PASSWORD_SHA256);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn("Unsafe to Double Hash user: " + username + "'. The user needs to login first.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure password hash is in the correct place
|
||||
|
Reference in New Issue
Block a user