Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)

93247: Merged 5.0.N (5.0.1) to HEAD-BUG-FIX (5.1/Cloud)
      93129: Merged V4.2-BUG-FIX (4.2.5) to 5.0.N (5.0.1)
         93098: MNT-12849 "My Sites public API is not returning the expected list of sites"


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@94945 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2015-01-31 12:14:27 +00:00
parent 4912765624
commit 744d19fdae
4 changed files with 153 additions and 7 deletions

View File

@@ -101,6 +101,7 @@
<property name="authorityBridgeDAO" ref="authorityBridgeDAO" /> <property name="authorityBridgeDAO" ref="authorityBridgeDAO" />
<property name="authorityBridgeTableCache" ref="authorityBridgeTableCache" /> <property name="authorityBridgeTableCache" ref="authorityBridgeTableCache" />
<property name="useBridgeTable" value="${authority.useBridgeTable}" /> <property name="useBridgeTable" value="${authority.useBridgeTable}" />
<property name="zoneAuthoritySampleSize" value="${authority.zoneAuthoritySampleSize}" />
</bean> </bean>
<bean name="authorityBridgeDAO" class="org.alfresco.repo.security.authority.AuthorityBridgeDAOImpl"> <bean name="authorityBridgeDAO" class="org.alfresco.repo.security.authority.AuthorityBridgeDAOImpl">

View File

@@ -971,6 +971,7 @@ trashcan.MaxSize=1000
# Use bridge tables for caching authority evaluation. # Use bridge tables for caching authority evaluation.
# #
authority.useBridgeTable=true authority.useBridgeTable=true
authority.zoneAuthoritySampleSize=10000
# enable QuickShare - if false then the QuickShare-specific REST APIs will return 403 Forbidden # enable QuickShare - if false then the QuickShare-specific REST APIs will return 403 Forbidden
system.quickshare.enabled=true system.quickshare.enabled=true

View File

@@ -145,7 +145,11 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
super(); super();
} }
public int getZoneAuthoritySampleSize()
{
return zoneAuthoritySampleSize;
}
/** /**
* Sets number of authorities in a zone to pre-cache, allowing quick generation of 'first n' results and adaption of * Sets number of authorities in a zone to pre-cache, allowing quick generation of 'first n' results and adaption of
* search technique based on hit rate. * search technique based on hit rate.
@@ -532,7 +536,7 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
} }
final PagingResults<PersonInfo> ppr = personService.getPeople(filter, true, sort, pagingRequest); final PagingResults<PersonInfo> ppr = personService.getPeople(filter, true, sort, pagingRequest);
List<PersonInfo> result = ppr.getPage(); List<PersonInfo> result = ppr.getPage();
final List<String> auths = new ArrayList<String>(result.size()); final List<String> auths = new ArrayList<String>(result.size());
@@ -911,7 +915,9 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
}, tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), currentUserDomain)); }, tenantService.getDomainUser(AuthenticationUtil.getSystemUserName(), currentUserDomain));
zoneAuthorityCache.put(cacheKey, zoneAuthorities); zoneAuthorityCache.put(cacheKey, zoneAuthorities);
} }
int numAuthorities = zoneAuthorities.size();
// Now search each for the required authority. If the number of results is greater than or close to the size // Now search each for the required authority. If the number of results is greater than or close to the size
// limit, then this will be the most efficient route // limit, then this will be the most efficient route
Set<String> result = new TreeSet<String>(); Set<String> result = new TreeSet<String>();
@@ -950,7 +956,8 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
} }
// If this top down search is not providing an adequate hit count then resort to a naiive unlimited search // If this top down search is not providing an adequate hit count then resort to a naiive unlimited search
if (processed >= maxToProcess) // we need to compare to the actual number of authorities cached or newly fetched from the database
if (processed >= numAuthorities)
{ {
Set<String> unfilteredResult; Set<String> unfilteredResult;
boolean filterZone; boolean filterZone;

View File

@@ -19,10 +19,12 @@
package org.alfresco.repo.security.authority; package org.alfresco.repo.security.authority;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -31,13 +33,14 @@ import javax.transaction.Status;
import javax.transaction.UserTransaction; import javax.transaction.UserTransaction;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException; import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQueryPageDetails;
import org.alfresco.query.PagingRequest; import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults; import org.alfresco.query.PagingResults;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.domain.permissions.AclDAO; import org.alfresco.repo.domain.permissions.AclDAO;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.node.archive.NodeArchiveService;
@@ -46,8 +49,11 @@ import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.MutableAuthenticationDao; import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
import org.alfresco.repo.site.SiteMembership;
import org.alfresco.repo.site.SiteModel;
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.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
@@ -60,13 +66,18 @@ import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility;
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.namespace.RegexQNamePattern; import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
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.alfresco.util.Pair;
import org.alfresco.util.PropertyMap;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@@ -81,6 +92,8 @@ public class AuthorityServiceTest extends TestCase
private AuthorityService authorityService; private AuthorityService authorityService;
private AuthorityService pubAuthorityService; private AuthorityService pubAuthorityService;
private PersonService personService; private PersonService personService;
private AuthorityDAOImpl authorityDAO;
private SiteService siteService;
private UserTransaction tx; private UserTransaction tx;
private AclDAO aclDaoComponent; private AclDAO aclDaoComponent;
private NodeService nodeService; private NodeService nodeService;
@@ -88,7 +101,9 @@ public class AuthorityServiceTest extends TestCase
private NodeArchiveService nodeArchiveService; private NodeArchiveService nodeArchiveService;
private PolicyComponent policyComponent; private PolicyComponent policyComponent;
private TransactionService transactionService; private TransactionService transactionService;
private SimpleCache<Pair<String, String>, List<ChildAssociationRef>> zoneToAuthorityCache;
public AuthorityServiceTest() public AuthorityServiceTest()
{ {
super(); super();
@@ -103,6 +118,7 @@ public class AuthorityServiceTest extends TestCase
private int GRP_CNT = 0; private int GRP_CNT = 0;
private int ROOT_GRP_CNT = 0; private int ROOT_GRP_CNT = 0;
@SuppressWarnings("unchecked")
public void setUp() throws Exception public void setUp() throws Exception
{ {
if (AlfrescoTransactionSupport.getTransactionReadState() != TxnReadState.TXN_NONE) if (AlfrescoTransactionSupport.getTransactionReadState() != TxnReadState.TXN_NONE)
@@ -117,14 +133,17 @@ public class AuthorityServiceTest extends TestCase
authorityService = (AuthorityService) ctx.getBean("authorityService"); authorityService = (AuthorityService) ctx.getBean("authorityService");
pubAuthorityService = (AuthorityService) ctx.getBean("AuthorityService"); pubAuthorityService = (AuthorityService) ctx.getBean("AuthorityService");
personService = (PersonService) ctx.getBean("personService"); personService = (PersonService) ctx.getBean("personService");
siteService = (SiteService) ctx.getBean("siteService");
authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao"); authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao");
authorityDAO = (AuthorityDAOImpl) ctx.getBean("authorityDAO");
aclDaoComponent = (AclDAO) ctx.getBean("aclDAO"); aclDaoComponent = (AclDAO) ctx.getBean("aclDAO");
nodeService = (NodeService) ctx.getBean("nodeService"); nodeService = (NodeService) ctx.getBean("nodeService");
authorityBridgeTableCache = (AuthorityBridgeTableAsynchronouslyRefreshedCache) ctx.getBean("authorityBridgeTableCache"); authorityBridgeTableCache = (AuthorityBridgeTableAsynchronouslyRefreshedCache) ctx.getBean("authorityBridgeTableCache");
nodeArchiveService = (NodeArchiveService) ctx.getBean("nodeArchiveService"); nodeArchiveService = (NodeArchiveService) ctx.getBean("nodeArchiveService");
policyComponent = (PolicyComponent) ctx.getBean("policyComponent"); policyComponent = (PolicyComponent) ctx.getBean("policyComponent");
transactionService = (TransactionService) ctx.getBean(ServiceRegistry.TRANSACTION_SERVICE.getLocalName()); transactionService = (TransactionService) ctx.getBean(ServiceRegistry.TRANSACTION_SERVICE.getLocalName());
zoneToAuthorityCache = (SimpleCache<Pair<String, String>, List<ChildAssociationRef>>) ctx.getBean("zoneToAuthorityCache");
String defaultAdminUser = AuthenticationUtil.getAdminUserName(); String defaultAdminUser = AuthenticationUtil.getAdminUserName();
AuthenticationUtil.setFullyAuthenticatedUser(defaultAdminUser); AuthenticationUtil.setFullyAuthenticatedUser(defaultAdminUser);
@@ -134,6 +153,7 @@ public class AuthorityServiceTest extends TestCase
// note: currently depends on any existing (and/or bootstrap) group data - eg. default site "swsdp" (Sample Web Site Design Project) // note: currently depends on any existing (and/or bootstrap) group data - eg. default site "swsdp" (Sample Web Site Design Project)
SiteService siteService = (SiteService) ctx.getBean("SiteService"); SiteService siteService = (SiteService) ctx.getBean("SiteService");
SITE_CNT = siteService.listSites(defaultAdminUser).size(); SITE_CNT = siteService.listSites(defaultAdminUser).size();
GRP_CNT = DEFAULT_GRP_CNT + (DEFAULT_SITE_GRP_CNT * SITE_CNT); GRP_CNT = DEFAULT_GRP_CNT + (DEFAULT_SITE_GRP_CNT * SITE_CNT);
ROOT_GRP_CNT = DEFAULT_GRP_CNT + (DEFAULT_SITE_ROOT_GRP_CNT * SITE_CNT); ROOT_GRP_CNT = DEFAULT_GRP_CNT + (DEFAULT_SITE_ROOT_GRP_CNT * SITE_CNT);
@@ -1504,4 +1524,121 @@ public class AuthorityServiceTest extends TestCase
{ {
return pubAuthorityService.getAuthorities(type, null, null, false, true, new PagingRequest(0, Integer.MAX_VALUE, null)).getPage(); return pubAuthorityService.getAuthorities(type, null, null, false, true, new PagingRequest(0, Integer.MAX_VALUE, null)).getPage();
} }
protected void createUser(String userName, String password)
{
if (authenticationService.authenticationExists(userName) == false)
{
authenticationService.createAuthentication(userName, password.toCharArray());
PropertyMap ppOne = new PropertyMap(4);
ppOne.put(ContentModel.PROP_USERNAME, userName);
ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");
ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
personService.createPerson(ppOne);
}
}
public void testMNT12849()
{
AuthenticationUtil.pushAuthentication();
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
// intentionally low zone authority sample size
int saveZoneAuthoritySampleSize = authorityDAO.getZoneAuthoritySampleSize();
authorityDAO.setZoneAuthoritySampleSize(2);
try
{
// create user
final String userName = GUID.generate();
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
createUser(userName, "password");
return null;
}
}, false, true);
final Set<String> zones = new HashSet<String>();
zones.add(AuthorityService.ZONE_APP_SHARE);
final List<SiteInfo> siteInfos = new LinkedList<>();
// create some sites with the user as member
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
for(int i = 0; i < 5; i++)
{
String siteName = GUID.generate();
SiteInfo siteInfo = siteService.createSite("", siteName, siteName, siteName, SiteVisibility.PUBLIC);
siteInfos.add(siteInfo);
siteService.setMembership(siteName, userName, SiteModel.SITE_COLLABORATOR);
}
return null;
}
}, false, true);
AuthenticationUtil.popAuthentication();
AuthenticationUtil.pushAuthentication();
AuthenticationUtil.setFullyAuthenticatedUser(userName);
final String authority = AuthenticationUtil.getFullyAuthenticatedUser();
final int maxResults = 1; // intentionally less than the authority.zoneAuthoritySampleSize
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
// get sites - size is intentionally less than the authority.zoneAuthoritySampleSize
// this is used by the legacy sites REST api
siteService.listSites(userName, 2);
return null;
}
}, false, true);
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
int numSiteMemberships = 5;
final List<Pair<SiteService.SortFields, Boolean>> sort = new ArrayList<Pair<SiteService.SortFields, Boolean>>();
sort.add(new Pair<SiteService.SortFields, Boolean>(SiteService.SortFields.SiteTitle, Boolean.TRUE));
sort.add(new Pair<SiteService.SortFields, Boolean>(SiteService.SortFields.Role, Boolean.TRUE));
PagingRequest pagingRequest = new PagingRequest(0, numSiteMemberships);
pagingRequest.setRequestTotalCountMax(CannedQueryPageDetails.DEFAULT_PAGE_SIZE);
// this is used by the public api sites REST api
PagingResults<SiteMembership> results = siteService.listSitesPaged(authority, sort, pagingRequest);
List<SiteMembership> siteMemberships = results.getPage();
assertEquals("Unexpected number of site memberships", numSiteMemberships, siteMemberships.size());
return null;
}
}, false, true);
AuthenticationUtil.popAuthentication();
}
finally
{
Pair<String, String> cacheKey = new Pair<String, String>("", AuthorityService.ZONE_APP_SHARE);
zoneToAuthorityCache.remove(cacheKey);
authorityDAO.setZoneAuthoritySampleSize(saveZoneAuthoritySampleSize);
}
}
} }