From 25632c2a96a6ddfa03ec8eeefe18d7563f38ee20 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Mon, 6 Jun 2011 18:31:52 +0000 Subject: [PATCH] Merged DEV/SWIFT to HEAD 25960: RepoBM: improve configurability - add option to configure base folder path - enable params (base urls, threads, base folder path, ...) to be configured via ant build.properties 25961: Merged BRANCHES/DEV/BM to BRANCHES/DEV/SWIFT: 24568: WebDAV - use fileInfo props (instead of nodeRef + getProp(s)) - resolve conflict 24727: SPP/WebDAV - compile fix (follow-on to r24568) 24855: BM - WebDAV - fix litmus -> locks -> 7. discover FAIL (fallout from r24568) + ran litmus 0.12.1 25963: Merged BRANCHES/DEV/BM to BRANCHES/DEV/SWIFT: 24784: Log stack trace when reporting exception 25966: Merged BRANCHES/DEV/BM to BRANCHES/DEV/SWIFT: 24725: BM - tweak validate (to use read-only txn) 25968: Merged BRANCHES/DEV/BM to BRANCHES/DEV/SWIFT: 24736: BM - getChildByName optimisation (add reverse-lookup for parentAssocs) 25992: RepoBM: add TPS - extend default ant-jmeter report to show approx/rounded test Time & TPS (note: not done for detailed report) - comment out detailed report - also expose "duration" param in ant build.xml / build.properties 26035: RepoBM: ALF-6796 - fix perf of report generation (switch from xalan to saxon) - also do not fail on error 26042: RepoBM: update readme (for ALF-6796) + add zip target 26045: (RECORD ONLY) Merged DEV/BM to DEV/SWIFT (RECORD ONLY) - already resolved for V3.4 & SWIFT Merged BRANCHES/V3.4 to BRANCHES/DEV/BM: 23613: Merged BRANCHES/DEV/BELARUS/HEAD_2010_10_21 to BRANCHES/V3.4: 23601: ALF-5447: It's impossible to save the MS Office 2010 document via webdav. Merged BRANCHES/V3.4 to BRANCHES/DEV/BM: 23618: Merged BRANCHES/DEV/V3.3-BUG-FIX to BRANCHES/V3.4: 23617: Merged BRANCHES/DEV/BELARUS/V3.3-2010_11_10 to BRANCHES/DEV/V3.3-BUG-FIX: 23602: ALF-5517: Webdav "supportedlock" propfind request fails if locking enabled Merged BRANCHES/V3.4 to BRANCHES/DEV/BM: 23997: Fix ALF-5731: Saving a doc from Office 2003 via WebDAV fails 26049: RepoBM: add "folder create" unit test - ALF-7309 (WebDAV) - ALF-7310 (CMIS) 26147: RepoBM: update WebDAV test - add patched sardine (thanks Florian) - adds "getResources(String url, int depth, boolean allProps)" 26219: RepoBM: test additions & improvements - add "itemRename" (document or folder) - for CMIS (ALF-7362) and WebDAV (ALF-7630) - update mixed scenario (add "folderCreate" & "itemRename") - for CMIS (ALF-7546) and WebDAV (ALF-7545) - cleanup of common code 26269: RepoBM: fix mixed scenarios (# of threads & weighted distribution) - use single thread group and interleave controllers - for CMIS (ALF-7546) and WebDAV (ALF-7545) 26271: (RECORD ONLY) Merged BRANCHES/DEV/BM to BRANCHES/DEV/SWIFT (RECORD-ONLY) - NOTE: verified w/ florian - NOTE: OpenCMIS and cmis-client-api are already on SWIFT - NOTE: cmis-bm has been superceded by repository-bm 26273: (RECORD ONLY) Merged BRANCHES/DEV/BM to BRANCHES/DEV/SWIFT (RECORD-ONLY) 24326: OpenCMIS update 26395: ALF-7755: add "system-build-test" project (and related RepoBM updates) - add ability to run "remote" tests (ie. selected *SystemTest) against embedded Jetty - initially run sanity builds test for RepoBM (RepositoryBenchmarkWebDAVSystemTest + RepositoryBenchmarkCMISSystemTest) & also SiteActivitySystemTest - RepoBM enhanced to import test data if not present (also added additional testItemDelete unit test) - using local copy of Spring 3.0.5 (requires at least 3.0.2) - can be rationalised once rest of Alfresco (ie. 3rd-party libs) moves up to a higher Spring version 26420: ALF-7755: tweak "system-build-test" for build box - also includes minor fixes to RepoBM (+ readme) 26448: ALF-7755: tweak "system-build-test" - for ant scripts (eg. running on build box) 26457: ALF-7898 - Alfresco Web Services: fix-up broken/regressed tests (WebServiceSuiteSystemTest) - revert default url context ... from "contentspaces" -> "alfresco" (broken during merge from ADB LC branch) - fix AuthoringServiceSystemTest.testVersionMethods() - when deleting version history - fix RepositoryServiceSystemTest.testPropertySetGet() - when creating dynamic model 26462: ALF-7898 / ALF-7755: add additional 'system' tests - effectively runs Alf Web Service build sanity tests (~= WebServiceSuiteSystemTest) 26478: ALF-7898 / ALF-7755: additional classpath fiddling (to get around limitation on Windows) - see also r26093 26487: Build fix: cut-and-paste formatting issue 26502: RepoBM: add "itemUpdate" (update props for doc or folder) - for CMIS (ALF-7633) - use Alfresco OpenCMIS Extension to update aspect props - for WebDAV (ALF-7631) - patch Sardine to allow custom namespaces 26526: ALF-7755: use temp classpaths 26528: ALF-7755: comment out for now - seems to work locally and on build boxes when run separately, but fails during full build - pending further investigation and testing (eg. when bamboo agents become free) 26567: ALF-7755: remove test-repository-bm since not used - was breaking the test classpath (for following tests) 26571: ALF-7755: re-enable RepoBenchmarkSystemTestSuite 26600: ALF-7755: test-system-build-test - add user.home (for build box env) - re-enable MiscSystemTestSuite (includes Alf WS* tests) 26609: ALF-7755: fix build/test (RepositoryServiceSystemTest.testPropertySetGet) - due to earlier MT test git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28217 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/public-services-context.xml | 1 + .../repo/dictionary/DictionaryModelType.java | 14 +- .../repo/domain/node/AbstractNodeDAOImpl.java | 60 +- .../repo/domain/node/ChildByNameKey.java | 100 ++ .../AbstractAuthenticationComponent.java | 886 +++++++++--------- .../alfresco/repo/tenant/MultiTDemoTest.java | 303 +++--- .../repo/version/Version2ServiceImpl.java | 63 +- 7 files changed, 833 insertions(+), 594 deletions(-) create mode 100644 source/java/org/alfresco/repo/domain/node/ChildByNameKey.java diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml index 73f7b5cfe2..062aa7a905 100644 --- a/config/alfresco/public-services-context.xml +++ b/config/alfresco/public-services-context.xml @@ -633,6 +633,7 @@ PROPAGATION_NOT_SUPPORTED, readOnly PROPAGATION_NOT_SUPPORTED, readOnly PROPAGATION_NOT_SUPPORTED, readOnly + PROPAGATION_NOT_SUPPORTED, readOnly PROPAGATION_NOT_SUPPORTED, readOnly PROPAGATION_NOT_SUPPORTED, readOnly PROPAGATION_NOT_SUPPORTED, readOnly diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java b/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java index 449559371c..93d0e84d20 100644 --- a/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java +++ b/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java @@ -65,6 +65,7 @@ import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition; +import org.alfresco.service.namespace.NamespaceException; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; @@ -806,7 +807,18 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda for (WorkflowDefinition workflowDef : workflowDefs) { String workflowDefName = workflowDef.getName(); - String workflowNamespaceURI = QName.createQName(BPMEngineRegistry.getLocalId(workflowDefName), namespaceService).getNamespaceURI(); + + String workflowNamespaceURI = null; + try + { + workflowNamespaceURI = QName.createQName(BPMEngineRegistry.getLocalId(workflowDefName), namespaceService).getNamespaceURI(); + } + catch (NamespaceException ne) + { + logger.warn("Skipped workflow when validating model delete - unknown namespace: "+ne); + continue; + } + for (NamespaceDefinition namespaceDef : namespaceDefs) { if (workflowNamespaceURI.equals(namespaceDef.getUri())) diff --git a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java index 7dcdd8163a..7d512d1d99 100644 --- a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java @@ -165,9 +165,9 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO * Cache for the Node parent assocs:
* KEY: ID
* VALUE: ParentAssocs
- * VALUE KEY: None
+ * VALUE KEY: ChildByNameKey
*/ - private EntityLookupCache parentAssocsCache; + private EntityLookupCache parentAssocsCache; /** * Constructor. Set up various instance-specific members such as caches and locks. @@ -182,7 +182,7 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO nodesCache = new EntityLookupCache(new NodesCacheCallbackDAO()); aspectsCache = new EntityLookupCache, Serializable>(new AspectsCallbackDAO()); propertiesCache = new EntityLookupCache, Serializable>(new PropertiesCallbackDAO()); - parentAssocsCache = new EntityLookupCache(new ParentAssocsCallbackDAO()); + parentAssocsCache = new EntityLookupCache(new ParentAssocsCallbackDAO()); } /** @@ -338,7 +338,7 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO */ public void setParentAssocsCache(SimpleCache parentAssocsCache) { - this.parentAssocsCache = new EntityLookupCache( + this.parentAssocsCache = new EntityLookupCache( parentAssocsCache, CACHE_REGION_PARENT_ASSOCS, new ParentAssocsCallbackDAO()); @@ -2733,7 +2733,37 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO public Pair getChildAssoc(Long parentNodeId, QName assocTypeQName, String childName) { + ChildByNameKey valueKey = new ChildByNameKey(parentNodeId, assocTypeQName, childName); + + // cache-only operation: try reverse lookup on parentAssocs (note: for primary assoc only) + Long childNodeId = parentAssocsCache.getKey(valueKey); + if (childNodeId != null) + { + Pair value = parentAssocsCache.getByKey(childNodeId); + if (value != null) + { + ChildAssocEntity assoc = value.getSecond().getPrimaryParentAssoc(); + if (assoc == null) + { + return null; + } + + Pair result = assoc.getPair(qnameDAO); + if (result.getSecond().getTypeQName().equals(assocTypeQName)) + { + return result; + } + } + } + + // TODO could refactor as single select to get parent assocs by child name ChildAssocEntity assoc = selectChildAssoc(parentNodeId, assocTypeQName, childName); + if (assoc != null) + { + // additional lookup to populate cache - note: also pulls in 2ndary assocs + parentAssocsCache.getByKey(assoc.getChildNode().getId()); + } + return assoc == null ? null : assoc.getPair(qnameDAO); } @@ -3072,13 +3102,13 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO * @author Derek Hulley * @since 3.4 */ - private class ParentAssocsCallbackDAO extends EntityLookupCallbackDAOAdaptor + private class ParentAssocsCallbackDAO extends EntityLookupCallbackDAOAdaptor { public Pair createValue(ParentAssocsInfo value) { throw new UnsupportedOperationException("Nodes are created independently."); } - + public Pair findByKey(Long nodeId) { // Find out if it is a root or store root @@ -3093,6 +3123,24 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO // Done return new Pair(nodeId, value); } + + @Override + public ChildByNameKey getValueKey(ParentAssocsInfo value) + { + ChildAssocEntity entity = value.getPrimaryParentAssoc(); + + if (entity != null) + { + return new ChildByNameKey(entity.getParentNode().getId(), qnameDAO.getQName(entity.getTypeQNameId()).getSecond(), entity.getChildNodeName()); + } + + return null; + } + + public Pair findByValue(ParentAssocsInfo value) + { + return findByKey(value.getPrimaryParentAssoc().getChildNode().getId()); + } } /* diff --git a/source/java/org/alfresco/repo/domain/node/ChildByNameKey.java b/source/java/org/alfresco/repo/domain/node/ChildByNameKey.java new file mode 100644 index 0000000000..8036eecd12 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/ChildByNameKey.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.io.Serializable; + +import org.alfresco.service.namespace.QName; + +/** + * @author janv + * @since 4.0 + */ +/* package */ class ChildByNameKey implements Serializable +{ + private static final long serialVersionUID = -2167221525380802365L; + + private final Long parentNodeId; + private QName assocTypeQName; + private String childNodeName; + + ChildByNameKey(Long parentNodeId, QName assocTypeQName, String childNodeName) + { + this.parentNodeId = parentNodeId; + this.assocTypeQName = assocTypeQName; + this.childNodeName = childNodeName; + } + + public Long getParentNodeId() + { + return parentNodeId; + } + + public QName getAssocTypeQName() + { + return assocTypeQName; + } + + public String getChildNodeName() + { + return childNodeName; + } + + + @Override + public boolean equals(Object other) + { + if (this == other) + { + return true; + } + if (!(other instanceof ChildByNameKey)) + { + return false; + } + ChildByNameKey o = (ChildByNameKey)other; + return parentNodeId.equals(o.getParentNodeId()) && + assocTypeQName.equals(o.getAssocTypeQName()) && + childNodeName.equalsIgnoreCase(o.getChildNodeName()); + } + + @Override + public int hashCode() + { + return parentNodeId.hashCode() + assocTypeQName.hashCode() + childNodeName.toLowerCase().hashCode(); + } + + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(); + builder.append("ChildByNameInfo ") + .append("[parentNodeId=").append(parentNodeId) + .append(", assocTypeQName=").append(assocTypeQName) + .append(", childNodeName=").append(childNodeName) + .append("]"); + return builder.toString(); + } +} diff --git a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java index 33c1415698..583e174c4e 100644 --- a/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java +++ b/source/java/org/alfresco/repo/security/authentication/AbstractAuthenticationComponent.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,114 +14,114 @@ * 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.authentication; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Set; -import java.util.TreeSet; - -import net.sf.acegisecurity.Authentication; -import net.sf.acegisecurity.GrantedAuthority; -import net.sf.acegisecurity.GrantedAuthorityImpl; -import net.sf.acegisecurity.UserDetails; -import net.sf.acegisecurity.providers.dao.User; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; -import org.alfresco.repo.security.sync.UserRegistrySynchronizer; -import org.alfresco.repo.tenant.TenantService; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.transaction.TransactionService; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This class abstract the support required to set up and query the Acegi context for security enforcement. There are - * some simple default method implementations to support simple authentication. - * - * @author Andy Hind - */ -public abstract class AbstractAuthenticationComponent implements AuthenticationComponent -{ - /** - * The abstract class keeps track of support for guest login - */ - private Boolean allowGuestLogin = null; - - private Set defaultAdministratorUserNames = Collections.emptySet(); - - private Set defaultGuestUserNames = Collections.emptySet(); - - private AuthenticationContext authenticationContext; - - private PersonService personService; - - private NodeService nodeService; - - private TransactionService transactionService; - - private UserRegistrySynchronizer userRegistrySynchronizer; - - private final Log logger = LogFactory.getLog(getClass()); - - public AbstractAuthenticationComponent() - { - super(); - } - - /** - * Set if guest login is supported. - * - * @param allowGuestLogin - */ - public void setAllowGuestLogin(Boolean allowGuestLogin) - { - this.allowGuestLogin = allowGuestLogin; - } - - public void setAuthenticationContext(AuthenticationContext authenticationContext) - { - this.authenticationContext = authenticationContext; - } - - public void setPersonService(PersonService personService) - { - this.personService = personService; - } - - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - - public void setUserRegistrySynchronizer(UserRegistrySynchronizer userRegistrySynchronizer) - { - this.userRegistrySynchronizer = userRegistrySynchronizer; - } - - public TransactionService getTransactionService() - { - return transactionService; - } - - public Boolean getAllowGuestLogin() - { - return allowGuestLogin; - } - + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.security.authentication; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; + +import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.GrantedAuthority; +import net.sf.acegisecurity.GrantedAuthorityImpl; +import net.sf.acegisecurity.UserDetails; +import net.sf.acegisecurity.providers.dao.User; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.security.sync.UserRegistrySynchronizer; +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.transaction.TransactionService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This class abstract the support required to set up and query the Acegi context for security enforcement. There are + * some simple default method implementations to support simple authentication. + * + * @author Andy Hind + */ +public abstract class AbstractAuthenticationComponent implements AuthenticationComponent +{ + /** + * The abstract class keeps track of support for guest login + */ + private Boolean allowGuestLogin = null; + + private Set defaultAdministratorUserNames = Collections.emptySet(); + + private Set defaultGuestUserNames = Collections.emptySet(); + + private AuthenticationContext authenticationContext; + + private PersonService personService; + + private NodeService nodeService; + + private TransactionService transactionService; + + private UserRegistrySynchronizer userRegistrySynchronizer; + + private final Log logger = LogFactory.getLog(getClass()); + + public AbstractAuthenticationComponent() + { + super(); + } + + /** + * Set if guest login is supported. + * + * @param allowGuestLogin + */ + public void setAllowGuestLogin(Boolean allowGuestLogin) + { + this.allowGuestLogin = allowGuestLogin; + } + + public void setAuthenticationContext(AuthenticationContext authenticationContext) + { + this.authenticationContext = authenticationContext; + } + + public void setPersonService(PersonService personService) + { + this.personService = personService; + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } + + public void setUserRegistrySynchronizer(UserRegistrySynchronizer userRegistrySynchronizer) + { + this.userRegistrySynchronizer = userRegistrySynchronizer; + } + + public TransactionService getTransactionService() + { + return transactionService; + } + + public Boolean getAllowGuestLogin() + { + return allowGuestLogin; + } + public NodeService getNodeService() { return nodeService; @@ -131,67 +131,67 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC { return personService; } - - public void authenticate(String userName, char[] password) throws AuthenticationException - { - if (logger.isDebugEnabled()) - { - logger.debug("Authenticating user \"" + userName + '"'); - } + + public void authenticate(String userName, char[] password) throws AuthenticationException + { + if (logger.isDebugEnabled()) + { + logger.debug("Authenticating user \"" + userName + '"'); + } if (userName == null) { throw new AuthenticationException("Null user name"); } - // Support guest login from the login screen - if (isGuestUserName(userName)) - { - if (logger.isDebugEnabled()) - { - logger.debug("User \"" + userName + "\" recognized as a guest user"); - } - setGuestUserAsCurrentUser(getUserDomain(userName)); - } - else - { - try - { - authenticateImpl(userName, password); - } - catch (RuntimeException e) - { - if (logger.isDebugEnabled()) - { - logger.debug("Failed to authenticate user \"" + userName + '"', e); - } - throw e; - } - } - if (logger.isDebugEnabled()) - { - logger.debug("User \"" + userName + "\" authenticated successfully"); - } - } - - /** - * Default unsupported authentication implementation - as of 2.1 this is the best way to implement your own - * authentication component as it will support guest login - prior to this direct over ride for authenticate(String , - * char[]) was used. This will still work. - * - * @param userName - * @param password - */ - protected void authenticateImpl(String userName, char[] password) - { - throw new UnsupportedOperationException(); - } - + // Support guest login from the login screen + if (isGuestUserName(userName)) + { + if (logger.isDebugEnabled()) + { + logger.debug("User \"" + userName + "\" recognized as a guest user"); + } + setGuestUserAsCurrentUser(getUserDomain(userName)); + } + else + { + try + { + authenticateImpl(userName, password); + } + catch (RuntimeException e) + { + if (logger.isDebugEnabled()) + { + logger.debug("Failed to authenticate user \"" + userName + '"', e); + } + throw e; + } + } + if (logger.isDebugEnabled()) + { + logger.debug("User \"" + userName + "\" authenticated successfully"); + } + } + + /** + * Default unsupported authentication implementation - as of 2.1 this is the best way to implement your own + * authentication component as it will support guest login - prior to this direct over ride for authenticate(String , + * char[]) was used. This will still work. + * + * @param userName + * @param password + */ + protected void authenticateImpl(String userName, char[] password) + { + throw new UnsupportedOperationException(); + } + public Authentication setCurrentUser(final String userName) throws AuthenticationException - { + { return setCurrentUser(userName, UserNameValidationMode.CHECK_AND_FIX); - } - + } + public Authentication setCurrentUser(String userName, UserNameValidationMode validationMode) - { + { if (validationMode == UserNameValidationMode.NONE || isSystemUserName(userName)) { return setCurrentUserImpl(userName); @@ -209,12 +209,16 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC authentication = transactionService.getRetryingTransactionHelper().doInTransaction(callback, true, false); } - // Otherwise, we want a writeable transaction, so if the current transaction is read only we set the + // Otherwise, + // - for check-only mode we want a readable txn or + // - for check-and-fix mode we want a writeable transaction, so if the current transaction is read only we set the // requiresNew flag to true else { - authentication = transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, - AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY); + boolean readOnly = (validationMode == UserNameValidationMode.CHECK); + boolean requiresNew = ((!readOnly) && (AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY)); + + authentication = transactionService.getRetryingTransactionHelper().doInTransaction(callback, readOnly, requiresNew); } if ((authentication == null) || (callback.ae != null)) { @@ -239,30 +243,30 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC throw new AuthenticationException("Null user name"); } - if (isSystemUserName(userName)) - { - return setSystemUserAsCurrentUser(getUserDomain(userName)); - } - + if (isSystemUserName(userName)) + { + return setSystemUserAsCurrentUser(getUserDomain(userName)); + } + try { UserDetails ud = null; if (isGuestUserName(userName)) { String tenantDomain = getUserDomain(userName); - if (logger.isDebugEnabled()) - { - logger.debug("Setting the current user to the guest user of tenant domain \"" + tenantDomain + '"'); - } + if (logger.isDebugEnabled()) + { + logger.debug("Setting the current user to the guest user of tenant domain \"" + tenantDomain + '"'); + } GrantedAuthority[] gas = new GrantedAuthority[0]; ud = new User(getGuestUserName(tenantDomain), "", true, true, true, true, gas); } else { - if (logger.isDebugEnabled()) - { - logger.debug("Setting the current user to \"" + userName + '"'); - } + if (logger.isDebugEnabled()) + { + logger.debug("Setting the current user to \"" + userName + '"'); + } ud = getUserDetails(userName); if(!userName.equals(ud.getUsername())) { @@ -291,163 +295,163 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC gas[0] = new GrantedAuthorityImpl("ROLE_AUTHENTICATED"); UserDetails ud = new User(userName, "", true, true, true, true, gas); return ud; - } - - /** - * {@inheritDoc} - */ - public Authentication setCurrentAuthentication(Authentication authentication) - { - return this.authenticationContext.setCurrentAuthentication(authentication); - } - - /** - * Get the current authentication context - * - * @return Authentication - * @throws AuthenticationException - */ - public Authentication getCurrentAuthentication() throws AuthenticationException - { - return authenticationContext.getCurrentAuthentication(); - } - - /** - * Get the current user name. - * - * @return String - * @throws AuthenticationException - */ - public String getCurrentUserName() throws AuthenticationException - { - return authenticationContext.getCurrentUserName(); - } - - /** - * Set the system user as the current user note: for MT, will set to default domain only - * - * @return Authentication - */ - public Authentication setSystemUserAsCurrentUser() - { - return authenticationContext.setSystemUserAsCurrentUser(); - } - - /** - * Get the name of the system user note: for MT, will get system for default domain only - * - * @return String - */ - public String getSystemUserName() - { - return authenticationContext.getSystemUserName(); - } - - /** - * Is this the system user ? - * - * @return boolean - */ - public boolean isSystemUserName(String userName) - { - return authenticationContext.isSystemUserName(userName); - } - - /** - * Is the current user the system user? - * - * @return boolean - */ - public boolean isCurrentUserTheSystemUser() - { - return authenticationContext.isCurrentUserTheSystemUser(); - } - - /** - * Get the name of the Guest User note: for MT, will get guest for default domain only - * - * @return String - */ - public String getGuestUserName() - { - return authenticationContext.getGuestUserName(); - } - - public String getGuestUserName(String tenantDomain) - { - return authenticationContext.getGuestUserName(tenantDomain); - } - - /** - * Set the guest user as the current user. note: for MT, will set to default domain only - */ - public Authentication setGuestUserAsCurrentUser() throws AuthenticationException - { - return setGuestUserAsCurrentUser(TenantService.DEFAULT_DOMAIN); - } - - /** - * Set the guest user as the current user. - */ - private Authentication setGuestUserAsCurrentUser(String tenantDomain) throws AuthenticationException - { - if (allowGuestLogin == null) - { - if (implementationAllowsGuestLogin()) - { - return setCurrentUser(getGuestUserName(tenantDomain)); - } - else - { - throw new AuthenticationException("Guest authentication is not allowed"); - } - } - else - { - if (allowGuestLogin.booleanValue()) - { - return setCurrentUser(getGuestUserName(tenantDomain)); - } - else -{ - throw new AuthenticationException("Guest authentication is not allowed"); - } - - } - } - - public boolean isGuestUserName(String userName) - { - return authenticationContext.isGuestUserName(userName); - } - - - protected abstract boolean implementationAllowsGuestLogin(); - - - /** - * @return true if Guest user authentication is allowed, false otherwise - */ - public boolean guestUserAuthenticationAllowed() - { - if (allowGuestLogin == null) - { - return (implementationAllowsGuestLogin()); - } - else - { - return (allowGuestLogin.booleanValue()); - } - } - - /** - * Remove the current security information - */ - public void clearCurrentSecurityContext() - { - authenticationContext.clearCurrentSecurityContext(); - } - + } + + /** + * {@inheritDoc} + */ + public Authentication setCurrentAuthentication(Authentication authentication) + { + return this.authenticationContext.setCurrentAuthentication(authentication); + } + + /** + * Get the current authentication context + * + * @return Authentication + * @throws AuthenticationException + */ + public Authentication getCurrentAuthentication() throws AuthenticationException + { + return authenticationContext.getCurrentAuthentication(); + } + + /** + * Get the current user name. + * + * @return String + * @throws AuthenticationException + */ + public String getCurrentUserName() throws AuthenticationException + { + return authenticationContext.getCurrentUserName(); + } + + /** + * Set the system user as the current user note: for MT, will set to default domain only + * + * @return Authentication + */ + public Authentication setSystemUserAsCurrentUser() + { + return authenticationContext.setSystemUserAsCurrentUser(); + } + + /** + * Get the name of the system user note: for MT, will get system for default domain only + * + * @return String + */ + public String getSystemUserName() + { + return authenticationContext.getSystemUserName(); + } + + /** + * Is this the system user ? + * + * @return boolean + */ + public boolean isSystemUserName(String userName) + { + return authenticationContext.isSystemUserName(userName); + } + + /** + * Is the current user the system user? + * + * @return boolean + */ + public boolean isCurrentUserTheSystemUser() + { + return authenticationContext.isCurrentUserTheSystemUser(); + } + + /** + * Get the name of the Guest User note: for MT, will get guest for default domain only + * + * @return String + */ + public String getGuestUserName() + { + return authenticationContext.getGuestUserName(); + } + + public String getGuestUserName(String tenantDomain) + { + return authenticationContext.getGuestUserName(tenantDomain); + } + + /** + * Set the guest user as the current user. note: for MT, will set to default domain only + */ + public Authentication setGuestUserAsCurrentUser() throws AuthenticationException + { + return setGuestUserAsCurrentUser(TenantService.DEFAULT_DOMAIN); + } + + /** + * Set the guest user as the current user. + */ + private Authentication setGuestUserAsCurrentUser(String tenantDomain) throws AuthenticationException + { + if (allowGuestLogin == null) + { + if (implementationAllowsGuestLogin()) + { + return setCurrentUser(getGuestUserName(tenantDomain)); + } + else + { + throw new AuthenticationException("Guest authentication is not allowed"); + } + } + else + { + if (allowGuestLogin.booleanValue()) + { + return setCurrentUser(getGuestUserName(tenantDomain)); + } + else +{ + throw new AuthenticationException("Guest authentication is not allowed"); + } + + } + } + + public boolean isGuestUserName(String userName) + { + return authenticationContext.isGuestUserName(userName); + } + + + protected abstract boolean implementationAllowsGuestLogin(); + + + /** + * @return true if Guest user authentication is allowed, false otherwise + */ + public boolean guestUserAuthenticationAllowed() + { + if (allowGuestLogin == null) + { + return (implementationAllowsGuestLogin()); + } + else + { + return (allowGuestLogin.booleanValue()); + } + } + + /** + * Remove the current security information + */ + public void clearCurrentSecurityContext() + { + authenticationContext.clearCurrentSecurityContext(); + } + abstract class CurrentUserCallback implements RetryingTransactionHelper.RetryingTransactionCallback { AuthenticationException ae = null; @@ -517,7 +521,7 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC { public String doWork() throws Exception { - if (!personService.personExists(userName)) + if (!personService.personExists(userName)) { if (logger.isDebugEnabled()) { @@ -525,19 +529,19 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC + "\" does not exist in Alfresco. Attempting to import / create the user."); } if (!userRegistrySynchronizer.createMissingPerson(userName)) - { - if (logger.isDebugEnabled()) - { + { + if (logger.isDebugEnabled()) + { logger.debug("Failed to import / create user \"" + userName + '"'); - } - throw new AuthenticationException("User \"" + userName - + "\" does not exist in Alfresco"); - } - } - NodeRef userNode = personService.getPerson(userName); - // Get the person name and use that as the current user to line up with permission - // checks - return (String) nodeService.getProperty(userNode, ContentModel.PROP_USERNAME); + } + throw new AuthenticationException("User \"" + userName + + "\" does not exist in Alfresco"); + } + } + NodeRef userNode = personService.getPerson(userName); + // Get the person name and use that as the current user to line up with permission + // checks + return (String) nodeService.getProperty(userNode, ContentModel.PROP_USERNAME); } }, getSystemUserName(getUserDomain(userName)))); } @@ -549,95 +553,95 @@ public abstract class AbstractAuthenticationComponent implements AuthenticationC } } - /** - * {@inheritDoc} - */ - public Set getDefaultAdministratorUserNames() - { - return this.defaultAdministratorUserNames; - } - - /** - * Sets the user names who for this particular authentication system should be considered administrators by default. - * - * @param defaultAdministratorUserNames - * a set of user names - */ - public void setDefaultAdministratorUserNames(Set defaultAdministratorUserNames) - { - this.defaultAdministratorUserNames = defaultAdministratorUserNames; - } - - /** - * Convenience method to allow the administrator user names to be specified as a comma separated list - * - * @param defaultAdministratorUserNames - */ - public void setDefaultAdministratorUserNameList(String defaultAdministratorUserNames) - { - Set nameSet = new TreeSet(); - if (defaultAdministratorUserNames.length() > 0) - { - nameSet.addAll(Arrays.asList(defaultAdministratorUserNames.split(","))); - } - setDefaultAdministratorUserNames(nameSet); - } - - /** - * {@inheritDoc} - */ - public Set getDefaultGuestUserNames() - { - return this.defaultGuestUserNames; - } - - /** - * Sets the user names who for this particular authentication system should be considered administrators by default. - * - * @param defaultAdministratorUserNames - * a set of user names - */ - public void setDefaultGuestUserNames(Set defaultGuestUserNames) - { - this.defaultGuestUserNames = defaultGuestUserNames; - } - - /** - * Convenience method to allow the administrator user names to be specified as a comma separated list - * - * @param defaultAdministratorUserNames - */ - public void setDefaultGuestUserNameList(String defaultGuestUserNames) - { - Set nameSet = new TreeSet(); - if (defaultGuestUserNames.length() > 0) - { - nameSet.addAll(Arrays.asList(defaultGuestUserNames.split(","))); - } - setDefaultGuestUserNames(nameSet); - } - - public String getSystemUserName(String tenantDomain) - { - return authenticationContext.getSystemUserName(tenantDomain); - } - - public String getUserDomain(String userName) - { - return authenticationContext.getUserDomain(userName); - } - - public Authentication setSystemUserAsCurrentUser(String tenantDomain) - { - if (logger.isDebugEnabled()) - { - logger.debug("Setting the current user to the system user of tenant domain \"" + tenantDomain + '"'); - } - return authenticationContext.setSystemUserAsCurrentUser(tenantDomain); - } - - public Authentication setUserDetails(UserDetails ud) - { - return authenticationContext.setUserDetails(ud); - } -} + /** + * {@inheritDoc} + */ + public Set getDefaultAdministratorUserNames() + { + return this.defaultAdministratorUserNames; + } + + /** + * Sets the user names who for this particular authentication system should be considered administrators by default. + * + * @param defaultAdministratorUserNames + * a set of user names + */ + public void setDefaultAdministratorUserNames(Set defaultAdministratorUserNames) + { + this.defaultAdministratorUserNames = defaultAdministratorUserNames; + } + + /** + * Convenience method to allow the administrator user names to be specified as a comma separated list + * + * @param defaultAdministratorUserNames + */ + public void setDefaultAdministratorUserNameList(String defaultAdministratorUserNames) + { + Set nameSet = new TreeSet(); + if (defaultAdministratorUserNames.length() > 0) + { + nameSet.addAll(Arrays.asList(defaultAdministratorUserNames.split(","))); + } + setDefaultAdministratorUserNames(nameSet); + } + + /** + * {@inheritDoc} + */ + public Set getDefaultGuestUserNames() + { + return this.defaultGuestUserNames; + } + + /** + * Sets the user names who for this particular authentication system should be considered administrators by default. + * + * @param defaultAdministratorUserNames + * a set of user names + */ + public void setDefaultGuestUserNames(Set defaultGuestUserNames) + { + this.defaultGuestUserNames = defaultGuestUserNames; + } + + /** + * Convenience method to allow the administrator user names to be specified as a comma separated list + * + * @param defaultAdministratorUserNames + */ + public void setDefaultGuestUserNameList(String defaultGuestUserNames) + { + Set nameSet = new TreeSet(); + if (defaultGuestUserNames.length() > 0) + { + nameSet.addAll(Arrays.asList(defaultGuestUserNames.split(","))); + } + setDefaultGuestUserNames(nameSet); + } + + public String getSystemUserName(String tenantDomain) + { + return authenticationContext.getSystemUserName(tenantDomain); + } + + public String getUserDomain(String userName) + { + return authenticationContext.getUserDomain(userName); + } + + public Authentication setSystemUserAsCurrentUser(String tenantDomain) + { + if (logger.isDebugEnabled()) + { + logger.debug("Setting the current user to the system user of tenant domain \"" + tenantDomain + '"'); + } + return authenticationContext.setSystemUserAsCurrentUser(tenantDomain); + } + + public Authentication setUserDetails(UserDetails ud) + { + return authenticationContext.setUserDetails(ud); + } +} diff --git a/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java b/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java index 4ed45a305c..171513a5e2 100644 --- a/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java +++ b/source/java/org/alfresco/repo/tenant/MultiTDemoTest.java @@ -38,6 +38,7 @@ import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.permissions.impl.AccessPermissionImpl; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.admin.RepoAdminService; import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.dictionary.ClassDefinition; @@ -63,6 +64,7 @@ import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.usage.UsageService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -92,6 +94,7 @@ public class MultiTDemoTest extends TestCase private RepoAdminService repoAdminService; private DictionaryService dictionaryService; private UsageService usageService; + private TransactionService transactionService; public static int NUM_TENANTS = 2; @@ -152,6 +155,7 @@ public class MultiTDemoTest extends TestCase repoAdminService = (RepoAdminService) ctx.getBean("RepoAdminService"); dictionaryService = (DictionaryService) ctx.getBean("DictionaryService"); usageService = (UsageService) ctx.getBean("usageService"); + transactionService = (TransactionService) ctx.getBean("TransactionService"); createTenants(); } @@ -270,58 +274,66 @@ public class MultiTDemoTest extends TestCase final String tenantDomain1 = TEST_RUN+".groupdel1"; final String tenantDomain2 = TEST_RUN+".groupdel2"; - final String[] tenantUniqueGroupNames = new String[10]; - final String[] superadminUniqueGroupNames = new String[10]; - for (int i = 0; i < tenantUniqueGroupNames.length; i++) + try { - tenantUniqueGroupNames[i] = TEST_RUN + "test_group" + i; - superadminUniqueGroupNames[i] = TEST_RUN + "test_group_sa" + i; + final String[] tenantUniqueGroupNames = new String[10]; + final String[] superadminUniqueGroupNames = new String[10]; + for (int i = 0; i < tenantUniqueGroupNames.length; i++) + { + tenantUniqueGroupNames[i] = TEST_RUN + "test_group" + i; + superadminUniqueGroupNames[i] = TEST_RUN + "test_group_sa" + i; + } + + clearUsage(AuthenticationUtil.getAdminUserName()); + + createTenant(tenantDomain1); + createTenant(tenantDomain2); + + final String tenantAdminName1 = tenantService.getDomainUser(AuthenticationUtil.getAdminUserName(), tenantDomain1); + final String tenantAdminName2 = tenantService.getDomainUser(AuthenticationUtil.getAdminUserName(), tenantDomain2); + final String superAdmin = "admin"; + + // Create test authorities that are visible only to tenant1 + clearUsage(tenantDomain1); + createTestAuthoritiesForTenant(tenantUniqueGroupNames, tenantAdminName1); + // Check that tenant1's authorities are visible to tenant1 + clearUsage(tenantDomain1); + checkTestAuthoritiesPresence(tenantUniqueGroupNames, tenantAdminName1, true); + // Check that tenant1's authorities are not visible to tenant2 + clearUsage(tenantDomain2); + checkTestAuthoritiesPresence(tenantUniqueGroupNames, tenantAdminName2, false); + // Check that tenant1's authorities are not visible to super-admin + checkTestAuthoritiesPresence(tenantUniqueGroupNames, superAdmin, false); + + + // Create test authorities that are visible only to super-admin + createTestAuthoritiesForTenant(superadminUniqueGroupNames, superAdmin); + // Check that super-admin's authorities are not visible to tenant1 + clearUsage(tenantDomain1); + checkTestAuthoritiesPresence(superadminUniqueGroupNames, tenantAdminName1, false); + // Check that super-admin's authorities are not visible to tenant2 + clearUsage(tenantDomain2); + checkTestAuthoritiesPresence(superadminUniqueGroupNames, tenantAdminName2, false); + // Check that super-admin's authorities are visible to super-admin + checkTestAuthoritiesPresence(superadminUniqueGroupNames, superAdmin, true); + + + // Delete tenant1's authorities + clearUsage(tenantDomain1); + deleteTestAuthoritiesForTenant(tenantUniqueGroupNames, tenantAdminName1); + // Check that tenant1's authorities are not visible to tenant1 + checkTestAuthoritiesPresence(tenantUniqueGroupNames, tenantAdminName1, false); + + // Delete super-admin's authorities + deleteTestAuthoritiesForTenant(superadminUniqueGroupNames, superAdmin); + // Check that super-admin's authorities are not visible to super-admin + checkTestAuthoritiesPresence(superadminUniqueGroupNames, superAdmin, false); + } + finally + { + deleteTenant(tenantDomain1); + deleteTenant(tenantDomain2); } - - clearUsage(AuthenticationUtil.getAdminUserName()); - - createTenant(tenantDomain1); - createTenant(tenantDomain2); - - final String tenantAdminName1 = tenantService.getDomainUser(AuthenticationUtil.getAdminUserName(), tenantDomain1); - final String tenantAdminName2 = tenantService.getDomainUser(AuthenticationUtil.getAdminUserName(), tenantDomain2); - final String superAdmin = "admin"; - - // Create test authorities that are visible only to tenant1 - clearUsage(tenantDomain1); - createTestAuthoritiesForTenant(tenantUniqueGroupNames, tenantAdminName1); - // Check that tenant1's authorities are visible to tenant1 - clearUsage(tenantDomain1); - checkTestAuthoritiesPresence(tenantUniqueGroupNames, tenantAdminName1, true); - // Check that tenant1's authorities are not visible to tenant2 - clearUsage(tenantDomain2); - checkTestAuthoritiesPresence(tenantUniqueGroupNames, tenantAdminName2, false); - // Check that tenant1's authorities are not visible to super-admin - checkTestAuthoritiesPresence(tenantUniqueGroupNames, superAdmin, false); - - - // Create test authorities that are visible only to super-admin - createTestAuthoritiesForTenant(superadminUniqueGroupNames, superAdmin); - // Check that super-admin's authorities are not visible to tenant1 - clearUsage(tenantDomain1); - checkTestAuthoritiesPresence(superadminUniqueGroupNames, tenantAdminName1, false); - // Check that super-admin's authorities are not visible to tenant2 - clearUsage(tenantDomain2); - checkTestAuthoritiesPresence(superadminUniqueGroupNames, tenantAdminName2, false); - // Check that super-admin's authorities are visible to super-admin - checkTestAuthoritiesPresence(superadminUniqueGroupNames, superAdmin, true); - - - // Delete tenant1's authorities - clearUsage(tenantDomain1); - deleteTestAuthoritiesForTenant(tenantUniqueGroupNames, tenantAdminName1); - // Check that tenant1's authorities are not visible to tenant1 - checkTestAuthoritiesPresence(tenantUniqueGroupNames, tenantAdminName1, false); - - // Delete super-admin's authorities - deleteTestAuthoritiesForTenant(superadminUniqueGroupNames, superAdmin); - // Check that super-admin's authorities are not visible to super-admin - checkTestAuthoritiesPresence(superadminUniqueGroupNames, superAdmin, false); } public void testSharedGroupDeletion() @@ -329,79 +341,89 @@ public class MultiTDemoTest extends TestCase final String tenantDomain1 = TEST_RUN+".groupdel3"; final String tenantDomain2 = TEST_RUN+".groupdel4"; - final String[] commonTenantUniqueGroupNames = new String[10]; - for (int i = 0; i < commonTenantUniqueGroupNames.length; i++) + try { - commonTenantUniqueGroupNames[i] = TEST_RUN + "test_group" + i; + final String[] commonTenantUniqueGroupNames = new String[10]; + for (int i = 0; i < commonTenantUniqueGroupNames.length; i++) + { + commonTenantUniqueGroupNames[i] = TEST_RUN + "test_group" + i; + } + + clearUsage(AuthenticationUtil.getAdminUserName()); + + createTenant(tenantDomain1); + createTenant(tenantDomain2); + + final String tenantAdminName1 = tenantService.getDomainUser(AuthenticationUtil.getAdminUserName(), tenantDomain1); + final String tenantAdminName2 = tenantService.getDomainUser(AuthenticationUtil.getAdminUserName(), tenantDomain2); + final String superAdmin = "admin"; + + // Create test common authorities for tenant1 + clearUsage(tenantDomain1); + createTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName1); + // Create test common authorities for tenant2 + clearUsage(tenantDomain2); + createTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName2); + // Create test common authorities for super-admin + createTestAuthoritiesForTenant(commonTenantUniqueGroupNames, superAdmin); + + // Check that authorities are visible to tenant1 + clearUsage(tenantDomain1); + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName1, true); + // Check that authorities are visible to tenant2 + clearUsage(tenantDomain2); + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName2, true); + // Check that authorities are visible to super-admin + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, superAdmin, true); + + // Delete tenant1's authorities + clearUsage(tenantDomain1); + deleteTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName1); + // Check that authorities are not visible to tenant1 + clearUsage(tenantDomain1); + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName1, false); + // Check that authorities are visible to tenant2 + clearUsage(tenantDomain2); + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName2, true); + // Check that authorities are visible to super-admin + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, superAdmin, true); + + // Create test common authorities for tenant1 + clearUsage(tenantDomain1); + createTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName1); + // Delete tenant2's authorities + clearUsage(tenantDomain2); + deleteTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName2); + // Check that authorities are visible to tenant1 + clearUsage(tenantDomain1); + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName1, true); + // Check that authorities are not visible to tenant2 + clearUsage(tenantDomain2); + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName2, false); + // Check that authorities are visible to super-admin + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, superAdmin, true); + + // Create test common authorities for tenant2 + clearUsage(tenantDomain2); + createTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName2); + // Delete super-admin's authorities + deleteTestAuthoritiesForTenant(commonTenantUniqueGroupNames, superAdmin); + // Check that authorities are visible to tenant1 + clearUsage(tenantDomain1); + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName1, true); + // Check that authorities are visible to tenant2 + clearUsage(tenantDomain2); + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName2, true); + // Check that authorities are not visible to super-admin + checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, superAdmin, false); + } + finally + { + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName()); + + deleteTenant(tenantDomain1); + deleteTenant(tenantDomain2); } - - clearUsage(AuthenticationUtil.getAdminUserName()); - - createTenant(tenantDomain1); - createTenant(tenantDomain2); - - final String tenantAdminName1 = tenantService.getDomainUser(AuthenticationUtil.getAdminUserName(), tenantDomain1); - final String tenantAdminName2 = tenantService.getDomainUser(AuthenticationUtil.getAdminUserName(), tenantDomain2); - final String superAdmin = "admin"; - - // Create test common authorities for tenant1 - clearUsage(tenantDomain1); - createTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName1); - // Create test common authorities for tenant2 - clearUsage(tenantDomain2); - createTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName2); - // Create test common authorities for super-admin - createTestAuthoritiesForTenant(commonTenantUniqueGroupNames, superAdmin); - - // Check that authorities are visible to tenant1 - clearUsage(tenantDomain1); - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName1, true); - // Check that authorities are visible to tenant2 - clearUsage(tenantDomain2); - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName2, true); - // Check that authorities are visible to super-admin - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, superAdmin, true); - - // Delete tenant1's authorities - clearUsage(tenantDomain1); - deleteTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName1); - // Check that authorities are not visible to tenant1 - clearUsage(tenantDomain1); - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName1, false); - // Check that authorities are visible to tenant2 - clearUsage(tenantDomain2); - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName2, true); - // Check that authorities are visible to super-admin - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, superAdmin, true); - - // Create test common authorities for tenant1 - clearUsage(tenantDomain1); - createTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName1); - // Delete tenant2's authorities - clearUsage(tenantDomain2); - deleteTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName2); - // Check that authorities are visible to tenant1 - clearUsage(tenantDomain1); - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName1, true); - // Check that authorities are not visible to tenant2 - clearUsage(tenantDomain2); - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName2, false); - // Check that authorities are visible to super-admin - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, superAdmin, true); - - // Create test common authorities for tenant2 - clearUsage(tenantDomain2); - createTestAuthoritiesForTenant(commonTenantUniqueGroupNames, tenantAdminName2); - // Delete super-admin's authorities - deleteTestAuthoritiesForTenant(commonTenantUniqueGroupNames, superAdmin); - // Check that authorities are visible to tenant1 - clearUsage(tenantDomain1); - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName1, true); - // Check that authorities are visible to tenant2 - clearUsage(tenantDomain2); - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, tenantAdminName2, true); - // Check that authorities are not visible to super-admin - checkTestAuthoritiesPresence(commonTenantUniqueGroupNames, superAdmin, false); } @@ -425,6 +447,32 @@ public class MultiTDemoTest extends TestCase }, AuthenticationUtil.getSystemUserName()); } + private void deleteTenant(final String tenantDomain) + { + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // delete tenant (if it exists) + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + if (tenantAdminService.existsTenant(tenantDomain)) + { + tenantAdminService.deleteTenant(tenantDomain); + + logger.info("Deleted tenant " + tenantDomain); + } + + return null; + } + }, AuthenticationUtil.getSystemUserName()); + return null; + } + }); + } + public void test_ETHREEOH_2015() { final String tenantDomain1 = TEST_RUN+".one.ethreeoh2015"; @@ -1130,6 +1178,19 @@ public class MultiTDemoTest extends TestCase } } + // pseudo cleanup - if this test runs last + public void testDeleteTenants() + { + logger.info("test delete tenant"); + + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + + for (final String tenantDomain : tenants) + { + deleteTenant(tenantDomain); + } + } + private void createGroup(String shortName, String parentShortName) { // create new Group using authority Service diff --git a/source/java/org/alfresco/repo/version/Version2ServiceImpl.java b/source/java/org/alfresco/repo/version/Version2ServiceImpl.java index 2d8b6782a2..960df9f4a6 100644 --- a/source/java/org/alfresco/repo/version/Version2ServiceImpl.java +++ b/source/java/org/alfresco/repo/version/Version2ServiceImpl.java @@ -423,11 +423,11 @@ public class Version2ServiceImpl extends VersionServiceImpl implements VersionSe VersionHistory versionHistory = null; - // Get the version history regardless of whether the node is still 'live' or not - NodeRef versionHistoryRef = getVersionHistoryNodeRef(nodeRef); - if (versionHistoryRef != null) + // Get the version history regardless of whether the node is still 'live' or not + NodeRef versionHistoryRef = getVersionHistoryNodeRef(nodeRef); + if (versionHistoryRef != null) { - versionHistory = buildVersionHistory(versionHistoryRef, nodeRef); + versionHistory = buildVersionHistory(versionHistoryRef, nodeRef); } else { @@ -558,7 +558,7 @@ public class Version2ServiceImpl extends VersionServiceImpl implements VersionSe PermissionService.ALL_PERMISSIONS, true); permissionService.setPermission( versionNodeRef, - AuthenticationUtil.getGuestUserName(), + AuthenticationUtil.getGuestUserName(), PermissionService.ALL_PERMISSIONS, true); } @@ -825,7 +825,7 @@ public class Version2ServiceImpl extends VersionServiceImpl implements VersionSe } // TODO consolidate with VersionUtil.convertFrozenToOriginalProps - + for (QName key : nodeProperties.keySet()) { Serializable value = nodeProperties.get(key); @@ -854,21 +854,21 @@ public class Version2ServiceImpl extends VersionServiceImpl implements VersionSe } else { - if (keyName.equals(Version.PROP_DESCRIPTION) || - keyName.equals(VersionBaseModel.PROP_VERSION_LABEL) || - keyName.equals(VersionBaseModel.PROP_VERSION_NUMBER)) - { - // ignore reserved localname (including cm:description, cm:versionLabel) - } - else - { - // all other properties - versionProperties.put(keyName, value); - } + if (keyName.equals(Version.PROP_DESCRIPTION) || + keyName.equals(VersionBaseModel.PROP_VERSION_LABEL) || + keyName.equals(VersionBaseModel.PROP_VERSION_NUMBER)) + { + // ignore reserved localname (including cm:description, cm:versionLabel) + } + else + { + // all other properties + versionProperties.put(keyName, value); + } } } } - + // Create and return the version object NodeRef newNodeRef = new NodeRef(new StoreRef(Version2Model.STORE_PROTOCOL, Version2Model.STORE_ID), versionRef.getId()); Version result = new VersionImpl(versionProperties, newNodeRef); @@ -1321,18 +1321,31 @@ public class Version2ServiceImpl extends VersionServiceImpl implements VersionSe { // Get the version history node for the node is question and delete it NodeRef versionHistoryNodeRef = getVersionHistoryNodeRef(nodeRef); - + if (versionHistoryNodeRef != null) { - // Delete the version history node - this.dbNodeService.deleteNode(versionHistoryNodeRef); - - if (this.nodeService.exists(nodeRef) == true && this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true) + try { - // Reset the version label property on the versionable node - this.nodeService.setProperty(nodeRef, ContentModel.PROP_VERSION_LABEL, null); + // Disable auto-version behaviour + this.policyBehaviourFilter.disableBehaviour(ContentModel.ASPECT_VERSIONABLE); + + // Delete the version history node + this.dbNodeService.deleteNode(versionHistoryNodeRef); + + if (this.nodeService.exists(nodeRef) == true && this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true) + { + + // Reset the version label property on the versionable node + this.nodeService.setProperty(nodeRef, ContentModel.PROP_VERSION_LABEL, null); + } + + } + finally + { + this.policyBehaviourFilter.enableBehaviour(ContentModel.ASPECT_VERSIONABLE); } } + } }