Merged 5.1-MC1 (5.1.0) to HEAD (5.1)

119057 adavis: Merged 5.1.N (5.1.1) to 5.1-MC1 (5.1.0)
      117339 adavis: Merged 5.0.2-CLOUD42 (Cloud ) to 5.1.N (5.1.1)
         117247 adavis: Merged 5.0.2-CLOUD (Cloud ) to 5.0.2-CLOUD42 (Cloud )
            114516 adavis: Merged BCRYPT to 5.0.2-CLOUD
               114004 gjames: Added a hashUserPassword method, and working on UpgradePasswordHashTest MNT-14892


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@119896 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jean-Pierre Huynh
2015-12-10 09:59:53 +00:00
parent 05375c63fc
commit 1670fcce1e
6 changed files with 158 additions and 20 deletions

View File

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

View File

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

View File

@@ -469,6 +469,22 @@ public class RepositoryAuthenticationDao implements MutableAuthenticationDao, In
return (getUserOrNull(userName) != null); 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 * @return Returns the user properties or <tt>null</tt> if there are none
*/ */

View File

@@ -42,6 +42,7 @@ import org.alfresco.repo.lock.LockAcquisitionException;
import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.site.SiteModel; import org.alfresco.repo.site.SiteModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
@@ -278,6 +279,18 @@ public class UpgradePasswordHashWorker implements ApplicationContextAware, Initi
RetryingTransactionHelper retryingTransactionHelper = transactionService.getRetryingTransactionHelper(); RetryingTransactionHelper retryingTransactionHelper = transactionService.getRetryingTransactionHelper();
retryingTransactionHelper.setForceWritable(true); retryingTransactionHelper.setForceWritable(true);
//Create the QNames if they don't exist
retryingTransactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
qnameDAO.getOrCreateQName(ContentModel.PROP_PASSWORD_HASH);
qnameDAO.getOrCreateQName(ContentModel.PROP_HASH_INDICATOR);
return null;
}
}, false, true);
BatchProcessor<Long> batchProcessor = new BatchProcessor<Long>( BatchProcessor<Long> batchProcessor = new BatchProcessor<Long>(
"UpgradePasswordHashWorker", "UpgradePasswordHashWorker",
retryingTransactionHelper, retryingTransactionHelper,
@@ -399,15 +412,12 @@ public class UpgradePasswordHashWorker implements ApplicationContextAware, Initi
// We do not want any behaviours associated with our transactions // We do not want any behaviours associated with our transactions
behaviourFilter.disableBehaviour(); behaviourFilter.disableBehaviour();
// call hashedPassword on the RepositoryAuthenticationDao object
// ((RepositoryAuthenticationDao)authenticationDao).rehashedPassword(userProps);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Upgrading password hash for user: " + username); logger.debug("Upgrading password hash for user: " + username);
} }
authenticationDao.hashUserPassword(username);
} }
else if (logger.isTraceEnabled()) else if (logger.isTraceEnabled())
{ {

View File

@@ -237,6 +237,15 @@ public class NullMutableAuthenticationDao implements MutableAuthenticationDao
throw new AlfrescoRuntimeException("Not implemented"); 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 * @throws AlfrescoRuntimeException Not implemented
*/ */

View File

@@ -18,8 +18,12 @@
*/ */
package org.alfresco.repo.security.authentication; package org.alfresco.repo.security.authentication;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.transaction.Status; import javax.transaction.Status;
import javax.transaction.UserTransaction; import javax.transaction.UserTransaction;
@@ -27,11 +31,20 @@ import javax.transaction.UserTransaction;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.test_category.OwnJVMTestsCategory; import org.alfresco.test_category.OwnJVMTestsCategory;
import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.GUID;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@@ -43,9 +56,12 @@ public class UpgradePasswordHashTest extends TestCase
private UserTransaction userTransaction; private UserTransaction userTransaction;
private ServiceRegistry serviceRegistry; private ServiceRegistry serviceRegistry;
private NodeService nodeService;
private RepositoryAuthenticationDao repositoryAuthenticationDao;
private CompositePasswordEncoder compositePasswordEncoder;
private UpgradePasswordHashWorker upgradePasswordHashWorker; private UpgradePasswordHashWorker upgradePasswordHashWorker;
private List<String> testUserNames; private List<String> testUserNames;
private List<NodeRef> testUsers;
public UpgradePasswordHashTest() public UpgradePasswordHashTest()
{ {
super(); super();
@@ -67,27 +83,86 @@ public class UpgradePasswordHashTest extends TestCase
serviceRegistry = (ServiceRegistry)ctx.getBean("ServiceRegistry"); serviceRegistry = (ServiceRegistry)ctx.getBean("ServiceRegistry");
upgradePasswordHashWorker = (UpgradePasswordHashWorker)ctx.getBean("upgradePasswordHashWorker"); SimpleCache<String, RepositoryAuthenticationDao.CacheEntry> authenticationCache = (SimpleCache<String, RepositoryAuthenticationDao.CacheEntry>) ctx.getBean("authenticationCache");
SimpleCache<String, NodeRef> immutableSingletonCache = (SimpleCache<String, NodeRef>) ctx.getBean("immutableSingletonCache");
TenantService tenantService = (TenantService) ctx.getBean("tenantService");
compositePasswordEncoder = (CompositePasswordEncoder) ctx.getBean("compositePasswordEncoder");
PolicyComponent policyComponent = (PolicyComponent) ctx.getBean("policyComponent");
repositoryAuthenticationDao = new RepositoryAuthenticationDao();
repositoryAuthenticationDao.setTransactionService(serviceRegistry.getTransactionService());
repositoryAuthenticationDao.setAuthorityService(serviceRegistry.getAuthorityService());
repositoryAuthenticationDao.setTenantService(tenantService);
repositoryAuthenticationDao.setNodeService(serviceRegistry.getNodeService());
repositoryAuthenticationDao.setNamespaceService(serviceRegistry.getNamespaceService());
repositoryAuthenticationDao.setCompositePasswordEncoder(compositePasswordEncoder);
repositoryAuthenticationDao.setPolicyComponent(policyComponent);
repositoryAuthenticationDao.setAuthenticationCache(authenticationCache);
repositoryAuthenticationDao.setSingletonCache(immutableSingletonCache);
upgradePasswordHashWorker = (UpgradePasswordHashWorker)ctx.getBean("upgradePasswordHashWorker");
nodeService = serviceRegistry.getNodeService();
userTransaction = serviceRegistry.getTransactionService().getUserTransaction(); userTransaction = serviceRegistry.getTransactionService().getUserTransaction();
userTransaction.begin(); userTransaction.begin();
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName()); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
createTestUsers(); createTestUsers("md4");
} }
protected void createTestUsers() throws Exception protected void createTestUsers(String encoding) throws Exception
{ {
// create 50 users and change their properties back to how // create 50 users and change their properties back to how
// they would have been pre-upgrade. // they would have been pre-upgrade.
testUsers = new ArrayList<NodeRef>(50);
testUsers.add(createUser("king"+encoding, "king".toCharArray(), encoding));
testUsers.add(createUser("kin" +encoding, "Kong".toCharArray(), encoding));
testUsers.add(createUser("ding"+encoding, "dong".toCharArray(), encoding));
testUsers.add(createUser("ping"+encoding, "pong".toCharArray(),encoding));
testUsers.add(createUser("pin" +encoding, "pop".toCharArray(), encoding));
}
testUserNames = new ArrayList<String>(50); private NodeRef createUser(String caseSensitiveUserName, char[] password, String encoding)
{
try
{
repositoryAuthenticationDao.createUser(caseSensitiveUserName,password);
} catch (AuthenticationException e)
{
if (!e.getMessage().contains("User already exists")) { throw e; }
}
NodeRef userNodeRef = repositoryAuthenticationDao.getUserOrNull(caseSensitiveUserName);
if (userNodeRef == null)
{
throw new AuthenticationException("User name does not exist: " + caseSensitiveUserName);
}
Map<QName, Serializable> properties = nodeService.getProperties(userNodeRef);
properties.remove(ContentModel.PROP_PASSWORD_HASH);
properties.remove(ContentModel.PROP_HASH_INDICATOR);
properties.remove(ContentModel.PROP_PASSWORD);
properties.remove(ContentModel.PROP_PASSWORD_SHA256);
properties.put(ContentModel.PROP_PASSWORD, compositePasswordEncoder.encode(encoding,new String(password), null));
nodeService.setProperties(userNodeRef, properties);
return userNodeRef;
} }
protected void deleteTestUsers() throws Exception protected void deleteTestUsers() throws Exception
{ {
// delete all the test users. for (NodeRef testUser : testUsers)
{
try
{
nodeService.deleteNode(testUser);
}
catch (InvalidNodeRefException e)
{
//Just ignore it.
}
}
testUsers.clear();
} }
@Override @Override
@@ -108,10 +183,24 @@ public class UpgradePasswordHashTest extends TestCase
public void testWorkerWithDefaultConfiguration() throws Exception public void testWorkerWithDefaultConfiguration() throws Exception
{ {
for (NodeRef testUser : testUsers)
{
assertNull("The hash indicator should not be set",nodeService.getProperty(testUser, ContentModel.PROP_HASH_INDICATOR));
assertNull("The password hash should not be set",nodeService.getProperty(testUser, ContentModel.PROP_PASSWORD_HASH));
}
// execute the worker to upgrade all users // execute the worker to upgrade all users
this.upgradePasswordHashWorker.execute(); this.upgradePasswordHashWorker.execute();
// ensure all the test users have been upgraded to use the preferred encoding // ensure all the test users have been upgraded to use the preferred encoding
List<String> doubleHashed = Arrays.asList("md4", "bcrypt10");
for (NodeRef testUser : testUsers)
{
assertNotNull("The password hash should be set", nodeService.getProperty(testUser, ContentModel.PROP_PASSWORD_HASH));
assertEquals(doubleHashed,nodeService.getProperty(testUser, ContentModel.PROP_HASH_INDICATOR));
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 public void xxxtestWorkerWithLegacyConfiguration() throws Exception