diff --git a/config/alfresco/cache-context.xml b/config/alfresco/cache-context.xml index 0925328aa2..9f4e8e81b3 100644 --- a/config/alfresco/cache-context.xml +++ b/config/alfresco/cache-context.xml @@ -42,6 +42,7 @@ + diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityBridgeTableAsynchronouslyRefreshedCache.java b/source/java/org/alfresco/repo/security/authority/AuthorityBridgeTableAsynchronouslyRefreshedCache.java index 9862d79575..a19c3b92c1 100644 --- a/source/java/org/alfresco/repo/security/authority/AuthorityBridgeTableAsynchronouslyRefreshedCache.java +++ b/source/java/org/alfresco/repo/security/authority/AuthorityBridgeTableAsynchronouslyRefreshedCache.java @@ -21,6 +21,9 @@ package org.alfresco.repo.security.authority; import java.util.List; import org.alfresco.repo.cache.AbstractAsynchronouslyRefreshedCache; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.tenant.TenantAdminService; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.util.BridgeTable; @@ -35,6 +38,7 @@ public class AuthorityBridgeTableAsynchronouslyRefreshedCache extends AbstractAs { private AuthorityBridgeDAO authorityBridgeDAO; private RetryingTransactionHelper retryingTransactionHelper; + private TenantAdminService tenantAdminService; /** * @param authorityBridgeDAO @@ -54,17 +58,29 @@ public class AuthorityBridgeTableAsynchronouslyRefreshedCache extends AbstractAs this.retryingTransactionHelper = retryingTransactionHelper; } + public void setTenantAdminService(TenantAdminService tenantAdminService) + { + this.tenantAdminService = tenantAdminService; + } + @Override protected BridgeTable buildCache(final String tenantId) { - return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback>() + return AuthenticationUtil.runAs(new RunAsWork>() { - @Override - public BridgeTable execute() throws Throwable + public BridgeTable doWork() throws Exception { - return doBuildCache(tenantId); + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback>() + { + @Override + public BridgeTable execute() throws Throwable + { + return doBuildCache(tenantId); + } + }, true, false); + } - }, true, false); + }, tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantId)); } private BridgeTable doBuildCache(String tenantId) diff --git a/source/test-java/org/alfresco/repo/security/SecurityTestSuite.java b/source/test-java/org/alfresco/repo/security/SecurityTestSuite.java index 826de1e3e9..fb060f0c20 100644 --- a/source/test-java/org/alfresco/repo/security/SecurityTestSuite.java +++ b/source/test-java/org/alfresco/repo/security/SecurityTestSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2011 Alfresco Software Limited. + * Copyright (C) 2005-2013 Alfresco Software Limited. * * This file is part of Alfresco * @@ -28,6 +28,7 @@ import org.alfresco.repo.security.authentication.AuthenticationTest; import org.alfresco.repo.security.authentication.AuthorizationTest; import org.alfresco.repo.security.authentication.ChainingAuthenticationServiceTest; import org.alfresco.repo.security.authentication.NameBasedUserNameGeneratorTest; +import org.alfresco.repo.security.authority.AuthorityBridgeTableAsynchronouslyRefreshedCacheTest; import org.alfresco.repo.security.authority.AuthorityServiceTest; import org.alfresco.repo.security.authority.DuplicateAuthorityTest; import org.alfresco.repo.security.authority.ExtendedPermissionServiceTest; @@ -76,7 +77,8 @@ public class SecurityTestSuite extends TestSuite // suite.addTestSuite(ChainingUserRegistrySynchronizerTest.class); suite.addTestSuite(OwnableServiceTest.class); suite.addTestSuite(ReadPermissionTest.class); - suite.addTestSuite(AuthorizationTest.class); + suite.addTestSuite(AuthorizationTest.class); + suite.addTestSuite(AuthorityBridgeTableAsynchronouslyRefreshedCacheTest.class); suite.addTest(new JUnit4TestAdapter(HomeFolderProviderSynchronizerTest.class)); diff --git a/source/test-java/org/alfresco/repo/security/authority/AuthorityBridgeTableAsynchronouslyRefreshedCacheTest.java b/source/test-java/org/alfresco/repo/security/authority/AuthorityBridgeTableAsynchronouslyRefreshedCacheTest.java new file mode 100644 index 0000000000..6386539a52 --- /dev/null +++ b/source/test-java/org/alfresco/repo/security/authority/AuthorityBridgeTableAsynchronouslyRefreshedCacheTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.security.authority; + +import junit.framework.TestCase; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.tenant.TenantAdminService; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; + +import org.alfresco.util.GUID; +import org.springframework.context.ApplicationContext; + +import java.util.Set; + +public class AuthorityBridgeTableAsynchronouslyRefreshedCacheTest extends TestCase +{ + private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + private AuthorityService authorityService; + private TenantAdminService tenantAdminService; + private TransactionService transactionService; + private PersonService personService; + + private static final String TENANT_DOMAIN = GUID.generate() + ".com"; + private static final String TENANT_ADMIN_USER = AuthenticationUtil.getAdminUserName() + "@" + TENANT_DOMAIN; + + public AuthorityBridgeTableAsynchronouslyRefreshedCacheTest() + { + super(); + } + + @Override + public void setUp() throws Exception + { + transactionService = (TransactionService) ctx.getBean(ServiceRegistry.TRANSACTION_SERVICE.getLocalName()); + authorityService = (AuthorityService) ctx.getBean(ServiceRegistry.AUTHORITY_SERVICE.getLocalName()); + tenantAdminService = ctx.getBean("tenantAdminService", TenantAdminService.class); + personService = (PersonService) ctx.getBean(ServiceRegistry.PERSON_SERVICE.getLocalName()); + } + + @Override + protected void tearDown() + { + + } + + /** + * See MNT-9375 + */ + public void testAuthorityBridgeTableCacheForTenants() throws Exception + { + final String tenantPersonName = GUID.generate() + "@" + TENANT_DOMAIN; + final String childGroupName = "tenantChildGroup" + GUID.generate(); + final String parentGroupName = "tenantParentGroup" + GUID.generate(); + + createTenant(TENANT_DOMAIN); + + // Create a group and place a user in it + AuthenticationUtil.setFullyAuthenticatedUser(TENANT_ADMIN_USER); + final String tenantChildGroup = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public String execute() throws Throwable + { + personService.getPerson(tenantPersonName, true); + assertTrue(personService.personExists(tenantPersonName)); + String tenantChildGroup = authorityService.createAuthority(AuthorityType.GROUP, childGroupName); + assertNotNull(authorityService.getAuthorityNodeRef(tenantChildGroup)); + authorityService.addAuthority(tenantChildGroup, tenantPersonName); + return tenantChildGroup; + } + }, false, true); + + // Create another group and place in it an existing group with a user + // The transaction is required, because the AuthorityBridgeTableAsynchronouslyRefreshedCache is cleared in the end of transaction asynchronously using FutureTask. + final String tenantParentGroup = transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public String execute() throws Throwable + { + String tenantParentGroup = authorityService.createAuthority(AuthorityType.GROUP, parentGroupName); + assertNotNull(authorityService.getAuthorityNodeRef(tenantParentGroup)); + authorityService.addAuthority(tenantParentGroup, tenantChildGroup); + + return tenantParentGroup; + } + }, false, true); + + Set authorities = authorityService.getContainingAuthorities(null, tenantPersonName, false); + assertEquals(2, authorities.size()); + assertTrue(authorities.contains(tenantParentGroup)); + assertTrue(authorities.contains(tenantChildGroup)); + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + } + + private void createTenant(final String tenantDomain) + { + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + if (!tenantAdminService.existsTenant(tenantDomain)) + { + tenantAdminService.createTenant(tenantDomain, "password".toCharArray()); + } + return null; + } + }, false, true); + } +}