Merged 5.0.2-CLOUD42 (Cloud ) to 5.1.N (5.1.1)

117248 adavis: Merged 5.0.2-CLOUD (Cloud ) to 5.0.2-CLOUD42 (Cloud )
      114517 adavis: Merged BCRYPT to 5.0.2-CLOUD
         114012 gcornwell: MNT-14892: Updates to upgrade password hash job and test.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.1.N/root@117340 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2015-11-11 17:52:16 +00:00
parent 1c1a381c2c
commit d048e04218
6 changed files with 97 additions and 98 deletions

View File

@@ -41,7 +41,6 @@ import org.springframework.dao.DataAccessException;
* getMD4HashedPassword(String userName)
* loadUserByUsername(String arg0)
* getSalt(UserDetails user)
* hashUserPassword(String userName)
*
* @author Andy Hind
*/
@@ -386,15 +385,6 @@ public class DefaultMutableAuthenticationDao implements MutableAuthenticationDao
throw new AlfrescoRuntimeException("Not implemented");
}
/**
* @throws AlfrescoRuntimeException always
*/
@Override
public void hashUserPassword(String userName) throws AuthenticationException
{
throw new AlfrescoRuntimeException("Not implemented");
}
// -------- //
// Bean IOC //
// -------- //

View File

@@ -51,11 +51,6 @@ public interface MutableAuthenticationDao extends AuthenticationDao, SaltSource
*/
public boolean userExists(String userName);
/**
* Hashes the user password to the preferred encoding.
*/
public void hashUserPassword(String userName) throws AuthenticationException;
/**
* Enable/disable a user.
*/

View File

@@ -287,49 +287,14 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao, In
}
/**
* Should we rehash the password by updating the properties
* @param properties
* @return
* Retrieves the password hash for the given user properties.
*
* @param properties The properties of the user.
* @return A Pair object containing the hash indicator and the hashed password.
*/
public boolean rehashedPassword(Map<QName, Serializable> properties)
{
List<String> hashIndicator = (List<String>) properties.get(ContentModel.PROP_HASH_INDICATOR);
Pair<List<String>, String> passwordHash = determinePasswordHash(properties);
if (!compositePasswordEncoder.lastEncodingIsPreferred(passwordHash.getFirst()))
{
//We need to double hash
List<String> nowHashed = new ArrayList<String>();
nowHashed.addAll(passwordHash.getFirst());
nowHashed.add(compositePasswordEncoder.getPreferredEncoding());
Object salt = properties.get(ContentModel.PROP_SALT);
properties.put(ContentModel.PROP_PASSWORD_HASH, compositePasswordEncoder.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 (hashIndicator == null)
{
//Already the preferred encoding, just set it
properties.put(ContentModel.PROP_HASH_INDICATOR, (Serializable)passwordHash.getFirst());
properties.put(ContentModel.PROP_PASSWORD_HASH, passwordHash.getSecond());
properties.remove(ContentModel.PROP_PASSWORD);
properties.remove(ContentModel.PROP_PASSWORD_SHA256);
return true;
}
return false;
}
/**
* Where is the password and how is it encoded?
* @param properties
* @return
*/
protected Pair<List<String>, String> determinePasswordHash(Map<QName, Serializable> properties)
public static Pair<List<String>, String> determinePasswordHash(Map<QName, Serializable> properties)
{
@SuppressWarnings("unchecked")
List<String> hashIndicator = (List<String>) properties.get(ContentModel.PROP_HASH_INDICATOR);
if (hashIndicator != null && hashIndicator.size()>0)
{
@@ -354,8 +319,11 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao, In
}
}
}
throw new AlfrescoRuntimeException("Unable to find a user password, please check your repository authentication settings."
+ "(PreferredEncoding="+compositePasswordEncoder.getPreferredEncoding()+")");
// throw execption if we failed to find a password for the user
throw new AlfrescoRuntimeException("Unable to find a password for user '" +
properties.get(ContentModel.PROP_USER_USERNAME) +
"', please check your repository authentication settings.");
}
@Override
@@ -469,22 +437,6 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao, In
return (getUserOrNull(userName) != null);
}
@Override
public void hashUserPassword(String userName) throws AuthenticationException
{
NodeRef userRef = getUserOrNull(userName);
if (userRef == null)
{
throw new AuthenticationException("User name does not exist: " + userName);
}
Map<QName, Serializable> properties = nodeService.getProperties(userRef);
if (rehashedPassword(properties))
{
nodeService.setProperties(userRef, properties);
}
}
/**
* @return Returns the user properties or <tt>null</tt> if there are none
*/

View File

@@ -19,6 +19,7 @@
package org.alfresco.repo.security.authentication;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -43,6 +44,7 @@ import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.site.SiteModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
@@ -387,7 +389,13 @@ public class UpgradePasswordHashWorker implements ApplicationContextAware, Initi
this.progress = progress;
}
@SuppressWarnings("unchecked")
@Override
public void beforeProcess() throws Throwable
{
// Run as the systemuser
AuthenticationUtil.setRunAsUser(AuthenticationUtil.getSystemUserName());
}
@Override
public void process(Long nodeId) throws Throwable
{
@@ -398,26 +406,32 @@ public class UpgradePasswordHashWorker implements ApplicationContextAware, Initi
// get properties for the user
Map<QName, Serializable> userProps = nodeDAO.getNodeProperties(nodeId);
// get the hash indicator property
List<String> hashIndicator = (List<String>)userProps.get(ContentModel.PROP_HASH_INDICATOR);
// get the username
String username = (String)userProps.get(ContentModel.PROP_USER_USERNAME);
// determine whether we need to upgrade the password hash for the user
if (hashIndicator == null || !passwordEncoder.lastEncodingIsPreferred(hashIndicator))
// determine whether the password requires re-hashing
if (processPasswordHash(userProps))
{
progress.usersChanged.incrementAndGet();
// We do not want any behaviours associated with our transactions
behaviourFilter.disableBehaviour();
if (logger.isDebugEnabled())
try
{
logger.debug("Upgrading password hash for user: " + username);
}
authenticationDao.hashUserPassword(username);
// disable auditing
behaviourFilter.disableBehaviour();
if (logger.isDebugEnabled())
{
logger.debug("Upgrading password hash for user: " + username);
}
// persist the changes
nodeDAO.setNodeProperties(nodeId, userProps);
}
finally
{
// enable auditing
behaviourFilter.enableBehaviour();
}
}
else if (logger.isTraceEnabled())
{
@@ -439,6 +453,55 @@ public class UpgradePasswordHashWorker implements ApplicationContextAware, Initi
{
return (String)nodeDAO.getNodeProperty(nodeId, ContentModel.PROP_USER_USERNAME);
}
@Override
public void afterProcess() throws Throwable
{
AuthenticationUtil.clearCurrentSecurityContext();
}
/**
* Processes the user properties, re-hashing the password, if required.
*
* @param properties The properties for the user.
* @return true if the password was upgraded, false if no changes were made.
*/
private boolean processPasswordHash(Map<QName, Serializable> properties)
{
// retrieve the password and hash indicator
Pair<List<String>, String> passwordHash = RepositoryAuthenticationDao.determinePasswordHash(properties);
// determine if current password hash matches the preferred encoding
if (!passwordEncoder.lastEncodingIsPreferred(passwordHash.getFirst()))
{
// We need to double hash
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;
}
// ensure password hash is in the correct place
@SuppressWarnings("unchecked")
List<String> hashIndicator = (List<String>) properties.get(ContentModel.PROP_HASH_INDICATOR);
if (hashIndicator == null)
{
// Already the preferred encoding, just set it
properties.put(ContentModel.PROP_HASH_INDICATOR, (Serializable)passwordHash.getFirst());
properties.put(ContentModel.PROP_PASSWORD_HASH, passwordHash.getSecond());
properties.remove(ContentModel.PROP_PASSWORD);
properties.remove(ContentModel.PROP_PASSWORD_SHA256);
return true;
}
// if we get here no changes were made
return false;
}
}
/**

View File

@@ -237,15 +237,6 @@ public class NullMutableAuthenticationDao implements MutableAuthenticationDao
throw new AlfrescoRuntimeException("Not implemented");
}
/**
* @throws AlfrescoRuntimeException always
*/
@Override
public void hashUserPassword(String userName) throws AuthenticationException
{
throw new AlfrescoRuntimeException("Not implemented");
}
/**
* @throws AlfrescoRuntimeException Not implemented
*/

View File

@@ -108,6 +108,8 @@ public class UpgradePasswordHashTest extends TestCase
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
createTestUsers("md4");
userTransaction.commit();
}
protected void createTestUsers(String encoding) throws Exception
@@ -183,6 +185,9 @@ public class UpgradePasswordHashTest extends TestCase
public void testWorkerWithDefaultConfiguration() throws Exception
{
userTransaction = serviceRegistry.getTransactionService().getUserTransaction();
userTransaction.begin();
for (NodeRef testUser : testUsers)
{
assertNull("The hash indicator should not be set",nodeService.getProperty(testUser, ContentModel.PROP_HASH_INDICATOR));
@@ -191,6 +196,10 @@ public class UpgradePasswordHashTest extends TestCase
// execute the worker to upgrade all users
this.upgradePasswordHashWorker.execute();
userTransaction.commit();
userTransaction = serviceRegistry.getTransactionService().getUserTransaction();
userTransaction.begin();
// ensure all the test users have been upgraded to use the preferred encoding
List<String> doubleHashed = Arrays.asList("md4", "bcrypt10");
for (NodeRef testUser : testUsers)
@@ -200,7 +209,6 @@ public class UpgradePasswordHashTest extends TestCase
assertNull("The md4 password should not be set", nodeService.getProperty(testUser, ContentModel.PROP_PASSWORD));
assertNull("The sh256 password should not be set",nodeService.getProperty(testUser, ContentModel.PROP_PASSWORD_SHA256));
}
}
public void xxxtestWorkerWithLegacyConfiguration() throws Exception