Merged V3.1 to HEAD

12991: Merged V3.0 to V3.1
      12929: Merged V2.2 to V3.0
         12579: Fix ETWOTWO-925: Adding users to a web project is slow due to permission setting
         12583: Fix ETWOTWO-925: Added post fix snapshot (follow on from 12579)
   ___________________________________________________________________
   Modified: svn:mergeinfo
      Merged /alfresco/BRANCHES/V3.0:r12929
      Merged /alfresco/BRANCHES/V2.2:r12579,12583
      Merged /alfresco/BRANCHES/V3.1:r12991


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13547 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-03-11 02:20:29 +00:00
parent e3503a6a88
commit b9bcb907bc
8 changed files with 821 additions and 178 deletions

View File

@@ -0,0 +1,493 @@
/*
* Copyright (C) 2005-2007 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.admin.patch.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sf.acegisecurity.providers.jaas.AuthorityGranter;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.WCMAppModel;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.avm.AVMRepository;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.domain.hibernate.AclDaoComponentImpl;
import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.service.transaction.TransactionService;
/**
* Remove ACLs on all but staging area stores On staging area stores, set ACls according to the users and roles as set
* on the web site Note: runs as the system user
*
* @author andyh
*/
public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch
{
public static final String[] PERMISSIONS = new String[] { PermissionService.WCM_CONTENT_MANAGER, PermissionService.WCM_CONTENT_PUBLISHER,
PermissionService.WCM_CONTENT_CONTRIBUTOR, PermissionService.WCM_CONTENT_REVIEWER };
private static final String MSG_SUCCESS = "patch.moveWCMToGroupBasedPermissionsPatch.result";
AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor;
AVMService avmService;
PermissionService permissionService;
AclDaoComponentImpl aclDaoComponent;
AuthorityService authorityService;
String replaceAllWith = PermissionService.WCM_CONTENT_MANAGER;
public void setAvmService(AVMService avmService)
{
this.avmService = avmService;
}
public void setAvmSnapShotTriggeredIndexingMethodInterceptor(AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor)
{
this.avmSnapShotTriggeredIndexingMethodInterceptor = avmSnapShotTriggeredIndexingMethodInterceptor;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setAclDaoComponent(AclDaoComponentImpl aclDaoComponent)
{
this.aclDaoComponent = aclDaoComponent;
}
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
public void setReplaceAllWith(String replaceAllWith)
{
this.replaceAllWith = replaceAllWith;
}
@Override
protected String applyInternal() throws Exception
{
Thread progressThread = null;
if (aclDaoComponent.supportsProgressTracking())
{
Long toDo = aclDaoComponent.getAVMHeadNodeCount();
Long maxId = aclDaoComponent.getMaxAclId();
progressThread = new Thread(new ProgressWatcher(toDo, maxId), "WCMPactchProgressWatcher");
progressThread.start();
}
List<AVMStoreDescriptor> stores = avmService.getStores();
for (AVMStoreDescriptor store : stores)
{
switch (avmSnapShotTriggeredIndexingMethodInterceptor.getStoreType(store.getName()))
{
/* Set permissions in staging */
case STAGING:
fixAllPermissions(store);
setStagingAreaPermissions(store);
setStagingAreaMasks(store);
// TODO: mark read only
break;
/* Clear permissions */
case AUTHOR:
case AUTHOR_PREVIEW:
case AUTHOR_WORKFLOW:
case AUTHOR_WORKFLOW_PREVIEW:
fixAllStagingPermissions(store);
setSandBoxMasks(store);
break;
case STAGING_PREVIEW:
fixAllStagingPermissions(store);
setStagingAreaMasks(store);
// TODO: mark read only
break;
case WORKFLOW:
case WORKFLOW_PREVIEW:
break;
/* non WCM stores - nothing to do */
case UNKNOWN:
default:
}
}
if (progressThread != null)
{
progressThread.interrupt();
progressThread.join();
}
// build the result message
String msg = I18NUtil.getMessage(MSG_SUCCESS);
// done
return msg;
}
private boolean isPermissionSet(NodeRef nodeRef, String authority, String permission)
{
Set<AccessPermission> set = permissionService.getAllSetPermissions(nodeRef);
for (AccessPermission ap : set)
{
if (ap.getAuthority().equals(authority) && ap.isSetDirectly() && ap.getPermission().equals(permission))
{
return true;
}
}
return false;
}
private boolean isMaskSet(StoreRef storeRef, String authority, String permission)
{
Set<AccessPermission> set = permissionService.getAllSetPermissions(storeRef);
for (AccessPermission ap : set)
{
if (ap.getAuthority().equals(authority) && ap.isSetDirectly() && ap.getPermission().equals(permission))
{
return true;
}
}
return false;
}
private void makeGroupsIfRequired(String stagingStoreName, NodeRef dirRef)
{
for (String permission : PERMISSIONS)
{
String shortName = stagingStoreName + "-" + permission;
String group = authorityService.getName(AuthorityType.GROUP, shortName);
if (!authorityService.authorityExists(group))
{
String newGroup = authorityService.createAuthority(AuthorityType.GROUP, null, shortName);
permissionService.setPermission(dirRef, newGroup, permission, true);
}
}
}
private void addToGroupIfRequired(String stagingStoreName, String user, String permission)
{
String shortName = stagingStoreName + "-" + permission;
String group = authorityService.getName(AuthorityType.GROUP, shortName);
Set<String> members = authorityService.getContainedAuthorities(AuthorityType.USER, group, true);
if (!members.contains(user))
{
authorityService.addAuthority(group, user);
}
}
private void fixAllPermissions(AVMStoreDescriptor store)
{
fixAllPermissionsImpl(store.getName());
}
private void fixAllStagingPermissions(AVMStoreDescriptor store)
{
String stagingAreaName = extractStagingAreaName(store.getName());
fixAllPermissionsImpl(stagingAreaName);
}
private void fixAllPermissionsImpl(String stagingStoreName)
{
QName propQName = QName.createQName(null, ".web_project.noderef");
PropertyValue pValue = avmService.getStoreProperty(stagingStoreName, propQName);
if (pValue != null)
{
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
List<ChildAssociationRef> userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
if (userrole.equals(PermissionService.ALL_PERMISSIONS))
{
nodeService.setProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE, replaceAllWith);
}
}
}
}
private void setStagingAreaPermissions(AVMStoreDescriptor store)
{
QName propQName = QName.createQName(null, ".web_project.noderef");
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, store.getName() + ":/www");
makeGroupsIfRequired(store.getName(), dirRef);
if (!isPermissionSet(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ))
{
permissionService.setPermission(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
}
// Add group permissions
for (String permission : PERMISSIONS)
{
String cms = authorityService.getName(AuthorityType.GROUP, store.getName() + "-" + permission);
permissionService.setPermission(dirRef, cms, permission, true);
}
PropertyValue pValue = avmService.getStoreProperty(store.getName(), propQName);
if (pValue != null)
{
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
List<ChildAssociationRef> userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
// remove existing
if (isPermissionSet(dirRef, username, userrole))
{
permissionService.deletePermission(dirRef, username, userrole);
}
addToGroupIfRequired(store.getName(), username, userrole);
}
}
}
private void setStagingAreaMasks(AVMStoreDescriptor store)
{
// groups must exist
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, store.getName() + ":/www");
if (!isMaskSet(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ))
{
permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
}
String cms = authorityService.getName(AuthorityType.GROUP, store.getName() + "-" + PermissionService.WCM_CONTENT_MANAGER);
if (!isMaskSet(dirRef.getStoreRef(), cms, PermissionService.CHANGE_PERMISSIONS))
{
permissionService.setPermission(dirRef.getStoreRef(), cms, PermissionService.CHANGE_PERMISSIONS, true);
}
if (!isMaskSet(dirRef.getStoreRef(), cms, PermissionService.READ_PERMISSIONS))
{
permissionService.setPermission(dirRef.getStoreRef(), cms, PermissionService.READ_PERMISSIONS, true);
}
QName propQName = QName.createQName(null, ".web_project.noderef");
PropertyValue pValue = avmService.getStoreProperty(store.getName(), propQName);
if (pValue != null)
{
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
List<ChildAssociationRef> userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
if (userrole.equals(PermissionService.WCM_CONTENT_MANAGER))
{
// remove existing
if (isMaskSet(dirRef.getStoreRef(), username, PermissionService.CHANGE_PERMISSIONS))
{
permissionService.deletePermission(dirRef.getStoreRef(), username, PermissionService.CHANGE_PERMISSIONS);
}
if (isMaskSet(dirRef.getStoreRef(), username, PermissionService.READ_PERMISSIONS))
{
permissionService.deletePermission(dirRef.getStoreRef(), username, PermissionService.READ_PERMISSIONS);
}
}
}
}
}
private void setSandBoxMasks(AVMStoreDescriptor sandBoxStore)
{
// get the settings from the staging store ...
String owner = extractOwner(sandBoxStore.getName());
String stagingAreaName = extractStagingAreaName(sandBoxStore.getName());
QName propQName = QName.createQName(null, ".web_project.noderef");
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, sandBoxStore.getName() + ":/www");
Map<QName, PropertyValue> woof = avmService.getStoreProperties(stagingAreaName);
PropertyValue pValue = avmService.getStoreProperty(stagingAreaName, propQName);
if (!isMaskSet(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ))
{
permissionService.setPermission(dirRef.getStoreRef(), PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
}
String cms = authorityService.getName(AuthorityType.GROUP, stagingAreaName + "-" + PermissionService.WCM_CONTENT_MANAGER);
if (!isMaskSet(dirRef.getStoreRef(), cms, PermissionService.WCM_CONTENT_MANAGER))
{
permissionService.setPermission(dirRef.getStoreRef(), cms, PermissionService.WCM_CONTENT_MANAGER, true);
}
if (pValue != null)
{
NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF);
// Apply sepcific user permissions as set on the web project
List<ChildAssociationRef> userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
String username = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
String userrole = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
if (username.equals(owner))
{
permissionService.setPermission(dirRef.getStoreRef(), username, PermissionService.ALL_PERMISSIONS, true);
}
else if (userrole.equals("ContentManager"))
{
if (isMaskSet(dirRef.getStoreRef(), username, userrole))
{
permissionService.deletePermission(dirRef.getStoreRef(), username, userrole);
}
}
}
}
}
private String extractOwner(String name)
{
int start = name.indexOf("--");
if (start == -1)
{
throw new UnsupportedOperationException(name);
}
int end = name.indexOf("--", start + 1);
if (end == -1)
{
return name.substring(start + 2);
}
return name.substring(start + 2, end);
}
private String extractStagingAreaName(String name)
{
int index = name.indexOf("--");
if (index == -1)
{
throw new UnsupportedOperationException(name);
}
return name.substring(0, index);
}
private class ProgressWatcher implements Runnable
{
private boolean running = true;
Long toDo;
Long max;
ProgressWatcher(Long toDo, Long max)
{
this.toDo = toDo;
this.max = max;
}
public void run()
{
while (running)
{
try
{
Thread.sleep(60000);
}
catch (InterruptedException e)
{
running = false;
}
if (running)
{
RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
txHelper.setMaxRetries(1);
Long done = txHelper.doInTransaction(new RetryingTransactionCallback<Long>()
{
public Long execute() throws Throwable
{
return aclDaoComponent.getAVMNodeCountWithNewACLS(max);
}
}, true, true);
reportProgress(toDo, done);
}
}
}
}
}