Classification enforecment refactor

* rename veto as permission pre-processor
  * add support for permission post-processors
  * add transaction cache to classification enforcement
  * add records management permission post processor to remove code from extended permission service 



git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ROYTEST@110013 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2015-08-13 03:46:43 +00:00
parent d0cecbd4fa
commit 42d26a6c2b
14 changed files with 483 additions and 148 deletions

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.classification.permission;
import java.util.Map;
import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceBootstrap;
import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService;
import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
import org.alfresco.module.org_alfresco_module_rm.util.TransactionalResourceHelper;
import org.alfresco.repo.security.permissions.processor.impl.PermissionPreProcessorBaseImpl;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.util.Triple;
/**
* Classification permission pre-processor implementation.
*
* @author Roy Wetherall
* @since 3.0.a
*/
public class ClassificationPermissionPreProcessor extends PermissionPreProcessorBaseImpl
{
/** transaction resource keys */
private static final String KEY_PROCESSING = ClassificationPermissionPreProcessor.class.getName() + ".processing";
private static final String KEY_CACHE = ClassificationPermissionPreProcessor.class.getName() + ".cache";
/** content classification service */
private ContentClassificationService contentClassificationService;
/** transaction resource helper */
private TransactionalResourceHelper transactionalResourceHelper;
/** classificaiton service bootstrap */
private ClassificationServiceBootstrap classificationServiceBootstrap;
/** authentication util */
private AuthenticationUtil authenticationUtil;
/**
* @param contentClassificationService content classification service
*/
public void setContentClassificationService(ContentClassificationService contentClassificationService)
{
this.contentClassificationService = contentClassificationService;
}
/**
* @param transactionalResourceHelper transaction resource helper
*/
public void setTransactionalResourceHelper(TransactionalResourceHelper transactionalResourceHelper)
{
this.transactionalResourceHelper = transactionalResourceHelper;
}
/**
* @param classificationServiceBootstrap classification service bootstrap
*/
public void setClassificationServiceBootstrap(ClassificationServiceBootstrap classificationServiceBootstrap)
{
this.classificationServiceBootstrap = classificationServiceBootstrap;
}
/**
* @param authenticationUtil authentication util
*/
public void setAuthenticationUtil(AuthenticationUtil authenticationUtil)
{
this.authenticationUtil = authenticationUtil;
}
/**
* @see org.alfresco.repo.security.permissions.processor.PermissionPreProcessor#process(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/
@Override
public AccessStatus process(NodeRef nodeRef, String perm)
{
AccessStatus result = AccessStatus.UNDETERMINED;
// ensure the classification bootstrap has been initialised
if (classificationServiceBootstrap.isInitialised())
{
// do not process a node that is already being processed
Set<Object> processing = transactionalResourceHelper.getSet(KEY_PROCESSING);
if (!processing.contains(nodeRef))
{
processing.add(nodeRef);
try
{
// create key
final String currentUser = authenticationUtil.getRunAsUser();
Triple<NodeRef, String, String> key = new Triple<NodeRef, String, String>(nodeRef, perm, currentUser);
// get transaction cache (the purpose of this is prevent duplicate tests within the same transaction)
Map<Triple<NodeRef, String, String>, AccessStatus> cache = transactionalResourceHelper.getMap(KEY_CACHE);
if (!cache.containsKey(key))
{
// determine whether the current user has clearance for the node
if (!contentClassificationService.hasClearance(nodeRef))
{
result = AccessStatus.DENIED;
}
// cache value (in transaction)
cache.put(key, result);
}
else
{
result = cache.get(key);
}
}
finally
{
processing.remove(nodeRef);
}
}
}
return result;
}
}

View File

@@ -1,68 +0,0 @@
/**
*
*/
package org.alfresco.module.org_alfresco_module_rm.classification.veto;
import java.util.Set;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceBootstrap;
import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService;
import org.alfresco.module.org_alfresco_module_rm.util.TransactionalResourceHelper;
import org.alfresco.repo.security.permissions.veto.PermissionVetoBaseImpl;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* @author Roy Wetherall
* @since 3.0.a
*/
public class ClassificationPermissionVeto extends PermissionVetoBaseImpl
{
private ContentClassificationService contentClassificationService;
private TransactionalResourceHelper transactionalResourceHelper;
private ClassificationServiceBootstrap classificationServiceBootstrap;
public void setContentClassificationService(ContentClassificationService contentClassificationService)
{
this.contentClassificationService = contentClassificationService;
}
public void setTransactionalResourceHelper(TransactionalResourceHelper transactionalResourceHelper)
{
this.transactionalResourceHelper = transactionalResourceHelper;
}
public void setClassificationServiceBootstrap(ClassificationServiceBootstrap classificationServiceBootstrap)
{
this.classificationServiceBootstrap = classificationServiceBootstrap;
}
/**
* @see org.alfresco.repo.security.permissions.veto.PermissionVeto#isVetoed(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/
@Override
public boolean isVetoed(NodeRef nodeRef, String perm)
{
boolean result = false;
if (classificationServiceBootstrap.isInitialised())
{
Set<Object> processing = transactionalResourceHelper.getSet(ClassificationPermissionVeto.class.getName());
if (!processing.contains(nodeRef))
{
processing.add(nodeRef);
try
{
result = !contentClassificationService.hasClearance(nodeRef);
}
finally
{
processing.remove(nodeRef);
}
}
}
return result;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.permission;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.security.permissions.processor.impl.PermissionPostProcessorBaseImpl;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
/**
* Records management permission post processor.
*
* @author Roy Wetherall
* @since 3.0.a
*/
public class RecordsManagementPermissionPostProcessor extends PermissionPostProcessorBaseImpl
{
/** node service */
private NodeService nodeService;
public void setNodeService(NodeService nodeService) {this.nodeService=nodeService;}
/** permission service */
private PermissionService permissionService;
public void setPermissionService(PermissionService permissionService) {this.permissionService=permissionService;}
/**
* @see org.alfresco.repo.security.permissions.processor.PermissionPostProcessor#process(org.alfresco.service.cmr.security.AccessStatus, org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/
@Override
public AccessStatus process(AccessStatus accessStatus, NodeRef nodeRef, String perm)
{
AccessStatus result = accessStatus;
if (AccessStatus.DENIED.equals(accessStatus) &&
nodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT))
{
// if read denied on rm artifact
if (PermissionService.READ.equals(perm))
{
// check for read record
result = permissionService.hasPermission(nodeRef, RMPermissionModel.READ_RECORDS);
}
// if write deinied on rm artificat
else if (PermissionService.WRITE.equals(perm))
{
// check for file record
result = permissionService.hasPermission(nodeRef, RMPermissionModel.FILE_RECORDS);
}
}
return result;
}
}

View File

@@ -30,5 +30,11 @@ import org.alfresco.service.cmr.security.PermissionService;
*/
public interface ExtendedPermissionService extends PermissionService
{
/**
* Get a set of all the authorities that have write access.
*
* @param aclId acl id
* @return {@link Set}<{@link String}> set of authorities with write access
*/
Set<String> getWriters(Long aclId);
}

View File

@@ -35,8 +35,9 @@ import org.alfresco.module.org_alfresco_module_rm.security.ExtendedWriterDynamic
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.security.permissions.AccessControlEntry;
import org.alfresco.repo.security.permissions.AccessControlList;
import org.alfresco.repo.security.permissions.veto.PermissionVeto;
import org.alfresco.repo.security.permissions.veto.PermissionVetoRegistry;
import org.alfresco.repo.security.permissions.processor.PermissionPostProcessor;
import org.alfresco.repo.security.permissions.processor.PermissionPreProcessor;
import org.alfresco.repo.security.permissions.processor.PermissionProcessorRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityType;
@@ -53,7 +54,7 @@ import org.springframework.context.ApplicationEvent;
* @author Roy Wetherall
*/
public class ExtendedPermissionServiceImpl extends PermissionServiceImpl
implements ExtendedPermissionService
implements ExtendedPermissionService
{
/** Writers simple cache */
protected SimpleCache<Serializable, Set<String>> writersCache;
@@ -61,8 +62,8 @@ public class ExtendedPermissionServiceImpl extends PermissionServiceImpl
/** File plan service */
private FilePlanService filePlanService;
/** Permission veto registry */
private PermissionVetoRegistry permissionVetoRegistry;
/** Permission processor registry */
private PermissionProcessorRegistry permissionProcessorRegistry;
/**
* Gets the file plan service
@@ -84,9 +85,14 @@ public class ExtendedPermissionServiceImpl extends PermissionServiceImpl
this.filePlanService = filePlanService;
}
public void setPermissionVetoRegistry(PermissionVetoRegistry permissionVetoRegistry)
/**
* Sets the permission processor registry
*
* @param permissionProcessorRegistry the permissions processor registry
*/
public void setPermissionProcessorRegistry(PermissionProcessorRegistry permissionProcessorRegistry)
{
this.permissionVetoRegistry = permissionVetoRegistry;
this.permissionProcessorRegistry = permissionProcessorRegistry;
}
/**
@@ -130,34 +136,34 @@ public class ExtendedPermissionServiceImpl extends PermissionServiceImpl
@Override
public AccessStatus hasPermission(NodeRef nodeRef, String perm)
{
// check permission vetos
List<PermissionVeto> permissionVetos = permissionVetoRegistry.getPermissionVetos();
for (PermissionVeto permissionVeto : permissionVetos)
AccessStatus result = AccessStatus.UNDETERMINED;
// permission pre-processors
List<PermissionPreProcessor> preProcessors = permissionProcessorRegistry.getPermissionPreProcessors();
for (PermissionPreProcessor preProcessor : preProcessors)
{
if (permissionVeto.isVetoed(nodeRef, perm))
// pre process permission
result = preProcessor.process(nodeRef, perm);
// veto if denied
if (AccessStatus.DENIED.equals(result))
{
// TODO add logging so veto cause can be diagnosed
// veto access to node
return AccessStatus.DENIED;
return result;
}
}
AccessStatus acs = super.hasPermission(nodeRef, perm);
if (AccessStatus.DENIED.equals(acs) &&
PermissionService.READ.equals(perm) &&
nodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT))
// evaluate permission
result = super.hasPermission(nodeRef, perm);
// permission post-processors
List<PermissionPostProcessor> postProcessors = permissionProcessorRegistry.getPermissionPostProcessors();
for (PermissionPostProcessor postProcessor : postProcessors)
{
return super.hasPermission(nodeRef, RMPermissionModel.READ_RECORDS);
}
else if (AccessStatus.DENIED.equals(acs) &&
PermissionService.WRITE.equals(perm) &&
nodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT))
{
return super.hasPermission(nodeRef, RMPermissionModel.FILE_RECORDS);
}
return acs;
// post process permission
result = postProcessor.process(result, nodeRef, perm);
}
return result;
}
/**

View File

@@ -16,33 +16,28 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.security.permissions.veto;
package org.alfresco.repo.security.permissions.processor;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus;
import java.util.ArrayList;
import java.util.List;
/**
* Permission Post Processor.
*
* @author Roy Wetherall
* @since 3.0.a
*/
public class PermissionVetoRegistry
public interface PermissionPostProcessor
{
/** list of vetos to apply */
private List<PermissionVeto> permissionVetos = new ArrayList<PermissionVeto>();
/**
* @param permissionVeto permission veto
* Process permission.
*
* @param accessStatus current access status
* @param nodeRef node reference
* @param perm permission
* @return {@link AccessStatus}
*/
public void addPermissionVeto(PermissionVeto permissionVeto)
{
permissionVetos.add(permissionVeto);
}
/**
* @return {@link List}<{@link PermissionVeto}> list of permission vetos
*/
public List<PermissionVeto> getPermissionVetos()
{
return permissionVetos;
}
AccessStatus process(AccessStatus accessStatus, NodeRef nodeRef, String perm);
}

View File

@@ -16,21 +16,28 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.security.permissions.veto;
package org.alfresco.repo.security.permissions.processor;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus;
/**
* Permission Veto Interface
*
* @author Roy Wetherall
* @since 3.0.a
*/
public interface PermissionVeto
public interface PermissionPreProcessor
{
/**
* Process permission.
*
* @param nodeRef
* @param perm
* @return
* @param accessStatus current access status
* @param nodeRef node reference
* @param perm permission
* @return {@link AccessStatus}
*/
boolean isVetoed(NodeRef nodeRef, String perm);
AccessStatus process(NodeRef nodeRef, String perm);
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.security.permissions.processor;
import java.util.ArrayList;
import java.util.List;
/**
* Permission Processor Registry
*
* @author Roy Wetherall
* @since 3.0.a
*/
public class PermissionProcessorRegistry
{
/** permission pre-processors */
private List<PermissionPreProcessor> permissionPreProcessors = new ArrayList<PermissionPreProcessor>();
/** permission post-processors */
private List<PermissionPostProcessor> permissionPostProcessors = new ArrayList<PermissionPostProcessor>();
/**
* Add a permission pre-processor.
*
* @param permissionPreProcessor permission pre-processor
*/
public void addPermissionPreProcessor(PermissionPreProcessor permissionPreProcessor)
{
permissionPreProcessors.add(permissionPreProcessor);
}
/**
* Add a permission post-processor.
*
* @param permissionPostProcessor permission post-processor
*/
public void addPermissionPostProcessor(PermissionPostProcessor permissionPostProcessor)
{
permissionPostProcessors.add(permissionPostProcessor);
}
/**
* Get a list of the registered permission pre-processors.
*
* @return {@link List}<{@link PermissionPreProcessor}> list of permission pre-processors
*/
public List<PermissionPreProcessor> getPermissionPreProcessors()
{
return permissionPreProcessors;
}
/**
* Get a list of the registered permission post-processors.
*
* @return <{@link List}>{@link PermissionPreProcessor} list of permission post-processors
*/
public List<PermissionPostProcessor> getPermissionPostProcessors()
{
return permissionPostProcessors;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.security.permissions.processor.impl;
import org.alfresco.repo.security.permissions.processor.PermissionPostProcessor;
/**
* Permission post processor base implementation.
* <p>
* Helper class that can be extended when providing a custom permission
* post processor implementation.
*
* @author Roy Wetherall
* @since 3.0.a
*/
public abstract class PermissionPostProcessorBaseImpl extends PermissionProcessorBaseImpl
implements PermissionPostProcessor
{
/**
* Init method to add this permission extensions to the registry
*/
public void init()
{
getPermissionProcessorRegistry().addPermissionPostProcessor(this);
}
}

View File

@@ -16,30 +16,27 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.security.permissions.veto;
package org.alfresco.repo.security.permissions.processor.impl;
import org.alfresco.repo.security.permissions.processor.PermissionPreProcessor;
/**
* Permission pre-processor base implementation.
* <p>
* Helper class that can be extended when providing a custom permission
* pre-processor implementation.
*
* @author Roy Wetherall
* @since 3.0.a
*/
public abstract class PermissionVetoBaseImpl implements PermissionVeto
public abstract class PermissionPreProcessorBaseImpl extends PermissionProcessorBaseImpl
implements PermissionPreProcessor
{
/** permission veto refistry */
private PermissionVetoRegistry permissionVetoRegistry;
/**
* @param permissionVetoRegistry permission veto registry
*/
public void setPermissionVetoRegistry(PermissionVetoRegistry permissionVetoRegistry)
{
this.permissionVetoRegistry = permissionVetoRegistry;
}
/**
* Init method to add this permission veto to the registry
* Init method to add this permission extensions to the registry
*/
public void init()
{
permissionVetoRegistry.addPermissionVeto(this);
getPermissionProcessorRegistry().addPermissionPreProcessor(this);
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2005-2015 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.security.permissions.processor.impl;
import org.alfresco.repo.security.permissions.processor.PermissionProcessorRegistry;
/**
* Commonality found in both pre and post permission processor implementations.
*
* @author Roy Wetherall
* @since 3.0.a
*/
/*package*/ abstract class PermissionProcessorBaseImpl
{
/** permission processor registry */
private PermissionProcessorRegistry permissionProcessorRegistry;
/**
* @param PermissionProcessorRegistry permission processor registry
*/
public void setPermissionProcessorRegistry(PermissionProcessorRegistry permissionProcessorRegistry)
{
this.permissionProcessorRegistry = permissionProcessorRegistry;
}
/**
* @return {@link PermissionProcessorRegistry} permission processor registry
*/
protected PermissionProcessorRegistry getPermissionProcessorRegistry()
{
return permissionProcessorRegistry;
}
}