mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
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:
@@ -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 //
|
||||
// -------- //
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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
|
||||
try
|
||||
{
|
||||
// disable auditing
|
||||
behaviourFilter.disableBehaviour();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Upgrading password hash for user: " + username);
|
||||
}
|
||||
authenticationDao.hashUserPassword(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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user