From 97d2051a7c570ce112b816263cb8cc8534bbcce3 Mon Sep 17 00:00:00 2001 From: Roy Wetherall Date: Mon, 1 Jun 2015 08:18:44 +0000 Subject: [PATCH 01/33] Dev branch for classification enforcement work git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@105193 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 From 2a398aab124126df06cf787fa474f68527d1f7fe Mon Sep 17 00:00:00 2001 From: Roy Wetherall Date: Mon, 1 Jun 2015 08:20:12 +0000 Subject: [PATCH 02/33] First pass at classification interceptor git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@105194 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 20 +- .../org_alfresco_module_rm/module-context.xml | 8 +- .../rm-action-context.xml | 1 + .../capability/RMActionProxyFactoryBean.java | 27 ++- .../ClassificationLevelManager.java | 10 +- .../ClassificationServiceBootstrap.java | 8 + .../ClassificationServiceImpl.java | 1 + .../SecurityClearanceServiceImpl.java | 3 +- .../ClassificationMethodInterceptor.java | 180 ++++++++++++++++++ ...icationMethodInterceptorPostProcessor.java | 82 ++++++++ .../util/AlfrescoTransactionSupport.java | 9 + .../EnforceClassificationTest.java | 111 +++++++++++ 12 files changed, 445 insertions(+), 15 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index c07153d8e1..0e94fc654b 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -1,7 +1,12 @@ - - - + @@ -27,6 +32,15 @@ + + + + + + + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml index 2a54c34b40..2a5c2b8cfd 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml @@ -1,7 +1,9 @@ - - + @@ -252,6 +254,6 @@ - + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml index 8aeaa34a0a..f3d6f08996 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/rm-action-context.xml @@ -149,6 +149,7 @@ + org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementAction diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMActionProxyFactoryBean.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMActionProxyFactoryBean.java index ed2a64e6e3..e063372f61 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMActionProxyFactoryBean.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMActionProxyFactoryBean.java @@ -23,6 +23,8 @@ import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementAction import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService; import org.alfresco.repo.action.RuntimeActionService; import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.transaction.TransactionService; import org.springframework.aop.framework.ProxyFactoryBean; /** @@ -42,6 +44,9 @@ public class RMActionProxyFactoryBean extends ProxyFactoryBean /** Records management audit service */ protected RecordsManagementAuditService recordsManagementAuditService; + + /** transaction service */ + private TransactionService transactionService; /** * Set action service @@ -72,6 +77,15 @@ public class RMActionProxyFactoryBean extends ProxyFactoryBean { this.recordsManagementAuditService = recordsManagementAuditService; } + + /** + * @param transactionService transaction service + * @since 3.0.a + */ + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } /** * Register the action @@ -82,9 +96,16 @@ public class RMActionProxyFactoryBean extends ProxyFactoryBean { public Void doWork() { - RecordsManagementAction action = (RecordsManagementAction)getObject(); - recordsManagementActionService.register(action); - + transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + RecordsManagementAction action = (RecordsManagementAction)getObject(); + recordsManagementActionService.register(action); + return null; + } + }); + return null; } }, AuthenticationUtil.getSystemUserName()); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationLevelManager.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationLevelManager.java index 26f92dce3a..19dd97874a 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationLevelManager.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationLevelManager.java @@ -31,11 +31,11 @@ import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationS */ public class ClassificationLevelManager { - /** Unclassified classification level */ - public static final String UNCLASSIFIED_ID = "Unclassified"; - private static final String UNCLASSIFIED_MSG = "rm.classification.unclassified"; - public static final ClassificationLevel UNCLASSIFIED = new ClassificationLevel(UNCLASSIFIED_ID, UNCLASSIFIED_MSG); - + /** Unclassified classification level */ + public static final String UNCLASSIFIED_ID = "Unclassified"; + private static final String UNCLASSIFIED_MSG = "rm.classification.unclassified"; + public static final ClassificationLevel UNCLASSIFIED = new ClassificationLevel(UNCLASSIFIED_ID, UNCLASSIFIED_MSG); + /** An immutable list of classification levels ordered from most to least secure. */ private ImmutableList classificationLevels; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceBootstrap.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceBootstrap.java index 42c3782823..6af2762c14 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceBootstrap.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceBootstrap.java @@ -56,6 +56,8 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem /** The clearance levels currently configured in this server. */ private ClearanceLevelManager clearanceLevelManager = new ClearanceLevelManager(); private ClassificationServiceDAO classificationServiceDAO; + + private boolean isInitialised = false; public ClassificationServiceBootstrap(AuthenticationUtil authUtil, TransactionService txService, @@ -77,6 +79,11 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem public ClassificationLevelManager getClassificationLevelManager() { return classificationLevelManager; } public ClassificationReasonManager getClassificationReasonManager() { return classificationReasonManager; } public ClearanceLevelManager getClearanceLevelManager() { return clearanceLevelManager; } + + public boolean isInitialised() + { + return isInitialised; + } @Override public void onBootstrap(ApplicationEvent event) { @@ -91,6 +98,7 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem initConfiguredClassificationLevels(); initConfiguredClassificationReasons(); initConfiguredClearanceLevels(classificationLevelManager.getClassificationLevels()); + isInitialised = true; return null; } }; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java index ec2ce30787..a5af2717c4 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java @@ -55,6 +55,7 @@ public class ClassificationServiceImpl extends ServiceBaseImpl } /** + * Create a list containing all classification levels up to and including the supplied level. * * @param allLevels The list of all the classification levels starting with the highest security. diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java index 076d0ba220..afe9499269 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java @@ -41,7 +41,7 @@ import org.alfresco.util.ParameterCheck; * @since 3.0 */ public class SecurityClearanceServiceImpl extends ServiceBaseImpl implements SecurityClearanceService -{ +{ /** The clearance levels currently configured in this server. */ private ClearanceLevelManager clearanceManager; /** The object containing the {@link ClassificationLevel}s in the system. */ @@ -50,6 +50,7 @@ public class SecurityClearanceServiceImpl extends ServiceBaseImpl implements Sec private ClassificationServiceBootstrap classificationServiceBootstrap; private ClassificationLevelComparator classificationLevelComparator; + /** dependency setters */ public void setClearanceManager(ClearanceLevelManager clearanceManager) { this.clearanceManager = clearanceManager; } public void setClassificationLevelManager(ClassificationLevelManager classificationLevelManager) { this.classificationLevelManager = classificationLevelManager; } public void setPersonService(PersonService service) { this.personService = service; } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java new file mode 100644 index 0000000000..565727e284 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java @@ -0,0 +1,180 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor; + +import java.lang.reflect.Method; + +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.AlfrescoTransactionSupport; +import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.GUID; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * Classification method interceptor + * + * @author Roy Wetherall + * @since 3.0 + */ +public class ClassificationMethodInterceptor implements MethodInterceptor, ApplicationContextAware +{ + private static final String KEY_PROCESSING = GUID.generate(); + + /** application context */ + private ApplicationContext applicationContext; + + /** + * @param applicationContext application context + * @throws BeansException + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + this.applicationContext = applicationContext; + } + + protected AuthenticationUtil getAuthenticationUtil() + { + return (AuthenticationUtil)applicationContext.getBean("rm.authenticationUtil"); + } + + /** + * @return {@link ContentClassificationService} content classification service + */ + protected ContentClassificationService getContentClassificaitonService() + { + return (ContentClassificationService)applicationContext.getBean("contentClassificationService"); + } + + protected AlfrescoTransactionSupport getAlfrescoTransactionSupport() + { + return (AlfrescoTransactionSupport)applicationContext.getBean("rm.alfrescoTransactionSupport"); + } + + protected RetryingTransactionHelper getRetryingTransactionHelper() + { + return ((TransactionService)applicationContext.getBean("transactionService")).getRetryingTransactionHelper(); + } + + protected ClassificationServiceBootstrap getClassificationServiceBootstrap() + { + return (ClassificationServiceBootstrap)applicationContext.getBean("classificationServiceBootstrap"); + } + + protected NodeService getNodeService() + { + return (NodeService)applicationContext.getBean("dbNodeService"); + } + + /** + * Check that the current user is cleared to see the items passed as parameters to the current + * method invocation. + * + * @param invocation method invocation + */ + @SuppressWarnings("rawtypes") + public void checkClassification(MethodInvocation invocation) + { + // do in transaction + getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + // ensure classification service has been bootstrapped + if (getClassificationServiceBootstrap().isInitialised()) + { + // check that we are not already processing a classification check + Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING); + if (value == null) + { + // check that we have an authenticated user and that they aren't "system" + if (getAuthenticationUtil().getFullyAuthenticatedUser() != null && + !getAuthenticationUtil().isRunAsUserTheSystemUser()) + { + Method method = invocation.getMethod(); + Class[] params = method.getParameterTypes(); + + int position = 0; + for (Class param : params) + { + // if the param is a node reference + if (NodeRef.class.isAssignableFrom(param)) + { + // mark the transaction as processing a classification check + getAlfrescoTransactionSupport().bindResource(KEY_PROCESSING, Boolean.TRUE); + try + { + // get the value of the parameter + NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position]; + + // if node exists then see if the current user has clearance + if (getNodeService().exists(testNodeRef) && + !getContentClassificaitonService().hasClearance(testNodeRef)) + { + // throw exception + throw new AccessDeniedException("You do not have clearance!"); + } + } + finally + { + // clear the transaction as processed a classification check + getAlfrescoTransactionSupport().unbindResource(KEY_PROCESSING); + } + } + + position++; + } + } + } + } + + return null; + } + }, true); + } + + /** + * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + */ + @Override + public Object invoke(MethodInvocation invocation) throws Throwable + { + // pre method invocation check + checkClassification(invocation); + + // method proceed + Object result = invocation.proceed(); + + // post method invocation processing + // TODO + + return result; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java new file mode 100644 index 0000000000..010d2e98cd --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java @@ -0,0 +1,82 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor; + +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.RuntimeBeanNameReference; +import org.springframework.beans.factory.support.ManagedList; + +/** + * Classification method interceptor bean factory post processor. + *

+ * Bean factory post processor that inspects available beans and adds the classification method interceptor + * to all public services. + * + * @author Roy Wetherall + * @since 3.0.a + */ +public class ClassificationMethodInterceptorPostProcessor implements BeanFactoryPostProcessor +{ + private static final String PROP_INTERCEPTOR_NAMES = "interceptorNames"; + private static final String TYPE_PROXY_FACTORY_BEAN = "ProxyFactoryBean"; + private static final String POSTFIX_SERVICE = "Service"; + private static final String BEAN_NAME_CLASSIFICATION_METHOD_INTERCEPTOR = "classificationMethodInterceptor"; + + /** + * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) + */ + @SuppressWarnings("unchecked") + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException + { + // get all bean definition names + String beans[] = beanFactory.getBeanDefinitionNames(); + for (String bean : beans) + { + // get bean definition + BeanDefinition beanDefinition = beanFactory.getBeanDefinition(bean); + + // only modify proxy factory beans that follow the public service naming postfix convention + if (beanDefinition.getBeanClassName() != null && + beanDefinition.getBeanClassName().endsWith(TYPE_PROXY_FACTORY_BEAN) && + bean.endsWith(POSTFIX_SERVICE)) + { + // get the property values for the bean definition + MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); + if (propertyValues.contains(PROP_INTERCEPTOR_NAMES)) + { + // get the current list of interceptor names + PropertyValue value = propertyValues.getPropertyValue(PROP_INTERCEPTOR_NAMES); + ManagedList list = (ManagedList)value.getValue(); + if (!list.isEmpty()) + { + // add reference to classification method interceptor + RuntimeBeanNameReference beanReference = new RuntimeBeanNameReference(BEAN_NAME_CLASSIFICATION_METHOD_INTERCEPTOR); + list.add(beanReference); + } + } + } + } + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/AlfrescoTransactionSupport.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/AlfrescoTransactionSupport.java index d2f9796300..4e30188a60 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/AlfrescoTransactionSupport.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/util/AlfrescoTransactionSupport.java @@ -42,4 +42,13 @@ public class AlfrescoTransactionSupport { org.alfresco.repo.transaction.AlfrescoTransactionSupport.unbindResource(key); } + + /** + * @see org.alfresco.repo.transaction.AlfrescoTransactionSupport#getResource(Object) + * @since 3.0.a + */ + public Object getResource(Object key) + { + return org.alfresco.repo.transaction.AlfrescoTransactionSupport.getResource(key); + } } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java new file mode 100644 index 0000000000..2898124ee5 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java @@ -0,0 +1,111 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification; + +import java.util.Collections; +import java.util.List; + +import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; +import org.alfresco.module.org_alfresco_module_rm.classification.SecurityClearanceService; +import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.repo.security.permissions.impl.model.PermissionModel; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.util.GUID; + +/** + * Enforce classification integration test + * + * @author Roy Wetherall + * @since 3.0 + */ +public class EnforceClassificationTest extends BaseRMTestCase +{ + /** test data */ + private static final String CLASSIFICATION_LEVEL1 = "level1"; + private static final String CLASSIFICATION_LEVEL2 = "level2"; + private static final String CLASSIFICATION_LEVEL3 = "level3"; + private static final String CLASSIFICATION_LEVEL4 = "level4"; + + private static final String CLASSIFICATION_REASON = "Test Reason 1"; + private static final String CLASSIFICATION_AUTHORITY = "classification.authority"; + private static final String RECORD_NAME = "recordname.txt"; + + private ContentClassificationService contentClassificationService; + + @Override + protected void initServices() + { + super.initServices(); + contentClassificationService = (ContentClassificationService)applicationContext.getBean("contentClassificationService"); + } + + @Override + protected boolean isCollaborationSiteTest() + { + return true; + } + + /** + * + */ + public void testUserNotClearedDocument() throws Exception + { + doBehaviourDrivenTest(new BehaviourDrivenTest(AccessDeniedException.class) + { + private String userName; + + public void given() throws Exception + { + // create test person and assign read permission to document + userName = GUID.generate(); + createPerson(userName, true); + permissionService.setPermission(dmDocument, userName , PermissionService.READ, true); + + // assign security clearance + securityClearanceService.setUserSecurityClearance(userName, CLASSIFICATION_LEVEL3); + + // classify document + contentClassificationService.classifyContent( + CLASSIFICATION_LEVEL1, + CLASSIFICATION_AUTHORITY, + Collections.singleton(CLASSIFICATION_REASON), + dmDocument); + + } + + public void when() throws Exception + { + AuthenticationUtil.runAs(new RunAsWork() + { + public Void doWork() throws Exception + { + nodeService.getAspects(dmDocument); + + return null; + } + }, userName); + } + }); + } +} From 557782857c3ca6053c0e244b76861f87f69db9d3 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Mon, 1 Jun 2015 16:46:59 +0000 Subject: [PATCH 03/33] Fixed compilation issue git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@105294 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../ClassificationMethodInterceptor.java | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java index 565727e284..fd477562b4 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java @@ -39,17 +39,17 @@ import org.springframework.context.ApplicationContextAware; /** * Classification method interceptor - * + * * @author Roy Wetherall * @since 3.0 */ -public class ClassificationMethodInterceptor implements MethodInterceptor, ApplicationContextAware +public class ClassificationMethodInterceptor implements MethodInterceptor, ApplicationContextAware { private static final String KEY_PROCESSING = GUID.generate(); - + /** application context */ private ApplicationContext applicationContext; - + /** * @param applicationContext application context * @throws BeansException @@ -59,12 +59,12 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli { this.applicationContext = applicationContext; } - + protected AuthenticationUtil getAuthenticationUtil() { return (AuthenticationUtil)applicationContext.getBean("rm.authenticationUtil"); } - + /** * @return {@link ContentClassificationService} content classification service */ @@ -72,22 +72,22 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli { return (ContentClassificationService)applicationContext.getBean("contentClassificationService"); } - + protected AlfrescoTransactionSupport getAlfrescoTransactionSupport() { return (AlfrescoTransactionSupport)applicationContext.getBean("rm.alfrescoTransactionSupport"); - } - + } + protected RetryingTransactionHelper getRetryingTransactionHelper() { return ((TransactionService)applicationContext.getBean("transactionService")).getRetryingTransactionHelper(); } - + protected ClassificationServiceBootstrap getClassificationServiceBootstrap() { return (ClassificationServiceBootstrap)applicationContext.getBean("classificationServiceBootstrap"); } - + protected NodeService getNodeService() { return (NodeService)applicationContext.getBean("dbNodeService"); @@ -96,31 +96,31 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli /** * Check that the current user is cleared to see the items passed as parameters to the current * method invocation. - * + * * @param invocation method invocation */ @SuppressWarnings("rawtypes") - public void checkClassification(MethodInvocation invocation) - { + public void checkClassification(final MethodInvocation invocation) + { // do in transaction getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { public Void execute() throws Throwable - { + { // ensure classification service has been bootstrapped if (getClassificationServiceBootstrap().isInitialised()) { // check that we are not already processing a classification check - Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING); + Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING); if (value == null) - { + { // check that we have an authenticated user and that they aren't "system" - if (getAuthenticationUtil().getFullyAuthenticatedUser() != null && + if (getAuthenticationUtil().getFullyAuthenticatedUser() != null && !getAuthenticationUtil().isRunAsUserTheSystemUser()) { Method method = invocation.getMethod(); Class[] params = method.getParameterTypes(); - + int position = 0; for (Class param : params) { @@ -133,7 +133,7 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli { // get the value of the parameter NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position]; - + // if node exists then see if the current user has clearance if (getNodeService().exists(testNodeRef) && !getContentClassificaitonService().hasClearance(testNodeRef)) @@ -148,13 +148,13 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli getAlfrescoTransactionSupport().unbindResource(KEY_PROCESSING); } } - + position++; } } } } - + return null; } }, true); @@ -168,13 +168,13 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli { // pre method invocation check checkClassification(invocation); - + // method proceed Object result = invocation.proceed(); - + // post method invocation processing // TODO - + return result; } } From bff94ee86346b733f89175e0d770fd5bb992f940 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Fri, 5 Jun 2015 08:51:17 +0000 Subject: [PATCH 04/33] RM-2129 (Check classification before method execution) +review RM-69 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@105565 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../ClassificationMethodInterceptor.java | 136 +++++++++++------- 1 file changed, 84 insertions(+), 52 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java index fd477562b4..fbd3943177 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java @@ -18,8 +18,11 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor; +import static org.codehaus.plexus.util.StringUtils.isNotBlank; + import java.lang.reflect.Method; +import org.alfresco.model.ContentModel; 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.AlfrescoTransactionSupport; @@ -27,6 +30,7 @@ import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.transaction.TransactionService; @@ -50,10 +54,10 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli /** application context */ private ApplicationContext applicationContext; - /** - * @param applicationContext application context - * @throws BeansException - */ + /** + * @param applicationContext application context + * @throws BeansException + */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { @@ -93,6 +97,11 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli return (NodeService)applicationContext.getBean("dbNodeService"); } + protected DictionaryService getDictionaryService() + { + return (DictionaryService)applicationContext.getBean("dictionaryService"); + } + /** * Check that the current user is cleared to see the items passed as parameters to the current * method invocation. @@ -100,10 +109,10 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli * @param invocation method invocation */ @SuppressWarnings("rawtypes") - public void checkClassification(final MethodInvocation invocation) - { - // do in transaction - getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + public void checkClassification(final MethodInvocation invocation) + { + // do in transaction + getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { public Void execute() throws Throwable { @@ -111,69 +120,92 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli if (getClassificationServiceBootstrap().isInitialised()) { // check that we are not already processing a classification check - Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING); - if (value == null) - { - // check that we have an authenticated user and that they aren't "system" - if (getAuthenticationUtil().getFullyAuthenticatedUser() != null && - !getAuthenticationUtil().isRunAsUserTheSystemUser()) - { - Method method = invocation.getMethod(); - Class[] params = method.getParameterTypes(); + Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING); + if (value == null) + { + Method method = invocation.getMethod(); + Class[] params = method.getParameterTypes(); - int position = 0; - for (Class param : params) + int position = 0; + for (Class param : params) + { + // if the param is a node reference + if (NodeRef.class.isAssignableFrom(param)) { - // if the param is a node reference - if (NodeRef.class.isAssignableFrom(param)) + // mark the transaction as processing a classification check + getAlfrescoTransactionSupport().bindResource(KEY_PROCESSING, Boolean.TRUE); + try { - // mark the transaction as processing a classification check - getAlfrescoTransactionSupport().bindResource(KEY_PROCESSING, Boolean.TRUE); - try - { - // get the value of the parameter - NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position]; + // get the value of the parameter + NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position]; - // if node exists then see if the current user has clearance - if (getNodeService().exists(testNodeRef) && - !getContentClassificaitonService().hasClearance(testNodeRef)) - { - // throw exception - throw new AccessDeniedException("You do not have clearance!"); - } - } - finally - { - // clear the transaction as processed a classification check - getAlfrescoTransactionSupport().unbindResource(KEY_PROCESSING); - } + // if node exists then see if the current user has clearance + checkNode(testNodeRef); + } + finally + { + // clear the transaction as processed a classification check + getAlfrescoTransactionSupport().unbindResource(KEY_PROCESSING); } - - position++; } - } - } + + position++; + } + } } return null; } }, true); - } + } - /** - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) - */ + private boolean validUser() + { + boolean result = false; + + // check that we have an authenticated user and that they aren't "system" + if (isNotBlank(getAuthenticationUtil().getFullyAuthenticatedUser()) && + !getAuthenticationUtil().isRunAsUserTheSystemUser()) + { + result = true; + } + + return result; + } + + private void checkNode(NodeRef testNodeRef) + { + if (getNodeService().exists(testNodeRef) && + getDictionaryService().isSubClass(getNodeService().getType(testNodeRef), ContentModel.TYPE_CONTENT) && + !getContentClassificaitonService().hasClearance(testNodeRef)) + { + // throw exception + throw new AccessDeniedException("You do not have clearance!"); + } + } + + /** + * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + */ @Override public Object invoke(MethodInvocation invocation) throws Throwable { - // pre method invocation check - checkClassification(invocation); + boolean isValidUser = validUser(); + + if (isValidUser) + { + // pre method invocation check + checkClassification(invocation); + } // method proceed Object result = invocation.proceed(); - // post method invocation processing - // TODO + if (isValidUser) + { + // post method invocation processing + // TODO + } return result; } From aa746dd474cd84c41c4f37caf16ba194066a0ec7 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Thu, 11 Jun 2015 09:37:24 +0000 Subject: [PATCH 05/33] RM-2130 (Check classification after method execution, filtering results where appropriate) * Initial (early) commit to get feedback from the review * The "check" method will be changed later +review RM @rwetherall git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@105923 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 40 ++++- .../ClassificationMethodInterceptor.java | 45 ++++- ...ationRefPostMethodInvocationProcessor.java | 61 +++++++ .../BasePostMethodInvocationProcessor.java | 157 ++++++++++++++++++ ...ationRefPostMethodInvocationProcessor.java | 61 +++++++ .../NodeRefPostMethodInvocationProcessor.java | 54 ++++++ 6 files changed, 402 insertions(+), 16 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index 0e94fc654b..4b804025ee 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -1,11 +1,11 @@ @@ -32,16 +32,40 @@ - + - - - + + + + + + + + + + + + + + + + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java index fbd3943177..338c5ea278 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java @@ -18,13 +18,16 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor; +import static org.alfresco.model.ContentModel.TYPE_CONTENT; import static org.codehaus.plexus.util.StringUtils.isNotBlank; import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; -import org.alfresco.model.ContentModel; 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.classification.interceptor.processor.BasePostMethodInvocationProcessor; import org.alfresco.module.org_alfresco_module_rm.util.AlfrescoTransactionSupport; import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; import org.alfresco.repo.security.permissions.AccessDeniedException; @@ -37,6 +40,7 @@ import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.GUID; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.apache.log4j.Logger; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -49,6 +53,12 @@ import org.springframework.context.ApplicationContextAware; */ public class ClassificationMethodInterceptor implements MethodInterceptor, ApplicationContextAware { + /** Logger */ + private static Logger LOG = Logger.getLogger(ClassificationMethodInterceptor.class); + + /** Post method invocation processors */ + private Map, BasePostMethodInvocationProcessor> processors = new HashMap, BasePostMethodInvocationProcessor>(); + private static final String KEY_PROCESSING = GUID.generate(); /** application context */ @@ -72,7 +82,7 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli /** * @return {@link ContentClassificationService} content classification service */ - protected ContentClassificationService getContentClassificaitonService() + protected ContentClassificationService getContentClassificationService() { return (ContentClassificationService)applicationContext.getBean("contentClassificationService"); } @@ -102,6 +112,16 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli return (DictionaryService)applicationContext.getBean("dictionaryService"); } + /** + * Registers the post method invocation processors + * + * @param object The object to register + */ + public void register(BasePostMethodInvocationProcessor object) + { + processors.put(object.getClassName(), object); + } + /** * Check that the current user is cleared to see the items passed as parameters to the current * method invocation. @@ -176,8 +196,8 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli private void checkNode(NodeRef testNodeRef) { if (getNodeService().exists(testNodeRef) && - getDictionaryService().isSubClass(getNodeService().getType(testNodeRef), ContentModel.TYPE_CONTENT) && - !getContentClassificaitonService().hasClearance(testNodeRef)) + getDictionaryService().isSubClass(getNodeService().getType(testNodeRef), TYPE_CONTENT) && + !getContentClassificationService().hasClearance(testNodeRef)) { // throw exception throw new AccessDeniedException("You do not have clearance!"); @@ -192,19 +212,28 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli { boolean isValidUser = validUser(); + // pre method invocation check if (isValidUser) { - // pre method invocation check checkClassification(invocation); } // method proceed Object result = invocation.proceed(); - if (isValidUser) + // post method invocation processing + if (isValidUser && result != null) { - // post method invocation processing - // TODO + Class clazz = result.getClass(); + BasePostMethodInvocationProcessor processor = processors.get(clazz); + if (processor != null) + { + processor.process(result); + } + else + { + LOG.warn("No post method invocation processor found for '" + clazz + "'."); + } } return result; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..85b5243636 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java @@ -0,0 +1,61 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.alfresco.util.ParameterCheck.mandatory; + +import org.alfresco.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * AssociationRef Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class AssociationRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + public Class getClassName() + { + return AssociationRef.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @Override + public T process(T object) + { + mandatory("object", object); + + AssociationRef associationRef = ((AssociationRef) object); + + NodeRef sourceRef = associationRef.getSourceRef(); + check(sourceRef); + + NodeRef targetRef = associationRef.getTargetRef(); + check(targetRef); + + return object; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java new file mode 100644 index 0000000000..f66d0d0b94 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -0,0 +1,157 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; +import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; + +/** + * Base class for post method invocation processors + * + * @author Tuna Aksoy + * @since 3.0 + */ +public abstract class BasePostMethodInvocationProcessor +{ + /** Classification method interceptor */ + private ClassificationMethodInterceptor classificationMethodInterceptor; + + /** Node service */ + private NodeService nodeService; + + /** Dictionary service */ + private DictionaryService dictionaryService; + + /** Content classification service */ + private ContentClassificationService contentClassificationService; + + /** + * @return the classificationMethodInterceptor + */ + protected ClassificationMethodInterceptor getClassificationMethodInterceptor() + { + return this.classificationMethodInterceptor; + } + + /** + * @return the nodeService + */ + protected NodeService getNodeService() + { + return this.nodeService; + } + + /** + * @return the dictionaryService + */ + protected DictionaryService getDictionaryService() + { + return this.dictionaryService; + } + + /** + * @return the contentClassificationService + */ + protected ContentClassificationService getContentClassificationService() + { + return this.contentClassificationService; + } + + /** + * @param classificationMethodInterceptor the classificationMethodInterceptor to set + */ + public void setClassificationMethodInterceptor(ClassificationMethodInterceptor classificationMethodInterceptor) + { + this.classificationMethodInterceptor = classificationMethodInterceptor; + } + + /** + * @param nodeService the nodeService to set + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * @param dictionaryService the dictionaryService to set + */ + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + /** + * @param contentClassificationService the contentClassificationService to set + */ + public void setContentClassificationService(ContentClassificationService contentClassificationService) + { + this.contentClassificationService = contentClassificationService; + } + + /** + * Performs checks on the given object and throws exception if not all checks pass + * + * @param object The object to check + * @return The given object + */ + public abstract T process(T object); + + /** + * Gets the class name + * + * @return The class name + */ + public abstract Class getClassName(); + + /** + * Registers the post method invocation processors + */ + public void register() + { + getClassificationMethodInterceptor().register(this); + } + + /** + * Performs checks on the given node: + * + *

    + *
  • Does the node exist
  • + *
  • Is it a content
  • + *
  • Is the logged in user cleared to see the it.
  • + *
+ * + * @param nodeRef Node reference + */ + protected void check(NodeRef nodeRef) + { + if (getNodeService().exists(nodeRef) && + getDictionaryService().isSubClass(getNodeService().getType(nodeRef), ContentModel.TYPE_CONTENT) && + !getContentClassificationService().hasClearance(nodeRef)) + { + // throw exception + throw new AccessDeniedException("You do not have clearance!"); + } + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..c868c34ea2 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java @@ -0,0 +1,61 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.alfresco.util.ParameterCheck.mandatory; + +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * ChildAssociationRef Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class ChildAssociationRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + public Class getClassName() + { + return ChildAssociationRef.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @Override + public T process(T object) + { + mandatory("object", object); + + ChildAssociationRef childAssociationRef = ((ChildAssociationRef) object); + + NodeRef childRef = childAssociationRef.getChildRef(); + check(childRef); + + NodeRef parentRef = childAssociationRef.getParentRef(); + check(parentRef); + + return object; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..8d78d7e4c6 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java @@ -0,0 +1,54 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.alfresco.util.ParameterCheck.mandatory; + +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * NodeRef Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class NodeRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + public Class getClassName() + { + return NodeRef.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @Override + public T process(T object) + { + mandatory("object", object); + + check(((NodeRef) object)); + + return object; + } +} From b83bc89275898f887721dbc43113c1a19c48c5d3 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sun, 14 Jun 2015 21:05:58 +0000 Subject: [PATCH 06/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106103 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 19 ++ .../documentlibrary-v2/rm-doclist.lib.js | 7 +- .../ClassificationMethodInterceptor.java | 73 +++++-- ...ationRefPostMethodInvocationProcessor.java | 6 +- .../BasePostMethodInvocationProcessor.java | 40 ++-- ...ationRefPostMethodInvocationProcessor.java | 6 +- ...llectionPostMethodInvocationProcessor.java | 193 ++++++++++++++++++ .../ListPostMethodInvocationProcessor.java | 49 +++++ .../NodeRefPostMethodInvocationProcessor.java | 4 +- .../SetPostMethodInvocationProcessor.java | 49 +++++ 10 files changed, 398 insertions(+), 48 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index 4b804025ee..d2bb45a2c0 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -66,6 +66,25 @@ class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AssociationRefPostMethodInvocationProcessor">
+ + + + + + + + + + + + diff --git a/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js b/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js index 3fcdb888af..710eed6a2e 100644 --- a/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js +++ b/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js @@ -241,7 +241,12 @@ function rm_doclist_main() { // we have to check if we have read permission on the node parent as an error will be thrown if we try to // get the evaluated properties for a linked record whose parent we do not have read permissions for - var parentReadable = (node.parent != null && node.parent.isContainer && node.parent.hasPermission("ReadRecords")); + var parentReadable; + try + { + parentReadable = (node.parent != null && node.parent.isContainer && node.parent.hasPermission("ReadRecords")); + } + catch(e){} if (!parentReadable) continue; // Get evaluated properties. diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java index 338c5ea278..5783e3bd0d 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java @@ -25,12 +25,12 @@ import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; +import org.alfresco.jlan.server.filesys.AccessDeniedException; 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.classification.interceptor.processor.BasePostMethodInvocationProcessor; import org.alfresco.module.org_alfresco_module_rm.util.AlfrescoTransactionSupport; import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; -import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -129,13 +129,15 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli * @param invocation method invocation */ @SuppressWarnings("rawtypes") - public void checkClassification(final MethodInvocation invocation) + public NodeRef checkClassification(final MethodInvocation invocation) { // do in transaction - getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + return getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { - public Void execute() throws Throwable + public NodeRef execute() throws Throwable { + NodeRef result = null; + // ensure classification service has been bootstrapped if (getClassificationServiceBootstrap().isInitialised()) { @@ -160,7 +162,7 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position]; // if node exists then see if the current user has clearance - checkNode(testNodeRef); + result = checkNode(testNodeRef); } finally { @@ -174,12 +176,12 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli } } - return null; + return result; } }, true); } - private boolean validUser() + private boolean isUserValid() { boolean result = false; @@ -193,15 +195,20 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli return result; } - private void checkNode(NodeRef testNodeRef) + private NodeRef checkNode(NodeRef testNodeRef) throws AccessDeniedException { + NodeRef result = testNodeRef; + if (getNodeService().exists(testNodeRef) && getDictionaryService().isSubClass(getNodeService().getType(testNodeRef), TYPE_CONTENT) && !getContentClassificationService().hasClearance(testNodeRef)) { - // throw exception - throw new AccessDeniedException("You do not have clearance!"); + // FIXME + result = null; + //throw new AccessDeniedException("You do not have clearance!"); } + + return result; } /** @@ -210,29 +217,59 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli @Override public Object invoke(MethodInvocation invocation) throws Throwable { - boolean isValidUser = validUser(); + // FIXME + //NodeRef preInvocation = null; + Object postInvocation = null; + + boolean isUserValid = isUserValid(); // pre method invocation check - if (isValidUser) + if (isUserValid) { + // FIXME + //preInvocation = checkClassification(invocation); checkClassification(invocation); } // method proceed - Object result = invocation.proceed(); + postInvocation = invocation.proceed(); // post method invocation processing - if (isValidUser && result != null) + if (isUserValid && postInvocation != null) { - Class clazz = result.getClass(); - BasePostMethodInvocationProcessor processor = processors.get(clazz); + Class clazz = postInvocation.getClass(); + BasePostMethodInvocationProcessor processor = getProcessor(processors, clazz); + if (processor != null) { - processor.process(result); + postInvocation = processor.process(postInvocation); } else { - LOG.warn("No post method invocation processor found for '" + clazz + "'."); + LOG.debug("No post method invocation processor found for '" + clazz + "'."); + } + } + + return postInvocation; + } + + /** + * Gets the processor from the available processors + * + * @param processors Available processors + * @param clazz The runtime class of the post invocation object + * @return The suitable processor for the given class + */ + private BasePostMethodInvocationProcessor getProcessor(Map, BasePostMethodInvocationProcessor> processors, Class clazz) + { + BasePostMethodInvocationProcessor result = null; + + for (Map.Entry, BasePostMethodInvocationProcessor> processor : processors.entrySet()) + { + if (processor.getKey().isAssignableFrom(clazz)) + { + result = processor.getValue(); + break; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java index 85b5243636..e2cebd6317 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java @@ -51,11 +51,11 @@ public class AssociationRefPostMethodInvocationProcessor extends BasePostMethodI AssociationRef associationRef = ((AssociationRef) object); NodeRef sourceRef = associationRef.getSourceRef(); - check(sourceRef); + NodeRef filteredSource = filter(sourceRef); NodeRef targetRef = associationRef.getTargetRef(); - check(targetRef); + NodeRef filteredTarget = filter(targetRef); - return object; + return (filteredSource == null || filteredTarget == null) ? null : object; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java index f66d0d0b94..52af2f95b4 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -18,10 +18,10 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import org.alfresco.model.ContentModel; +import static org.alfresco.model.ContentModel.TYPE_CONTENT; + import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor; -import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -110,6 +110,13 @@ public abstract class BasePostMethodInvocationProcessor this.contentClassificationService = contentClassificationService; } + /** + * Gets the class name + * + * @return The class name + */ + public abstract Class getClassName(); + /** * Performs checks on the given object and throws exception if not all checks pass * @@ -118,13 +125,6 @@ public abstract class BasePostMethodInvocationProcessor */ public abstract T process(T object); - /** - * Gets the class name - * - * @return The class name - */ - public abstract Class getClassName(); - /** * Registers the post method invocation processors */ @@ -134,24 +134,24 @@ public abstract class BasePostMethodInvocationProcessor } /** - * Performs checks on the given node: - * - *
    - *
  • Does the node exist
  • - *
  • Is it a content
  • - *
  • Is the logged in user cleared to see the it.
  • - *
+ * Filters the node if the give node reference exist and it is a + * content but the logged in user is not cleared to see the it. * * @param nodeRef Node reference + * @return null if the give node reference has been + * filtered, the node reference itself otherwise */ - protected void check(NodeRef nodeRef) + protected NodeRef filter(NodeRef nodeRef) { + NodeRef filter = nodeRef; + if (getNodeService().exists(nodeRef) && - getDictionaryService().isSubClass(getNodeService().getType(nodeRef), ContentModel.TYPE_CONTENT) && + getDictionaryService().isSubClass(getNodeService().getType(nodeRef), TYPE_CONTENT) && !getContentClassificationService().hasClearance(nodeRef)) { - // throw exception - throw new AccessDeniedException("You do not have clearance!"); + filter = null; } + + return filter; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java index c868c34ea2..9fa6b263d0 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java @@ -51,11 +51,11 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends BasePostMe ChildAssociationRef childAssociationRef = ((ChildAssociationRef) object); NodeRef childRef = childAssociationRef.getChildRef(); - check(childRef); + NodeRef filteredChildRef = filter(childRef); NodeRef parentRef = childAssociationRef.getParentRef(); - check(parentRef); + NodeRef filteredParentRef = filter(parentRef); - return object; + return (filteredChildRef == null || filteredParentRef == null) ? null : object; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..b65bd326f2 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -0,0 +1,193 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.Collection; +import java.util.Iterator; + +import org.alfresco.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.collections.CollectionUtils; +import org.alfresco.util.collections.Filter; + +/** + * Collection Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public abstract class CollectionPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** Node ref post method invocation processor */ + private NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor; + + /** Association post method invocation processor */ + private AssociationRefPostMethodInvocationProcessor associationRefPostMethodInvocationProcessor; + + /** Child association post method invocation processor */ + private ChildAssociationRefPostMethodInvocationProcessor childAssociationRefPostMethodInvocationProcessor; + + /** + * @return the nodeRefPostMethodInvocationProcessor + */ + protected NodeRefPostMethodInvocationProcessor getNodeRefPostMethodInvocationProcessor() + { + return this.nodeRefPostMethodInvocationProcessor; + } + + /** + * @return the associationRefPostMethodInvocationProcessor + */ + protected AssociationRefPostMethodInvocationProcessor getAssociationRefPostMethodInvocationProcessor() + { + return this.associationRefPostMethodInvocationProcessor; + } + + /** + * @return the childAssociationRefPostMethodInvocationProcessor + */ + protected ChildAssociationRefPostMethodInvocationProcessor getChildAssociationRefPostMethodInvocationProcessor() + { + return this.childAssociationRefPostMethodInvocationProcessor; + } + + /** + * @param nodeRefPostMethodInvocationProcessor the nodeRefPostMethodInvocationProcessor to set + */ + public void setNodeRefPostMethodInvocationProcessor(NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor) + { + this.nodeRefPostMethodInvocationProcessor = nodeRefPostMethodInvocationProcessor; + } + + /** + * @param associationRefPostMethodInvocationProcessor the associationRefPostMethodInvocationProcessor to set + */ + public void setAssociationRefPostMethodInvocationProcessor(AssociationRefPostMethodInvocationProcessor associationRefPostMethodInvocationProcessor) + { + this.associationRefPostMethodInvocationProcessor = associationRefPostMethodInvocationProcessor; + } + + /** + * @param childAssociationRefPostMethodInvocationProcessor the childAssociationRefPostMethodInvocationProcessor to set + */ + public void setChildAssociationRefPostMethodInvocationProcessor(ChildAssociationRefPostMethodInvocationProcessor childAssociationRefPostMethodInvocationProcessor) + { + this.childAssociationRefPostMethodInvocationProcessor = childAssociationRefPostMethodInvocationProcessor; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public T process(T object) + { + Object result = object; + + Collection collection = ((Collection) object); + if (!collection.isEmpty()) + { + Iterator iterator = collection.iterator(); + if (iterator.hasNext()) + { + Class clazz = iterator.next().getClass(); + if (NodeRef.class.isAssignableFrom(clazz)) + { + result = processNodeRef(collection, iterator); + } + + if (AssociationRef.class.isAssignableFrom(clazz)) + { + result = processAssociationRef(collection, iterator); + } + + if (ChildAssociationRef.class.isAssignableFrom(clazz)) + { + result = processChildAssociationRef(collection, iterator); + } + } + } + + return (T) result; + } + + /** + * Processes a {@link NodeRef} collection + * + * @param collection The collection to process + * @return The processed collection + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Collection processNodeRef(Collection collection, Iterator iterator) + { + CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(NodeRef nodeRef) + { + return getNodeRefPostMethodInvocationProcessor().process(nodeRef) != null; + } + }); + + return collection; + } + + /** + * Processes a {@link AssociationRef} collection + * + * @param collection The collection to process + * @return The processed collection + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Collection processAssociationRef(Collection collection, Iterator iterator) + { + CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(AssociationRef associationRef) + { + return getAssociationRefPostMethodInvocationProcessor().process(associationRef) != null; + } + }); + + return collection; + } + + /** + * Processes a {@link ChildAssociationRef} collection + * + * @param collection The collection to process + * @return The processed collection + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Collection processChildAssociationRef(Collection collection, Iterator iterator) + { + CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(ChildAssociationRef childAssociationRef) + { + return getChildAssociationRefPostMethodInvocationProcessor().process(childAssociationRef) != null; + } + }); + + return collection; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..4962eada3f --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java @@ -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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.List; + +/** + * List Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class ListPostMethodInvocationProcessor extends CollectionPostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @SuppressWarnings("rawtypes") + @Override + public Class getClassName() + { + return List.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @Override + public T process(T object) + { + return super.process(object); + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java index 8d78d7e4c6..11654de8a5 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java @@ -47,8 +47,6 @@ public class NodeRefPostMethodInvocationProcessor extends BasePostMethodInvocati { mandatory("object", object); - check(((NodeRef) object)); - - return object; + return filter((NodeRef) object) == null ? null : object; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..6fb47e4516 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java @@ -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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.Set; + +/** + * Set Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class SetPostMethodInvocationProcessor extends CollectionPostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @SuppressWarnings("rawtypes") + @Override + public Class getClassName() + { + return Set.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @Override + public T process(T object) + { + return super.process(object); + } +} From f7ab449f794e63267aeb5734db94ccf1c756a40e Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sun, 14 Jun 2015 22:32:59 +0000 Subject: [PATCH 07/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106104 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 5 ++ ...llectionPostMethodInvocationProcessor.java | 12 +--- ...StoreRefPostMethodInvocationProcessor.java | 55 +++++++++++++++++++ 3 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index d2bb45a2c0..a222a6e7ac 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -56,6 +56,11 @@ class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.NodeRefPostMethodInvocationProcessor">
+ + + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java index b65bd326f2..4cb567777d 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -137,7 +137,7 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe @SuppressWarnings({ "rawtypes", "unchecked" }) private Collection processNodeRef(Collection collection, Iterator iterator) { - CollectionUtils.filter(collection, new Filter() + return CollectionUtils.filter(collection, new Filter() { @Override public Boolean apply(NodeRef nodeRef) @@ -145,8 +145,6 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe return getNodeRefPostMethodInvocationProcessor().process(nodeRef) != null; } }); - - return collection; } /** @@ -158,7 +156,7 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe @SuppressWarnings({ "rawtypes", "unchecked" }) private Collection processAssociationRef(Collection collection, Iterator iterator) { - CollectionUtils.filter(collection, new Filter() + return CollectionUtils.filter(collection, new Filter() { @Override public Boolean apply(AssociationRef associationRef) @@ -166,8 +164,6 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe return getAssociationRefPostMethodInvocationProcessor().process(associationRef) != null; } }); - - return collection; } /** @@ -179,7 +175,7 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe @SuppressWarnings({ "rawtypes", "unchecked" }) private Collection processChildAssociationRef(Collection collection, Iterator iterator) { - CollectionUtils.filter(collection, new Filter() + return CollectionUtils.filter(collection, new Filter() { @Override public Boolean apply(ChildAssociationRef childAssociationRef) @@ -187,7 +183,5 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe return getChildAssociationRefPostMethodInvocationProcessor().process(childAssociationRef) != null; } }); - - return collection; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..f0a387829d --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java @@ -0,0 +1,55 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.alfresco.util.ParameterCheck.mandatory; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; + +/** + * StoreRef Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class StoreRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + public Class getClassName() + { + return StoreRef.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @Override + public T process(T object) + { + mandatory("object", object); + + NodeRef nodeRef = getNodeService().getRootNode((StoreRef) object); + + return filter(nodeRef) == null ? null : object; + } +} From d975418fa6ff2e1c9691fb4d78821b1f43972065 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Mon, 15 Jun 2015 20:59:10 +0000 Subject: [PATCH 08/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106169 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 3 + .../ClassificationMethodInterceptor.java | 2 +- ...llectionPostMethodInvocationProcessor.java | 12 +- ...lassificationPostMethodInvocationTest.java | 148 ++++++++++++++++++ 4 files changed, 158 insertions(+), 7 deletions(-) create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ClassificationPostMethodInvocationTest.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index a222a6e7ac..d5316533ae 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -80,10 +80,13 @@ + + clazz = iterator.next().getClass(); if (NodeRef.class.isAssignableFrom(clazz)) { - result = processNodeRef(collection, iterator); + result = processNodeRef(collection); } if (AssociationRef.class.isAssignableFrom(clazz)) { - result = processAssociationRef(collection, iterator); + result = processAssociationRef(collection); } if (ChildAssociationRef.class.isAssignableFrom(clazz)) { - result = processChildAssociationRef(collection, iterator); + result = processChildAssociationRef(collection); } } } @@ -135,7 +135,7 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe * @return The processed collection */ @SuppressWarnings({ "rawtypes", "unchecked" }) - private Collection processNodeRef(Collection collection, Iterator iterator) + private Collection processNodeRef(Collection collection) { return CollectionUtils.filter(collection, new Filter() { @@ -154,7 +154,7 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe * @return The processed collection */ @SuppressWarnings({ "rawtypes", "unchecked" }) - private Collection processAssociationRef(Collection collection, Iterator iterator) + private Collection processAssociationRef(Collection collection) { return CollectionUtils.filter(collection, new Filter() { @@ -173,7 +173,7 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe * @return The processed collection */ @SuppressWarnings({ "rawtypes", "unchecked" }) - private Collection processChildAssociationRef(Collection collection, Iterator iterator) + private Collection processChildAssociationRef(Collection collection) { return CollectionUtils.filter(collection, new Filter() { diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ClassificationPostMethodInvocationTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ClassificationPostMethodInvocationTest.java new file mode 100644 index 0000000000..e1cd6d2be9 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ClassificationPostMethodInvocationTest.java @@ -0,0 +1,148 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification; + +import static com.google.common.collect.Lists.newArrayList; +import static com.google.common.collect.Sets.newHashSet; +import static org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService.ROLE_USER; +import static org.alfresco.util.GUID.generate; + +import java.util.List; +import java.util.Set; + +import org.alfresco.module.org_alfresco_module_rm.relationship.Relationship; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Classification Post Method Invocation Test + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class ClassificationPostMethodInvocationTest extends BaseRMTestCase +{ + private static final String LEVEL1 = "level1"; + private static final String LEVEL3 = "level3"; + private static final String REASON = "Test Reason 1"; + + public void testClassificationPostMethodInvocation() + { + /** + * Given a test user has been created + * and added to the RM user role + * and a category, a folder and two records have been created + * + * When the user has been granted filing permissions + * and the clearance level 3 for the test user has been set + * and one of the records has been classified as level 1 + * and a relationship between those two records has been created + * + * Then the admin user should see both records in the folder + * and the admin user should see in the relationship table + * (in the details page of the record) the other record + * + * and the test user should see only the unclassified record in the same folder + * and the relationship table should be empty. + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private String myUser; + private NodeRef category; + private NodeRef folder; + private NodeRef record1; + private NodeRef record2; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + myUser = generate(); + createPerson(myUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, myUser); + + category = filePlanService.createRecordCategory(filePlan, generate()); + folder = recordFolderService.createRecordFolder(category, generate()); + record1 = utils.createRecord(folder, generate()); + record2 = utils.createRecord(folder, generate()); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + filePlanPermissionService.setPermission(category, myUser, FILING); + securityClearanceService.setUserSecurityClearance(myUser, LEVEL3); + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + relationshipService.addRelationship(CUSTOM_REF_RENDITION.getLocalName(), record1, record2); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssocs = nodeService.getChildAssocs(folder); + assertEquals(2, childAssocs.size()); + + List recordList = newArrayList(record1, record2); + assertTrue(recordList.contains(childAssocs.get(0).getChildRef())); + assertTrue(recordList.contains(childAssocs.get(1).getChildRef())); + + Set relationshipsFrom = relationshipService.getRelationshipsFrom(record1); + assertEquals(1, relationshipsFrom.size()); + Relationship relationship1 = relationshipsFrom.iterator().next(); + assertEquals(record1, relationship1.getSource()); + assertEquals(record2, relationship1.getTarget()); + assertEquals(CUSTOM_REF_RENDITION.getLocalName(), relationship1.getUniqueName()); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssocs = nodeService.getChildAssocs(folder); + assertEquals(1, childAssocs.size()); + assertEquals(record2, childAssocs.get(0).getChildRef()); + + Set relationshipsFrom = relationshipService.getRelationshipsFrom(record2); + assertEquals(0, relationshipsFrom.size()); + + return null; + } + }, myUser); + } + }); + } +} From 4357be8ef4a062542347a1fd384219c8c8e114e4 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Tue, 16 Jun 2015 09:12:56 +0000 Subject: [PATCH 09/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106187 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../ContentClassificationServiceImpl.java | 26 ++++-- .../EnforceClassificationTest.java | 84 +++++++++---------- 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ContentClassificationServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ContentClassificationServiceImpl.java index 001ec25192..0fed7dbb5c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ContentClassificationServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ContentClassificationServiceImpl.java @@ -32,6 +32,8 @@ import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationS import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.LevelIdNotFound; import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel; import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -66,18 +68,24 @@ public class ContentClassificationServiceImpl extends ServiceBaseImpl implements } @Override - public ClassificationLevel getCurrentClassification(NodeRef nodeRef) + public ClassificationLevel getCurrentClassification(final NodeRef nodeRef) { - // by default everything is unclassified - ClassificationLevel result = ClassificationLevelManager.UNCLASSIFIED; - - if (nodeService.hasAspect(nodeRef, ASPECT_CLASSIFIED)) + return AuthenticationUtil.runAsSystem(new RunAsWork() { - String classificationId = (String)nodeService.getProperty(nodeRef, PROP_CURRENT_CLASSIFICATION); - result = levelManager.findLevelById(classificationId); - } + public ClassificationLevel doWork() throws Exception + { + // by default everything is unclassified + ClassificationLevel result = ClassificationLevelManager.UNCLASSIFIED; - return result; + if (nodeService.hasAspect(nodeRef, ASPECT_CLASSIFIED)) + { + String classificationId = (String)nodeService.getProperty(nodeRef, PROP_CURRENT_CLASSIFICATION); + result = levelManager.findLevelById(classificationId); + } + + return result; + } + }); }; @Override diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java index 2898124ee5..6ed0072c4c 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java @@ -46,66 +46,66 @@ public class EnforceClassificationTest extends BaseRMTestCase private static final String CLASSIFICATION_LEVEL2 = "level2"; private static final String CLASSIFICATION_LEVEL3 = "level3"; private static final String CLASSIFICATION_LEVEL4 = "level4"; - + private static final String CLASSIFICATION_REASON = "Test Reason 1"; private static final String CLASSIFICATION_AUTHORITY = "classification.authority"; private static final String RECORD_NAME = "recordname.txt"; - + private ContentClassificationService contentClassificationService; - + @Override protected void initServices() { super.initServices(); contentClassificationService = (ContentClassificationService)applicationContext.getBean("contentClassificationService"); } - + @Override protected boolean isCollaborationSiteTest() { return true; } - + /** - * + * */ public void testUserNotClearedDocument() throws Exception { - doBehaviourDrivenTest(new BehaviourDrivenTest(AccessDeniedException.class) - { - private String userName; - - public void given() throws Exception - { - // create test person and assign read permission to document - userName = GUID.generate(); - createPerson(userName, true); - permissionService.setPermission(dmDocument, userName , PermissionService.READ, true); - - // assign security clearance - securityClearanceService.setUserSecurityClearance(userName, CLASSIFICATION_LEVEL3); - - // classify document - contentClassificationService.classifyContent( - CLASSIFICATION_LEVEL1, - CLASSIFICATION_AUTHORITY, - Collections.singleton(CLASSIFICATION_REASON), - dmDocument); - - } - - public void when() throws Exception - { - AuthenticationUtil.runAs(new RunAsWork() - { - public Void doWork() throws Exception - { - nodeService.getAspects(dmDocument); - - return null; - } - }, userName); - } - }); +// doBehaviourDrivenTest(new BehaviourDrivenTest(AccessDeniedException.class) +// { +// private String userName; +// +// public void given() throws Exception +// { +// // create test person and assign read permission to document +// userName = GUID.generate(); +// createPerson(userName, true); +// permissionService.setPermission(dmDocument, userName , PermissionService.READ, true); +// +// // assign security clearance +// securityClearanceService.setUserSecurityClearance(userName, CLASSIFICATION_LEVEL3); +// +// // classify document +// contentClassificationService.classifyContent( +// CLASSIFICATION_LEVEL1, +// CLASSIFICATION_AUTHORITY, +// Collections.singleton(CLASSIFICATION_REASON), +// dmDocument); +// +// } +// +// public void when() throws Exception +// { +// AuthenticationUtil.runAs(new RunAsWork() +// { +// public Void doWork() throws Exception +// { +// nodeService.getAspects(dmDocument); +// +// return null; +// } +// }, userName); +// } +// }); } } From d79c6c21051edc1b2386aced4b0dbf107552fccd Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Tue, 16 Jun 2015 14:30:37 +0000 Subject: [PATCH 10/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106283 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- ...ationRefPostMethodInvocationProcessor.java | 1 + .../BasePostMethodInvocationProcessor.java | 14 +++ ...ationRefPostMethodInvocationProcessor.java | 1 + ...ficationPostMethodInvocationException.java | 80 ++++++++++++++ ...llectionPostMethodInvocationProcessor.java | 5 + .../NodeRefPostMethodInvocationProcessor.java | 1 + ...StoreRefPostMethodInvocationProcessor.java | 1 + ...PostMethodInvocationProcessorUnitTest.java | 104 ++++++++++++++++++ 8 files changed, 207 insertions(+) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ClassificationPostMethodInvocationException.java create mode 100644 rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java index e2cebd6317..841259c259 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java @@ -47,6 +47,7 @@ public class AssociationRefPostMethodInvocationProcessor extends BasePostMethodI public T process(T object) { mandatory("object", object); + checkObjectClass(object); AssociationRef associationRef = ((AssociationRef) object); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java index 52af2f95b4..9e64b16d7e 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -22,6 +22,7 @@ import static org.alfresco.model.ContentModel.TYPE_CONTENT; import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor; +import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ClassificationPostMethodInvocationException.NotSupportedClassTypeException; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -133,6 +134,19 @@ public abstract class BasePostMethodInvocationProcessor getClassificationMethodInterceptor().register(this); } + /** + * Checks if the given object's class is suitable for the processor + * + * @param object The object to process + */ + protected void checkObjectClass(Object object) + { + if (!(object.getClass().equals(getClassName()))) + { + throw new NotSupportedClassTypeException("The object is not an instance of '" + getClassName() + "' but '" + object.getClass() + "'."); + } + } + /** * Filters the node if the give node reference exist and it is a * content but the logged in user is not cleared to see the it. diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java index 9fa6b263d0..b71130584d 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java @@ -47,6 +47,7 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends BasePostMe public T process(T object) { mandatory("object", object); + checkObjectClass(object); ChildAssociationRef childAssociationRef = ((ChildAssociationRef) object); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ClassificationPostMethodInvocationException.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ClassificationPostMethodInvocationException.java new file mode 100644 index 0000000000..8bb41253e4 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ClassificationPostMethodInvocationException.java @@ -0,0 +1,80 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import org.alfresco.error.AlfrescoRuntimeException; + +/** + * Generic class for any runtime exception thrown within the {@link BasePostMethodInvocationProcessor} and subclasses. + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class ClassificationPostMethodInvocationException extends AlfrescoRuntimeException +{ + /** Serial version UID */ + private static final long serialVersionUID = 2614182915625548638L; + + /** + * Base classification post method invocation exception + * + * @param msgId The text which will be shown in the exception + */ + public ClassificationPostMethodInvocationException(String msgId) + { + super(msgId); + } + + /** + * Base classification post method invocation exception + * + * @param msgId The text which will be shown in the exception + * @param cause The cause of the exception + */ + public ClassificationPostMethodInvocationException(String msgId, Throwable cause) + { + super(msgId, cause); + } + + /** + * Represents a fatal error due to a wrong class type + */ + public static class NotSupportedClassTypeException extends ClassificationPostMethodInvocationException + { + /** Serial version UID */ + private static final long serialVersionUID = 7614080640030648878L; + + /** + * @param msgId The text which will be shown in the exception + */ + public NotSupportedClassTypeException(String msgId) + { + super(msgId); + } + + /** + * @param msgId The text which will be shown in the exception + * @param cause The cause of the exception + */ + public NotSupportedClassTypeException(String msgId, Throwable cause) + { + super(msgId, cause); + } + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java index 8011216549..68c8d6acc3 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -18,6 +18,8 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; +import static org.alfresco.util.ParameterCheck.mandatory; + import java.util.Collection; import java.util.Iterator; @@ -99,6 +101,9 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe @Override public T process(T object) { + mandatory("object", object); + checkObjectClass(object); + Object result = object; Collection collection = ((Collection) object); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java index 11654de8a5..679ebe034e 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java @@ -46,6 +46,7 @@ public class NodeRefPostMethodInvocationProcessor extends BasePostMethodInvocati public T process(T object) { mandatory("object", object); + checkObjectClass(object); return filter((NodeRef) object) == null ? null : object; } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java index f0a387829d..9a9476ca4c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java @@ -47,6 +47,7 @@ public class StoreRefPostMethodInvocationProcessor extends BasePostMethodInvocat public T process(T object) { mandatory("object", object); + checkObjectClass(object); NodeRef nodeRef = getNodeService().getRootNode((StoreRef) object); diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java new file mode 100644 index 0000000000..df7704687d --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java @@ -0,0 +1,104 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; +import static org.springframework.extensions.webscripts.GUID.generate; + +import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; +import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ClassificationPostMethodInvocationException.NotSupportedClassTypeException; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; +import org.alfresco.service.cmr.repository.NodeRef; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +/** + * NodeRef Post Method Invocation Processor Unit Test + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class NodeRefPostMethodInvocationProcessorUnitTest extends BaseUnitTest +{ + @InjectMocks private NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor; + @Mock private ContentClassificationService mockedContentClassificationService; + + @Test (expected = IllegalArgumentException.class) + public void testProcessingNull() + { + nodeRefPostMethodInvocationProcessor.process(null); + } + + @Test (expected = NotSupportedClassTypeException.class) + public void testProccessingAnotherClassType() + { + NodeRef nodeRef = generateNodeRef(); + nodeRefPostMethodInvocationProcessor.process(nodeRef.getStoreRef()); + } + + @Test + public void testProcessingNonExistingNode() + { + NodeRef nodeRef = new NodeRef(generate() + "://" + generate() + "/"); + + when(mockedNodeService.getType(nodeRef)).thenReturn(TYPE_CONTENT); + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef)).thenReturn(true); + + assertEquals(nodeRef, nodeRefPostMethodInvocationProcessor.process(nodeRef)); + } + + @Test + public void testProcessingNonContent() + { + NodeRef nodeRef = generateNodeRef(); + + when(mockedNodeService.getType(nodeRef)).thenReturn(TYPE_CONTENT); + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef), TYPE_CONTENT)).thenReturn(false); + when(mockedContentClassificationService.hasClearance(nodeRef)).thenReturn(true); + + assertEquals(nodeRef, nodeRefPostMethodInvocationProcessor.process(nodeRef)); + } + + @Test + public void testExistingNodeWithUserClearance() + { + NodeRef nodeRef = generateNodeRef(); + + when(mockedNodeService.getType(nodeRef)).thenReturn(TYPE_CONTENT); + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef)).thenReturn(true); + + assertEquals(nodeRef, nodeRefPostMethodInvocationProcessor.process(nodeRef)); + } + + @Test + public void testExistingNodeWithNoUserClearance() + { + NodeRef nodeRef = generateNodeRef(); + + when(mockedNodeService.getType(nodeRef)).thenReturn(TYPE_CONTENT); + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef)).thenReturn(false); + + assertEquals(null, nodeRefPostMethodInvocationProcessor.process(nodeRef)); + } +} From d8f71fba1828fc49e4bc2d44362887f774bc325d Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Tue, 16 Jun 2015 20:17:27 +0000 Subject: [PATCH 11/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106356 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 21 ++- .../ClassificationMethodInterceptor.java | 40 +---- ...AbstractPostMethodInvocationProcessor.java | 78 ++++++++++ ...ationRefPostMethodInvocationProcessor.java | 34 +++-- .../BasePostMethodInvocationProcessor.java | 36 ++++- ...ationRefPostMethodInvocationProcessor.java | 32 +++- ...llectionPostMethodInvocationProcessor.java | 138 +----------------- .../ListPostMethodInvocationProcessor.java | 2 +- .../NodeRefPostMethodInvocationProcessor.java | 33 ++++- ...PostMethodInvocationProcessorRegistry.java | 82 +++++++++++ .../SetPostMethodInvocationProcessor.java | 2 +- ...StoreRefPostMethodInvocationProcessor.java | 33 +++-- 12 files changed, 316 insertions(+), 215 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index d5316533ae..1a5c7bff55 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -42,6 +42,9 @@ + + @@ -49,25 +52,32 @@ + + + + @@ -75,9 +85,6 @@ abstract="true" parent="basePostMethodInvocationProcessor" class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.CollectionPostMethodInvocationProcessor"> - - - diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java index 235e681983..687b0ba392 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java @@ -22,13 +22,12 @@ import static org.alfresco.model.ContentModel.TYPE_CONTENT; import static org.codehaus.plexus.util.StringUtils.isNotBlank; import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; import org.alfresco.jlan.server.filesys.AccessDeniedException; 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.classification.interceptor.processor.BasePostMethodInvocationProcessor; +import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PostMethodInvocationProcessorRegistry; import org.alfresco.module.org_alfresco_module_rm.util.AlfrescoTransactionSupport; import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; @@ -56,9 +55,6 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli /** Logger */ private static Logger LOG = Logger.getLogger(ClassificationMethodInterceptor.class); - /** Post method invocation processors */ - private Map, BasePostMethodInvocationProcessor> processors = new HashMap, BasePostMethodInvocationProcessor>(); - private static final String KEY_PROCESSING = GUID.generate(); /** application context */ @@ -112,14 +108,9 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli return (DictionaryService)applicationContext.getBean("dictionaryService"); } - /** - * Registers the post method invocation processors - * - * @param object The object to register - */ - public void register(BasePostMethodInvocationProcessor object) + protected PostMethodInvocationProcessorRegistry getPostMethodInvocationProcessorRegistry() { - processors.put(object.getClassName(), object); + return (PostMethodInvocationProcessorRegistry)applicationContext.getBean("postMethodInvocationProcessorRegistry"); } /** @@ -238,7 +229,7 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli if (isUserValid && postInvocation != null) { Class clazz = postInvocation.getClass(); - BasePostMethodInvocationProcessor processor = getProcessor(processors, clazz); + BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessorRegistry().getProcessor(clazz); if (processor != null) { @@ -252,27 +243,4 @@ public class ClassificationMethodInterceptor implements MethodInterceptor, Appli return postInvocation; } - - /** - * Gets the processor from the available processors - * - * @param processors Available processors - * @param clazz The runtime class of the post invocation object - * @return The suitable processor for the given class - */ - private BasePostMethodInvocationProcessor getProcessor(Map, BasePostMethodInvocationProcessor> processors, Class clazz) - { - BasePostMethodInvocationProcessor result = null; - - for (Map.Entry, BasePostMethodInvocationProcessor> processor : processors.entrySet()) - { - if (processor.getKey().isAssignableFrom(clazz)) - { - result = processor.getValue(); - break; - } - } - - return result; - } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..022dbed21e --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java @@ -0,0 +1,78 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.alfresco.util.ParameterCheck.mandatory; + +import java.util.Collection; + +/** + * Abstract Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public abstract class AbstractPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * Abstract method to process a single element + * + * @param object The element to process + * @return Processed element + */ + protected abstract T processSingleElement(T object); + + /** + * Abstract method to process a collection + * + * @param collection The collection to process + * @return Processed collection + */ + @SuppressWarnings("rawtypes") + protected abstract Collection processCollection(Collection collection); + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public T process(T object) + { + mandatory("object", object); + + T result = null; + + if (isCollection(object)) + { + Collection collection = ((Collection) object); + if (!collection.isEmpty()) + { + checkObjectClass(collection.iterator().next()); + result = (T) processCollection(collection); + } + } + else + { + checkObjectClass(object); + result = (T) processSingleElement(object); + } + + return result; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java index 841259c259..e077e6558d 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java @@ -18,10 +18,12 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import static org.alfresco.util.ParameterCheck.mandatory; +import java.util.Collection; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.collections.CollectionUtils; +import org.alfresco.util.collections.Filter; /** * AssociationRef Post Method Invocation Processor @@ -29,27 +31,24 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Tuna Aksoy * @since 3.0 */ -public class AssociationRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +public class AssociationRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor { /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() */ @Override - public Class getClassName() + protected Class getClassName() { return AssociationRef.class; } /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) */ @Override - public T process(T object) + protected T processSingleElement(T object) { - mandatory("object", object); - checkObjectClass(object); - - AssociationRef associationRef = ((AssociationRef) object); + AssociationRef associationRef = (AssociationRef) object; NodeRef sourceRef = associationRef.getSourceRef(); NodeRef filteredSource = filter(sourceRef); @@ -59,4 +58,21 @@ public class AssociationRefPostMethodInvocationProcessor extends BasePostMethodI return (filteredSource == null || filteredTarget == null) ? null : object; } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processCollection(java.util.Collection) + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + protected Collection processCollection(Collection collection) + { + return CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(AssociationRef associationRef) + { + return processSingleElement(associationRef) != null; + } + }); + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java index 9e64b16d7e..9ada7a259e 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -20,6 +20,8 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.pr import static org.alfresco.model.ContentModel.TYPE_CONTENT; +import java.util.Collection; + import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ClassificationPostMethodInvocationException.NotSupportedClassTypeException; @@ -47,6 +49,9 @@ public abstract class BasePostMethodInvocationProcessor /** Content classification service */ private ContentClassificationService contentClassificationService; + /** Post method invocation processor registry */ + private PostMethodInvocationProcessorRegistry postMethodInvocationProcessorRegistry; + /** * @return the classificationMethodInterceptor */ @@ -79,6 +84,14 @@ public abstract class BasePostMethodInvocationProcessor return this.contentClassificationService; } + /** + * @return the postMethodInvocationProcessorRegistry + */ + protected PostMethodInvocationProcessorRegistry getPostMethodInvocationProcessorRegistry() + { + return this.postMethodInvocationProcessorRegistry; + } + /** * @param classificationMethodInterceptor the classificationMethodInterceptor to set */ @@ -111,12 +124,20 @@ public abstract class BasePostMethodInvocationProcessor this.contentClassificationService = contentClassificationService; } + /** + * @param postMethodInvocationProcessorRegistry the postMethodInvocationProcessorRegistry to set + */ + public void setPostMethodInvocationProcessorRegistry(PostMethodInvocationProcessorRegistry postMethodInvocationProcessorRegistry) + { + this.postMethodInvocationProcessorRegistry = postMethodInvocationProcessorRegistry; + } + /** * Gets the class name * * @return The class name */ - public abstract Class getClassName(); + protected abstract Class getClassName(); /** * Performs checks on the given object and throws exception if not all checks pass @@ -131,7 +152,7 @@ public abstract class BasePostMethodInvocationProcessor */ public void register() { - getClassificationMethodInterceptor().register(this); + getPostMethodInvocationProcessorRegistry().register(this); } /** @@ -147,6 +168,17 @@ public abstract class BasePostMethodInvocationProcessor } } + /** + * Checks if the given object is a collection + * + * @param object Object to check + * @return true if the code is a collection, false otherwise + */ + protected boolean isCollection(T object) + { + return Collection.class.isAssignableFrom(object.getClass()); + } + /** * Filters the node if the give node reference exist and it is a * content but the logged in user is not cleared to see the it. diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java index b71130584d..7af8983451 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java @@ -18,10 +18,12 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import static org.alfresco.util.ParameterCheck.mandatory; +import java.util.Collection; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.collections.CollectionUtils; +import org.alfresco.util.collections.Filter; /** * ChildAssociationRef Post Method Invocation Processor @@ -29,26 +31,23 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Tuna Aksoy * @since 3.0 */ -public class ChildAssociationRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +public class ChildAssociationRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor { /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() */ @Override - public Class getClassName() + protected Class getClassName() { return ChildAssociationRef.class; } /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) */ @Override - public T process(T object) + protected T processSingleElement(T object) { - mandatory("object", object); - checkObjectClass(object); - ChildAssociationRef childAssociationRef = ((ChildAssociationRef) object); NodeRef childRef = childAssociationRef.getChildRef(); @@ -59,4 +58,21 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends BasePostMe return (filteredChildRef == null || filteredParentRef == null) ? null : object; } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processCollection(java.util.Collection) + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + protected Collection processCollection(Collection collection) + { + return CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(ChildAssociationRef childAssociationRef) + { + return process(childAssociationRef) != null; + } + }); + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java index 68c8d6acc3..527e144b3e 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -23,12 +23,6 @@ import static org.alfresco.util.ParameterCheck.mandatory; import java.util.Collection; import java.util.Iterator; -import org.alfresco.service.cmr.repository.AssociationRef; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.collections.CollectionUtils; -import org.alfresco.util.collections.Filter; - /** * Collection Post Method Invocation Processor * @@ -37,63 +31,6 @@ import org.alfresco.util.collections.Filter; */ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { - /** Node ref post method invocation processor */ - private NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor; - - /** Association post method invocation processor */ - private AssociationRefPostMethodInvocationProcessor associationRefPostMethodInvocationProcessor; - - /** Child association post method invocation processor */ - private ChildAssociationRefPostMethodInvocationProcessor childAssociationRefPostMethodInvocationProcessor; - - /** - * @return the nodeRefPostMethodInvocationProcessor - */ - protected NodeRefPostMethodInvocationProcessor getNodeRefPostMethodInvocationProcessor() - { - return this.nodeRefPostMethodInvocationProcessor; - } - - /** - * @return the associationRefPostMethodInvocationProcessor - */ - protected AssociationRefPostMethodInvocationProcessor getAssociationRefPostMethodInvocationProcessor() - { - return this.associationRefPostMethodInvocationProcessor; - } - - /** - * @return the childAssociationRefPostMethodInvocationProcessor - */ - protected ChildAssociationRefPostMethodInvocationProcessor getChildAssociationRefPostMethodInvocationProcessor() - { - return this.childAssociationRefPostMethodInvocationProcessor; - } - - /** - * @param nodeRefPostMethodInvocationProcessor the nodeRefPostMethodInvocationProcessor to set - */ - public void setNodeRefPostMethodInvocationProcessor(NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor) - { - this.nodeRefPostMethodInvocationProcessor = nodeRefPostMethodInvocationProcessor; - } - - /** - * @param associationRefPostMethodInvocationProcessor the associationRefPostMethodInvocationProcessor to set - */ - public void setAssociationRefPostMethodInvocationProcessor(AssociationRefPostMethodInvocationProcessor associationRefPostMethodInvocationProcessor) - { - this.associationRefPostMethodInvocationProcessor = associationRefPostMethodInvocationProcessor; - } - - /** - * @param childAssociationRefPostMethodInvocationProcessor the childAssociationRefPostMethodInvocationProcessor to set - */ - public void setChildAssociationRefPostMethodInvocationProcessor(ChildAssociationRefPostMethodInvocationProcessor childAssociationRefPostMethodInvocationProcessor) - { - this.childAssociationRefPostMethodInvocationProcessor = childAssociationRefPostMethodInvocationProcessor; - } - /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) */ @@ -102,91 +39,24 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe public T process(T object) { mandatory("object", object); - checkObjectClass(object); Object result = object; - Collection collection = ((Collection) object); + if (!collection.isEmpty()) { Iterator iterator = collection.iterator(); if (iterator.hasNext()) { Class clazz = iterator.next().getClass(); - if (NodeRef.class.isAssignableFrom(clazz)) + BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessorRegistry().getProcessor(clazz); + if (processor != null) { - result = processNodeRef(collection); - } - - if (AssociationRef.class.isAssignableFrom(clazz)) - { - result = processAssociationRef(collection); - } - - if (ChildAssociationRef.class.isAssignableFrom(clazz)) - { - result = processChildAssociationRef(collection); + result = processor.process(object); } } } return (T) result; } - - /** - * Processes a {@link NodeRef} collection - * - * @param collection The collection to process - * @return The processed collection - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - private Collection processNodeRef(Collection collection) - { - return CollectionUtils.filter(collection, new Filter() - { - @Override - public Boolean apply(NodeRef nodeRef) - { - return getNodeRefPostMethodInvocationProcessor().process(nodeRef) != null; - } - }); - } - - /** - * Processes a {@link AssociationRef} collection - * - * @param collection The collection to process - * @return The processed collection - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - private Collection processAssociationRef(Collection collection) - { - return CollectionUtils.filter(collection, new Filter() - { - @Override - public Boolean apply(AssociationRef associationRef) - { - return getAssociationRefPostMethodInvocationProcessor().process(associationRef) != null; - } - }); - } - - /** - * Processes a {@link ChildAssociationRef} collection - * - * @param collection The collection to process - * @return The processed collection - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - private Collection processChildAssociationRef(Collection collection) - { - return CollectionUtils.filter(collection, new Filter() - { - @Override - public Boolean apply(ChildAssociationRef childAssociationRef) - { - return getChildAssociationRefPostMethodInvocationProcessor().process(childAssociationRef) != null; - } - }); - } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java index 4962eada3f..0176f9c3e8 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java @@ -33,7 +33,7 @@ public class ListPostMethodInvocationProcessor extends CollectionPostMethodInvoc */ @SuppressWarnings("rawtypes") @Override - public Class getClassName() + protected Class getClassName() { return List.class; } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java index 679ebe034e..4abde0e223 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java @@ -18,9 +18,11 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import static org.alfresco.util.ParameterCheck.mandatory; +import java.util.Collection; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.collections.CollectionUtils; +import org.alfresco.util.collections.Filter; /** * NodeRef Post Method Invocation Processor @@ -28,26 +30,41 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Tuna Aksoy * @since 3.0 */ -public class NodeRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +public class NodeRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor { /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() */ @Override - public Class getClassName() + protected Class getClassName() { return NodeRef.class; } /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) */ @Override - public T process(T object) + protected T processSingleElement(T object) { - mandatory("object", object); - checkObjectClass(object); + NodeRef nodeRef = (NodeRef) object; + return filter(nodeRef) == null ? null : object; + } - return filter((NodeRef) object) == null ? null : object; + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processCollection(java.util.Collection) + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + protected Collection processCollection(Collection collection) + { + return CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(NodeRef nodeRef) + { + return processSingleElement(nodeRef) != null; + } + }); } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java new file mode 100644 index 0000000000..ae835565ff --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java @@ -0,0 +1,82 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.alfresco.util.ParameterCheck.mandatory; + +import java.util.HashMap; +import java.util.Map; + +/** + * Registry for post method invocation processors + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class PostMethodInvocationProcessorRegistry +{ + /** Post method invocation processors */ + private Map, BasePostMethodInvocationProcessor> processors = new HashMap, BasePostMethodInvocationProcessor>(); + + /** + * Registers a post method invocation processor + * + * @param Post method invocation processor object + */ + public void register(BasePostMethodInvocationProcessor object) + { + mandatory("object", object); + + processors.put(object.getClassName(), object); + } + + /** + * Gets all the available processors + * + * @return the processors Available processors + */ + public Map, BasePostMethodInvocationProcessor> getProcessors() + { + return this.processors; + } + + /** + * Gets the processor from the available processors + * + * @param clazz The runtime class of the post invocation object + * @return The suitable processor for the given class + */ + public BasePostMethodInvocationProcessor getProcessor(Class clazz) + { + mandatory("clazz", clazz); + + BasePostMethodInvocationProcessor result = null; + + for (Map.Entry, BasePostMethodInvocationProcessor> processor : processors.entrySet()) + { + if (processor.getKey().isAssignableFrom(clazz)) + { + result = processor.getValue(); + break; + } + } + + return result; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java index 6fb47e4516..c8536b65a7 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java @@ -33,7 +33,7 @@ public class SetPostMethodInvocationProcessor extends CollectionPostMethodInvoca */ @SuppressWarnings("rawtypes") @Override - public Class getClassName() + protected Class getClassName() { return Set.class; } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java index 9a9476ca4c..5f9e39251b 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java @@ -18,10 +18,12 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import static org.alfresco.util.ParameterCheck.mandatory; +import java.util.Collection; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.util.collections.CollectionUtils; +import org.alfresco.util.collections.Filter; /** * StoreRef Post Method Invocation Processor @@ -29,28 +31,41 @@ import org.alfresco.service.cmr.repository.StoreRef; * @author Tuna Aksoy * @since 3.0 */ -public class StoreRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +public class StoreRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor { /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() */ @Override - public Class getClassName() + protected Class getClassName() { return StoreRef.class; } /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) */ @Override - public T process(T object) + protected T processSingleElement(T object) { - mandatory("object", object); - checkObjectClass(object); - NodeRef nodeRef = getNodeService().getRootNode((StoreRef) object); - return filter(nodeRef) == null ? null : object; } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processCollection(java.util.Collection) + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + protected Collection processCollection(Collection collection) + { + return CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(NodeRef nodeRef) + { + return processSingleElement(nodeRef) != null; + } + }); + } } From e79b4a9d8fa64348ff22cf6b31bc42079a09c6ec Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Fri, 19 Jun 2015 12:39:04 +0000 Subject: [PATCH 12/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106552 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../SecurityClearanceServiceImpl.java | 4 +- ...PostMethodInvocationProcessorRegistry.java | 2 +- ...PostMethodInvocationProcessorUnitTest.java | 90 ++++++++++++++++++- 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java index afe9499269..493180dc40 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java @@ -41,7 +41,7 @@ import org.alfresco.util.ParameterCheck; * @since 3.0 */ public class SecurityClearanceServiceImpl extends ServiceBaseImpl implements SecurityClearanceService -{ +{ /** The clearance levels currently configured in this server. */ private ClearanceLevelManager clearanceManager; /** The object containing the {@link ClassificationLevel}s in the system. */ @@ -88,7 +88,7 @@ public class SecurityClearanceServiceImpl extends ServiceBaseImpl implements Sec */ private SecurityClearance getUserSecurityClearance(final String userName) { - final NodeRef personNode = personService.getPerson(userName, false); + final NodeRef personNode = personService.getPerson(userName, true); final PersonInfo personInfo = personService.getPerson(personNode); ClearanceLevel clearanceLevel = ClearanceLevelManager.NO_CLEARANCE; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java index ae835565ff..d4e6f0e10a 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java @@ -68,7 +68,7 @@ public class PostMethodInvocationProcessorRegistry BasePostMethodInvocationProcessor result = null; - for (Map.Entry, BasePostMethodInvocationProcessor> processor : processors.entrySet()) + for (Map.Entry, BasePostMethodInvocationProcessor> processor : getProcessors().entrySet()) { if (processor.getKey().isAssignableFrom(clazz)) { diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java index df7704687d..3bdf4ef2cd 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java @@ -18,10 +18,15 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; +import static com.google.common.collect.ImmutableList.copyOf; +import static com.google.common.collect.Lists.newArrayList; +import static java.util.Collections.unmodifiableCollection; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.when; import static org.springframework.extensions.webscripts.GUID.generate; +import java.util.ArrayList; + import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ClassificationPostMethodInvocationException.NotSupportedClassTypeException; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; @@ -59,7 +64,6 @@ public class NodeRefPostMethodInvocationProcessorUnitTest extends BaseUnitTest { NodeRef nodeRef = new NodeRef(generate() + "://" + generate() + "/"); - when(mockedNodeService.getType(nodeRef)).thenReturn(TYPE_CONTENT); when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef), TYPE_CONTENT)).thenReturn(true); when(mockedContentClassificationService.hasClearance(nodeRef)).thenReturn(true); @@ -71,7 +75,6 @@ public class NodeRefPostMethodInvocationProcessorUnitTest extends BaseUnitTest { NodeRef nodeRef = generateNodeRef(); - when(mockedNodeService.getType(nodeRef)).thenReturn(TYPE_CONTENT); when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef), TYPE_CONTENT)).thenReturn(false); when(mockedContentClassificationService.hasClearance(nodeRef)).thenReturn(true); @@ -83,7 +86,6 @@ public class NodeRefPostMethodInvocationProcessorUnitTest extends BaseUnitTest { NodeRef nodeRef = generateNodeRef(); - when(mockedNodeService.getType(nodeRef)).thenReturn(TYPE_CONTENT); when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef), TYPE_CONTENT)).thenReturn(true); when(mockedContentClassificationService.hasClearance(nodeRef)).thenReturn(true); @@ -95,10 +97,90 @@ public class NodeRefPostMethodInvocationProcessorUnitTest extends BaseUnitTest { NodeRef nodeRef = generateNodeRef(); - when(mockedNodeService.getType(nodeRef)).thenReturn(TYPE_CONTENT); when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef), TYPE_CONTENT)).thenReturn(true); when(mockedContentClassificationService.hasClearance(nodeRef)).thenReturn(false); assertEquals(null, nodeRefPostMethodInvocationProcessor.process(nodeRef)); } + + @Test + public void testCollection_bothNodesConent_userClearedForBoth() + { + NodeRef nodeRef1 = generateNodeRef(); + NodeRef nodeRef2 = generateNodeRef(); + ArrayList nodeRefs = newArrayList(nodeRef1, nodeRef2); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(true); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(true); + + assertEquals(nodeRefs, nodeRefPostMethodInvocationProcessor.process(nodeRefs)); + } + + @Test + public void testCollection_bothNodesContent_userClearedForOne() + { + NodeRef nodeRef1 = generateNodeRef(); + NodeRef nodeRef2 = generateNodeRef(); + ArrayList nodeRefs = newArrayList(nodeRef1, nodeRef2); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(true); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(false); + + assertEquals(newArrayList(nodeRef1), nodeRefPostMethodInvocationProcessor.process(nodeRefs)); + } + + @SuppressWarnings("rawtypes") + @Test + public void testCollection_bothNodesContent_userClearedForNone() + { + NodeRef nodeRef1 = generateNodeRef(); + NodeRef nodeRef2 = generateNodeRef(); + ArrayList nodeRefs = newArrayList(nodeRef1, nodeRef2); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(false); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(false); + + assertEquals(new ArrayList(), nodeRefPostMethodInvocationProcessor.process(unmodifiableCollection(nodeRefs))); + } + + @Test + public void testCollection_onlyOneNodeContent_userClearedForBoth() + { + NodeRef nodeRef1 = generateNodeRef(); + NodeRef nodeRef2 = generateNodeRef(); + ArrayList nodeRefs = newArrayList(nodeRef1, nodeRef2); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(false); + when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(true); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(true); + + assertEquals(nodeRefs, nodeRefPostMethodInvocationProcessor.process(copyOf(nodeRefs))); + } + + @Test + public void testCollection_bothNodesNotContent_userClearedForBoth() + { + NodeRef nodeRef1 = generateNodeRef(); + NodeRef nodeRef2 = generateNodeRef(); + ArrayList nodeRefs = newArrayList(nodeRef1, nodeRef2); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(false); + when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(true); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(false); + when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(true); + + assertEquals(nodeRefs, nodeRefPostMethodInvocationProcessor.process(copyOf(nodeRefs))); + } } From 3772764f8e020bb348891d02422e01386332b953 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sat, 20 Jun 2015 18:42:32 +0000 Subject: [PATCH 13/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106639 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 24 +- .../SecurityClearanceServiceImpl.java | 2 +- .../ClassificationMethodInterceptor.java | 375 ++++++------------ ...icationMethodInterceptorPostProcessor.java | 18 +- ...AbstractPostMethodInvocationProcessor.java | 29 +- .../BasePostMethodInvocationProcessor.java | 38 +- ...ationRefPostMethodInvocationProcessor.java | 2 +- ...llectionPostMethodInvocationProcessor.java | 28 +- ...ava => PostMethodInvocationProcessor.java} | 51 ++- .../PreMethodInvocationProcessor.java | 173 ++++++++ ...PostMethodInvocationProcessorUnitTest.java | 6 - 11 files changed, 407 insertions(+), 339 deletions(-) rename rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/{PostMethodInvocationProcessorRegistry.java => PostMethodInvocationProcessor.java} (59%) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index 1a5c7bff55..aeb2f39e64 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -35,24 +35,30 @@ + + + + + + + class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor"> + + - - + class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptorPostProcessor" /> - + abstract="true" + init-method="register"> - + . - */ -package org.alfresco.module.org_alfresco_module_rm.classification.interceptor; - -import static org.alfresco.model.ContentModel.TYPE_CONTENT; -import static org.codehaus.plexus.util.StringUtils.isNotBlank; - -import java.lang.reflect.Method; - -import org.alfresco.jlan.server.filesys.AccessDeniedException; -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.classification.interceptor.processor.BasePostMethodInvocationProcessor; -import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PostMethodInvocationProcessorRegistry; -import org.alfresco.module.org_alfresco_module_rm.util.AlfrescoTransactionSupport; -import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.GUID; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.log4j.Logger; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; - -/** - * Classification method interceptor - * - * @author Roy Wetherall - * @since 3.0 - */ -public class ClassificationMethodInterceptor implements MethodInterceptor, ApplicationContextAware -{ - /** Logger */ - private static Logger LOG = Logger.getLogger(ClassificationMethodInterceptor.class); - - private static final String KEY_PROCESSING = GUID.generate(); - - /** application context */ - private ApplicationContext applicationContext; - - /** - * @param applicationContext application context - * @throws BeansException - */ - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException - { - this.applicationContext = applicationContext; - } - - protected AuthenticationUtil getAuthenticationUtil() - { - return (AuthenticationUtil)applicationContext.getBean("rm.authenticationUtil"); - } - - /** - * @return {@link ContentClassificationService} content classification service - */ - protected ContentClassificationService getContentClassificationService() - { - return (ContentClassificationService)applicationContext.getBean("contentClassificationService"); - } - - protected AlfrescoTransactionSupport getAlfrescoTransactionSupport() - { - return (AlfrescoTransactionSupport)applicationContext.getBean("rm.alfrescoTransactionSupport"); - } - - protected RetryingTransactionHelper getRetryingTransactionHelper() - { - return ((TransactionService)applicationContext.getBean("transactionService")).getRetryingTransactionHelper(); - } - - protected ClassificationServiceBootstrap getClassificationServiceBootstrap() - { - return (ClassificationServiceBootstrap)applicationContext.getBean("classificationServiceBootstrap"); - } - - protected NodeService getNodeService() - { - return (NodeService)applicationContext.getBean("dbNodeService"); - } - - protected DictionaryService getDictionaryService() - { - return (DictionaryService)applicationContext.getBean("dictionaryService"); - } - - protected PostMethodInvocationProcessorRegistry getPostMethodInvocationProcessorRegistry() - { - return (PostMethodInvocationProcessorRegistry)applicationContext.getBean("postMethodInvocationProcessorRegistry"); - } - - /** - * Check that the current user is cleared to see the items passed as parameters to the current - * method invocation. - * - * @param invocation method invocation - */ - @SuppressWarnings("rawtypes") - public NodeRef checkClassification(final MethodInvocation invocation) - { - // do in transaction - return getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() - { - public NodeRef execute() throws Throwable - { - NodeRef result = null; - - // ensure classification service has been bootstrapped - if (getClassificationServiceBootstrap().isInitialised()) - { - // check that we are not already processing a classification check - Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING); - if (value == null) - { - Method method = invocation.getMethod(); - Class[] params = method.getParameterTypes(); - - int position = 0; - for (Class param : params) - { - // if the param is a node reference - if (NodeRef.class.isAssignableFrom(param)) - { - // mark the transaction as processing a classification check - getAlfrescoTransactionSupport().bindResource(KEY_PROCESSING, Boolean.TRUE); - try - { - // get the value of the parameter - NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position]; - - // if node exists then see if the current user has clearance - result = checkNode(testNodeRef); - } - finally - { - // clear the transaction as processed a classification check - getAlfrescoTransactionSupport().unbindResource(KEY_PROCESSING); - } - } - - position++; - } - } - } - - return result; - } - }, true); - } - - private boolean isUserValid() - { - boolean result = false; - - // check that we have an authenticated user and that they aren't "system" - if (isNotBlank(getAuthenticationUtil().getFullyAuthenticatedUser()) && - !getAuthenticationUtil().isRunAsUserTheSystemUser()) - { - result = true; - } - - return result; - } - - private NodeRef checkNode(NodeRef testNodeRef) throws AccessDeniedException - { - NodeRef result = testNodeRef; - - if (getNodeService().exists(testNodeRef) && - getDictionaryService().isSubClass(getNodeService().getType(testNodeRef), TYPE_CONTENT) && - !getContentClassificationService().hasClearance(testNodeRef)) - { - // FIXME - result = null; - //throw new AccessDeniedException("You do not have clearance!"); - } - - return result; - } - - /** - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) - */ - @Override - public Object invoke(MethodInvocation invocation) throws Throwable - { - // FIXME - //NodeRef preInvocation = null; - Object postInvocation = null; - - boolean isUserValid = isUserValid(); - - // pre method invocation check - if (isUserValid) - { - // FIXME - //preInvocation = checkClassification(invocation); - //checkClassification(invocation); - } - - // method proceed - postInvocation = invocation.proceed(); - - // post method invocation processing - if (isUserValid && postInvocation != null) - { - Class clazz = postInvocation.getClass(); - BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessorRegistry().getProcessor(clazz); - - if (processor != null) - { - postInvocation = processor.process(postInvocation); - } - else - { - LOG.debug("No post method invocation processor found for '" + clazz + "'."); - } - } - - return postInvocation; - } -} +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor; + +import static org.alfresco.repo.security.authentication.AuthenticationUtil.getFullyAuthenticatedUser; +import static org.alfresco.repo.security.authentication.AuthenticationUtil.isRunAsUserTheSystemUser; +import static org.alfresco.util.ParameterCheck.mandatory; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PostMethodInvocationProcessor; +import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PreMethodInvocationProcessor; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * Classification method interceptor + * + * @author Roy Wetherall + * @author Tuna Aksoy + * @since 3.0 + */ +public class ClassificationMethodInterceptor implements MethodInterceptor +{ + /** Pre method invocation processor */ + private PreMethodInvocationProcessor preMethodInvocationProcessor; + + /** Post method invocation processor */ + private PostMethodInvocationProcessor postMethodInvocationProcessor; + + /** + * @return the preMethodInvocationProcessor + */ + protected PreMethodInvocationProcessor getPreMethodInvocationProcessor() + { + return this.preMethodInvocationProcessor; + } + + /** + * @return the postMethodInvocationProcessor + */ + protected PostMethodInvocationProcessor getPostMethodInvocationProcessor() + { + return this.postMethodInvocationProcessor; + } + + /** + * @param postMethodInvocationProcessor the postMethodInvocationProcessor to set + */ + public void setPostMethodInvocationProcessor(PostMethodInvocationProcessor postMethodInvocationProcessor) + { + this.postMethodInvocationProcessor = postMethodInvocationProcessor; + } + + /** + * @param preMethodInvocationProcessor the preMethodInvocationProcessor to set + */ + public void setPreMethodInvocationProcessor(PreMethodInvocationProcessor preMethodInvocationProcessor) + { + this.preMethodInvocationProcessor = preMethodInvocationProcessor; + } + + /** + * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + */ + @Override + public Object invoke(MethodInvocation invocation) throws Throwable + { + mandatory("invocation", invocation); + + Object result = null; + + boolean canProceed = true; + boolean isUserValid = isUserValid(); + + if (isUserValid) + { + //FIXME!!! + // Pre method invocation processing + //canProceed = getPreMethodInvocationProcessor().process(invocation); + } + + if (canProceed) + { + // Method invocation + result = invocation.proceed(); + + // Post method invocation processing + if (isUserValid && result != null) + { + result = getPostMethodInvocationProcessor().process(result); + } + } + + return result; + } + + /** + * Checks if we have an authenticated user and that they aren't "System" + * + * @return true if we have an authenticated user and that they aren't "System", false otherwise. + */ + private boolean isUserValid() + { + boolean result = false; + + if (isNotBlank(getFullyAuthenticatedUser()) && !isRunAsUserTheSystemUser()) + { + result = true; + } + + return result; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java index 010d2e98cd..5bb5be1062 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptorPostProcessor.java @@ -32,17 +32,17 @@ import org.springframework.beans.factory.support.ManagedList; *

* Bean factory post processor that inspects available beans and adds the classification method interceptor * to all public services. - * + * * @author Roy Wetherall * @since 3.0.a */ public class ClassificationMethodInterceptorPostProcessor implements BeanFactoryPostProcessor { private static final String PROP_INTERCEPTOR_NAMES = "interceptorNames"; - private static final String TYPE_PROXY_FACTORY_BEAN = "ProxyFactoryBean"; + private static final String TYPE_PROXY_FACTORY_BEAN = "ProxyFactoryBean"; private static final String POSTFIX_SERVICE = "Service"; private static final String BEAN_NAME_CLASSIFICATION_METHOD_INTERCEPTOR = "classificationMethodInterceptor"; - + /** * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) */ @@ -56,27 +56,27 @@ public class ClassificationMethodInterceptorPostProcessor implements BeanFactory { // get bean definition BeanDefinition beanDefinition = beanFactory.getBeanDefinition(bean); - + // only modify proxy factory beans that follow the public service naming postfix convention - if (beanDefinition.getBeanClassName() != null && + if (beanDefinition.getBeanClassName() != null && beanDefinition.getBeanClassName().endsWith(TYPE_PROXY_FACTORY_BEAN) && bean.endsWith(POSTFIX_SERVICE)) - { + { // get the property values for the bean definition MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); if (propertyValues.contains(PROP_INTERCEPTOR_NAMES)) { // get the current list of interceptor names - PropertyValue value = propertyValues.getPropertyValue(PROP_INTERCEPTOR_NAMES); + PropertyValue value = propertyValues.getPropertyValue(PROP_INTERCEPTOR_NAMES); ManagedList list = (ManagedList)value.getValue(); if (!list.isEmpty()) { // add reference to classification method interceptor RuntimeBeanNameReference beanReference = new RuntimeBeanNameReference(BEAN_NAME_CLASSIFICATION_METHOD_INTERCEPTOR); list.add(beanReference); - } + } } } - } + } } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java index 022dbed21e..e86eef1983 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java @@ -18,8 +18,6 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import static org.alfresco.util.ParameterCheck.mandatory; - import java.util.Collection; /** @@ -54,23 +52,24 @@ public abstract class AbstractPostMethodInvocationProcessor extends BasePostMeth @Override public T process(T object) { - mandatory("object", object); + T result = object; - T result = null; - - if (isCollection(object)) + if (result != null) { - Collection collection = ((Collection) object); - if (!collection.isEmpty()) + if (isCollection(result)) { - checkObjectClass(collection.iterator().next()); - result = (T) processCollection(collection); + Collection collection = ((Collection) result); + if (!collection.isEmpty()) + { + checkObjectClass(collection.iterator().next()); + result = (T) processCollection(collection); + } + } + else + { + checkObjectClass(result); + result = processSingleElement(result); } - } - else - { - checkObjectClass(object); - result = (T) processSingleElement(object); } return result; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java index 9ada7a259e..ba690141f2 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -23,7 +23,6 @@ import static org.alfresco.model.ContentModel.TYPE_CONTENT; import java.util.Collection; import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; -import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ClassificationPostMethodInvocationException.NotSupportedClassTypeException; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; @@ -37,9 +36,6 @@ import org.alfresco.service.cmr.repository.NodeService; */ public abstract class BasePostMethodInvocationProcessor { - /** Classification method interceptor */ - private ClassificationMethodInterceptor classificationMethodInterceptor; - /** Node service */ private NodeService nodeService; @@ -49,16 +45,8 @@ public abstract class BasePostMethodInvocationProcessor /** Content classification service */ private ContentClassificationService contentClassificationService; - /** Post method invocation processor registry */ - private PostMethodInvocationProcessorRegistry postMethodInvocationProcessorRegistry; - - /** - * @return the classificationMethodInterceptor - */ - protected ClassificationMethodInterceptor getClassificationMethodInterceptor() - { - return this.classificationMethodInterceptor; - } + /** Post method invocation processor */ + private PostMethodInvocationProcessor postMethodInvocationProcessor; /** * @return the nodeService @@ -85,19 +73,11 @@ public abstract class BasePostMethodInvocationProcessor } /** - * @return the postMethodInvocationProcessorRegistry + * @return the postMethodInvocationProcessor */ - protected PostMethodInvocationProcessorRegistry getPostMethodInvocationProcessorRegistry() + protected PostMethodInvocationProcessor getPostMethodInvocationProcessor() { - return this.postMethodInvocationProcessorRegistry; - } - - /** - * @param classificationMethodInterceptor the classificationMethodInterceptor to set - */ - public void setClassificationMethodInterceptor(ClassificationMethodInterceptor classificationMethodInterceptor) - { - this.classificationMethodInterceptor = classificationMethodInterceptor; + return this.postMethodInvocationProcessor; } /** @@ -125,11 +105,11 @@ public abstract class BasePostMethodInvocationProcessor } /** - * @param postMethodInvocationProcessorRegistry the postMethodInvocationProcessorRegistry to set + * @param postMethodInvocationProcessor the postMethodInvocationProcessor to set */ - public void setPostMethodInvocationProcessorRegistry(PostMethodInvocationProcessorRegistry postMethodInvocationProcessorRegistry) + public void setPostMethodInvocationProcessor(PostMethodInvocationProcessor postMethodInvocationProcessor) { - this.postMethodInvocationProcessorRegistry = postMethodInvocationProcessorRegistry; + this.postMethodInvocationProcessor = postMethodInvocationProcessor; } /** @@ -152,7 +132,7 @@ public abstract class BasePostMethodInvocationProcessor */ public void register() { - getPostMethodInvocationProcessorRegistry().register(this); + getPostMethodInvocationProcessor().register(this); } /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java index 7af8983451..89a62e0714 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java @@ -71,7 +71,7 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends AbstractPo @Override public Boolean apply(ChildAssociationRef childAssociationRef) { - return process(childAssociationRef) != null; + return processSingleElement(childAssociationRef) != null; } }); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java index 527e144b3e..7c0160f65f 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -18,8 +18,6 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import static org.alfresco.util.ParameterCheck.mandatory; - import java.util.Collection; import java.util.Iterator; @@ -34,29 +32,29 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) */ - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "rawtypes" }) @Override public T process(T object) { - mandatory("object", object); + T result = object; - Object result = object; - Collection collection = ((Collection) object); - - if (!collection.isEmpty()) + if (result != null) { - Iterator iterator = collection.iterator(); - if (iterator.hasNext()) + Collection collection = ((Collection) result); + if (!collection.isEmpty()) { - Class clazz = iterator.next().getClass(); - BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessorRegistry().getProcessor(clazz); - if (processor != null) + Iterator iterator = collection.iterator(); + if (iterator.hasNext()) { - result = processor.process(object); + BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(iterator.next()); + if (processor != null) + { + result = processor.process(object); + } } } } - return (T) result; + return result; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java similarity index 59% rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java rename to rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java index d4e6f0e10a..3c1a81ac07 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessorRegistry.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java @@ -22,6 +22,10 @@ import static org.alfresco.util.ParameterCheck.mandatory; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.log4j.Logger; /** * Registry for post method invocation processors @@ -29,8 +33,11 @@ import java.util.Map; * @author Tuna Aksoy * @since 3.0 */ -public class PostMethodInvocationProcessorRegistry +public class PostMethodInvocationProcessor { + /** Logger */ + private static Logger LOG = Logger.getLogger(PostMethodInvocationProcessor.class); + /** Post method invocation processors */ private Map, BasePostMethodInvocationProcessor> processors = new HashMap, BasePostMethodInvocationProcessor>(); @@ -51,7 +58,7 @@ public class PostMethodInvocationProcessorRegistry * * @return the processors Available processors */ - public Map, BasePostMethodInvocationProcessor> getProcessors() + private Map, BasePostMethodInvocationProcessor> getProcessors() { return this.processors; } @@ -59,24 +66,52 @@ public class PostMethodInvocationProcessorRegistry /** * Gets the processor from the available processors * - * @param clazz The runtime class of the post invocation object + * @param object The post invocation object * @return The suitable processor for the given class */ - public BasePostMethodInvocationProcessor getProcessor(Class clazz) + protected BasePostMethodInvocationProcessor getProcessor(Object object) { - mandatory("clazz", clazz); + mandatory("object", object); BasePostMethodInvocationProcessor result = null; + Class clazz = object.getClass(); - for (Map.Entry, BasePostMethodInvocationProcessor> processor : getProcessors().entrySet()) + Set, BasePostMethodInvocationProcessor>> processorsEntrySet = getProcessors().entrySet(); + for (Map.Entry, BasePostMethodInvocationProcessor> processorEntry : processorsEntrySet) { - if (processor.getKey().isAssignableFrom(clazz)) + if (processorEntry.getKey().isAssignableFrom(clazz)) { - result = processor.getValue(); + result = processorEntry.getValue(); break; } } return result; } + + /** + * Processes the given object + * + * @param object The object to process + * @return The processed object + */ + public T process(T object) + { + T result = object; + + if (result != null) + { + BasePostMethodInvocationProcessor processor = getProcessor(result); + if (processor != null) + { + result = processor.process(result); + } + else + { + LOG.debug("No processor found for '" + result + "'."); + } + } + + return result; + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java new file mode 100644 index 0000000000..d19bc5b1f8 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java @@ -0,0 +1,173 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static java.lang.Boolean.TRUE; +import static org.alfresco.model.ContentModel.TYPE_CONTENT; +import static org.alfresco.util.GUID.generate; +import static org.alfresco.util.ParameterCheck.mandatory; + +import java.lang.reflect.Method; + +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.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.transaction.TransactionService; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * Pre method invocation processor + * + * @author Roy Wetherall + * @author Tuna Aksoy + * @since 3.0 + */ +public class PreMethodInvocationProcessor implements ApplicationContextAware +{ + private static final String KEY_PROCESSING = generate(); + + private ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + this.applicationContext = applicationContext; + } + + protected ContentClassificationService getContentClassificationService() + { + return (ContentClassificationService)applicationContext.getBean("contentClassificationService"); + } + + protected AlfrescoTransactionSupport getAlfrescoTransactionSupport() + { + return (AlfrescoTransactionSupport)applicationContext.getBean("rm.alfrescoTransactionSupport"); + } + + protected RetryingTransactionHelper getRetryingTransactionHelper() + { + return ((TransactionService)applicationContext.getBean("transactionService")).getRetryingTransactionHelper(); + } + + protected ClassificationServiceBootstrap getClassificationServiceBootstrap() + { + return (ClassificationServiceBootstrap)applicationContext.getBean("classificationServiceBootstrap"); + } + + protected NodeService getNodeService() + { + return (NodeService)applicationContext.getBean("dbNodeService"); + } + + protected DictionaryService getDictionaryService() + { + return (DictionaryService)applicationContext.getBean("dictionaryService"); + } + + /** + * Checks if the current user is cleared to see the items + * passed as parameters to the current method invocation. + * + * @param invocation The current method invocation + * @return true if the user is cleared to see the items, false otherwise + */ + public boolean process(final MethodInvocation invocation) + { + mandatory("invocation", invocation); + + // do in transaction + return getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + @SuppressWarnings("rawtypes") + public Boolean execute() throws Throwable + { + Boolean result = true; + + // ensure classification service has been bootstrapped + if (getClassificationServiceBootstrap().isInitialised()) + { + // check that we are not already processing a classification check + Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING); + if (value == null) + { + Method method = invocation.getMethod(); + Class[] params = method.getParameterTypes(); + + int position = 0; + for (Class param : params) + { + // if the param is a node reference + if (NodeRef.class.isAssignableFrom(param)) + { + // mark the transaction as processing a classification check + getAlfrescoTransactionSupport().bindResource(KEY_PROCESSING, TRUE); + try + { + // get the value of the parameter + NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position]; + + // if node exists then see if the current user has clearance + result = isNodeCleared(testNodeRef); + } + finally + { + // clear the transaction as processed a classification check + getAlfrescoTransactionSupport().unbindResource(KEY_PROCESSING); + } + } + + position++; + } + } + } + + return result; + } + }, true); + } + + /** + * Checks if the given node exists, if it is a content and if + * the currently logged in user is cleared to see it. + * + * @param nodeRef Node reference to check + * @return true if the node passes the checks, false otherwise + */ + private boolean isNodeCleared(NodeRef nodeRef) + { + boolean result = true; + + if (getNodeService().exists(nodeRef) && + getDictionaryService().isSubClass(getNodeService().getType(nodeRef), TYPE_CONTENT) && + !getContentClassificationService().hasClearance(nodeRef)) + { + result = false; + } + + return result; + } +} diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java index 3bdf4ef2cd..89735d7472 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java @@ -46,12 +46,6 @@ public class NodeRefPostMethodInvocationProcessorUnitTest extends BaseUnitTest @InjectMocks private NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor; @Mock private ContentClassificationService mockedContentClassificationService; - @Test (expected = IllegalArgumentException.class) - public void testProcessingNull() - { - nodeRefPostMethodInvocationProcessor.process(null); - } - @Test (expected = NotSupportedClassTypeException.class) public void testProccessingAnotherClassType() { From 862fde1e612bb673e241e01f867b309d05940579 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sun, 21 Jun 2015 19:47:57 +0000 Subject: [PATCH 14/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106657 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 13 ++ .../ArrayPostMethodInvocationProcessor.java | 87 +++++++++++++ .../PostMethodInvocationProcessor.java | 19 ++- .../PreMethodInvocationProcessor.java | 117 +++++++++++++++++- ...PostMethodInvocationProcessorUnitTest.java | 76 ++++++++++++ 5 files changed, 306 insertions(+), 6 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java create mode 100644 rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessorUnitTest.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index aeb2f39e64..cf15c1b485 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -37,6 +37,14 @@ + + + + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..672958aab9 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java @@ -0,0 +1,87 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static java.lang.reflect.Array.newInstance; +import static org.alfresco.util.ParameterCheck.mandatory; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; + +/** + * Array Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class ArrayPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + protected Class getClassName() + { + return Array.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public T process(T object) + { + mandatory("object", object); + + T result = object; + T[] objects = (T[]) result; + T obj = objects[0]; + + BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(obj); + if (processor != null) + { + int length = objects.length; + List processedObjects = new ArrayList(); + + for (int i = 0; i < length; i++) + { + Object processedObject = processor.process(objects[i]); + if (processedObject != null) + { + processedObjects.add(processedObject); + } + } + + int size = processedObjects.size(); + T[] objs = (T[]) newInstance(obj.getClass(), size); + + for (int i = 0; i < size; i++) + { + objs[i] = (T) processedObjects.get(i); + } + + result = (T) objs; + } + + return result; + } + +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java index 3c1a81ac07..775d03a169 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java @@ -20,6 +20,7 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.pr import static org.alfresco.util.ParameterCheck.mandatory; +import java.lang.reflect.Array; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -76,13 +77,21 @@ public class PostMethodInvocationProcessor BasePostMethodInvocationProcessor result = null; Class clazz = object.getClass(); - Set, BasePostMethodInvocationProcessor>> processorsEntrySet = getProcessors().entrySet(); - for (Map.Entry, BasePostMethodInvocationProcessor> processorEntry : processorsEntrySet) + if (clazz.isArray()) { - if (processorEntry.getKey().isAssignableFrom(clazz)) + result = getProcessors().get(Array.class); + } + + if (result == null) + { + Set, BasePostMethodInvocationProcessor>> processorsEntrySet = getProcessors().entrySet(); + for (Map.Entry, BasePostMethodInvocationProcessor> processorEntry : processorsEntrySet) { - result = processorEntry.getValue(); - break; + if (processorEntry.getKey().isAssignableFrom(clazz)) + { + result = processorEntry.getValue(); + break; + } } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java index d19bc5b1f8..85585653be 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java @@ -48,6 +48,7 @@ import org.springframework.context.ApplicationContextAware; */ public class PreMethodInvocationProcessor implements ApplicationContextAware { + /** Key to mark the transaction as processing */ private static final String KEY_PROCESSING = generate(); private ApplicationContext applicationContext; @@ -88,6 +89,120 @@ public class PreMethodInvocationProcessor implements ApplicationContextAware return (DictionaryService)applicationContext.getBean("dictionaryService"); } +// /** Transaction service */ +// private TransactionService transactionService; +// +// /** Classification service bootstrap */ +// private ClassificationServiceBootstrap classificationServiceBootstrap; +// +// /** Alfresco transaction support */ +// private AlfrescoTransactionSupport alfrescoTransactionSupport; +// +// /** Node service */ +// private NodeService nodeService; +// +// /** Dictionary service */ +// private DictionaryService dictionaryService; +// +// /** Content classification service */ +// private ContentClassificationService contentClassificationService; +// +// /** +// * @return the transactionService +// */ +// protected TransactionService getTransactionService() +// { +// return this.transactionService; +// } +// +// /** +// * @return the classificationServiceBootstrap +// */ +// protected ClassificationServiceBootstrap getClassificationServiceBootstrap() +// { +// return this.classificationServiceBootstrap; +// } +// +// /** +// * @return the alfrescoTransactionSupport +// */ +// protected AlfrescoTransactionSupport getAlfrescoTransactionSupport() +// { +// return this.alfrescoTransactionSupport; +// } +// +// /** +// * @return the nodeService +// */ +// protected NodeService getNodeService() +// { +// return this.nodeService; +// } +// +// /** +// * @return the dictionaryService +// */ +// protected DictionaryService getDictionaryService() +// { +// return this.dictionaryService; +// } +// +// /** +// * @return the contentClassificationService +// */ +// protected ContentClassificationService getContentClassificationService() +// { +// return this.contentClassificationService; +// } +// +// /** +// * @param transactionService the transactionService to set +// */ +// public void setTransactionService(TransactionService transactionService) +// { +// this.transactionService = transactionService; +// } +// +// /** +// * @param classificationServiceBootstrap the classificationServiceBootstrap to set +// */ +// public void setClassificationServiceBootstrap(ClassificationServiceBootstrap classificationServiceBootstrap) +// { +// this.classificationServiceBootstrap = classificationServiceBootstrap; +// } +// +// /** +// * @param alfrescoTransactionSupport the alfrescoTransactionSupport to set +// */ +// public void setAlfrescoTransactionSupport(AlfrescoTransactionSupport alfrescoTransactionSupport) +// { +// this.alfrescoTransactionSupport = alfrescoTransactionSupport; +// } +// +// /** +// * @param nodeService the nodeService to set +// */ +// public void setNodeService(NodeService nodeService) +// { +// this.nodeService = nodeService; +// } +// +// /** +// * @param dictionaryService the dictionaryService to set +// */ +// public void setDictionaryService(DictionaryService dictionaryService) +// { +// this.dictionaryService = dictionaryService; +// } +// +// /** +// * @param contentClassificationService the contentClassificationService to set +// */ +// public void setContentClassificationService(ContentClassificationService contentClassificationService) +// { +// this.contentClassificationService = contentClassificationService; +// } + /** * Checks if the current user is cleared to see the items * passed as parameters to the current method invocation. @@ -100,7 +215,7 @@ public class PreMethodInvocationProcessor implements ApplicationContextAware mandatory("invocation", invocation); // do in transaction - return getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + return /*getTransactionService().*/getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() { @SuppressWarnings("rawtypes") public Boolean execute() throws Throwable diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessorUnitTest.java new file mode 100644 index 0000000000..a9c44c4601 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessorUnitTest.java @@ -0,0 +1,76 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; +import org.alfresco.service.cmr.repository.NodeRef; +import org.apache.commons.lang3.ArrayUtils; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; + +/** + * Array Post Method Invocation Processor Unit Test + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class ArrayPostMethodInvocationProcessorUnitTest extends BaseUnitTest +{ + @InjectMocks ArrayPostMethodInvocationProcessor arrayPostMethodInvocationProcessor; + @Mock private ContentClassificationService mockedContentClassificationService; + @Mock private PostMethodInvocationProcessor mockedPostMethodInvocationProcessor; + + @Test + public void testArrayPostMethodInvocationProcessor() + { + NodeRefPostMethodInvocationProcessor processor = new NodeRefPostMethodInvocationProcessor(); + processor.setNodeService(mockedNodeService); + processor.setDictionaryService(mockedDictionaryService); + processor.setContentClassificationService(mockedContentClassificationService); + + NodeRef nodeRef1 = generateNodeRef(); + NodeRef nodeRef2 = generateNodeRef(); + NodeRef nodeRef3 = generateNodeRef(); + NodeRef nodeRef4 = generateNodeRef(); + + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(true); + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(true); + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef3), TYPE_CONTENT)).thenReturn(true); + when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef4), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(false); + when(mockedContentClassificationService.hasClearance(nodeRef3)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef4)).thenReturn(false); + when(mockedPostMethodInvocationProcessor.getProcessor(Mockito.any())).thenReturn(processor); + + NodeRef[] nodes = new NodeRef[] { nodeRef1, nodeRef2, nodeRef3, nodeRef4 }; + NodeRef[] processedNodes = arrayPostMethodInvocationProcessor.process(nodes); + + assertEquals(2, processedNodes.length); + assertTrue(ArrayUtils.contains(processedNodes, nodeRef1)); + assertTrue(ArrayUtils.contains(processedNodes, nodeRef3)); + } +} From 24cc5ca519e4e8df7835317d955d8a4969e99e5a Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sun, 21 Jun 2015 21:58:42 +0000 Subject: [PATCH 15/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106658 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 5 ++ ...AbstractPostMethodInvocationProcessor.java | 21 +++-- ...ationRefPostMethodInvocationProcessor.java | 23 +----- .../BasePostMethodInvocationProcessor.java | 14 ---- ...ationRefPostMethodInvocationProcessor.java | 23 +----- ...ficationPostMethodInvocationException.java | 80 ------------------- .../NodeRefPostMethodInvocationProcessor.java | 23 +----- ...eckValuePostMethodInvocationProcessor.java | 51 ++++++++++++ ...StoreRefPostMethodInvocationProcessor.java | 24 +----- .../EnforceClassificationTest.java | 32 +++----- ...PostMethodInvocationProcessorUnitTest.java | 8 -- 11 files changed, 87 insertions(+), 217 deletions(-) delete mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ClassificationPostMethodInvocationException.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index cf15c1b485..c3dd709f3b 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -95,6 +95,11 @@ class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AssociationRefPostMethodInvocationProcessor"> + + + T processSingleElement(T object); /** - * Abstract method to process a collection + * Processes a collection * * @param collection The collection to process * @return Processed collection */ - @SuppressWarnings("rawtypes") - protected abstract Collection processCollection(Collection collection); + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected Collection processCollection(Collection collection) + { + return CollectionUtils.filter(collection, new Filter() + { + @Override + public Boolean apply(Object element) + { + return processSingleElement(element) != null; + } + }); + } /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) @@ -61,13 +74,11 @@ public abstract class AbstractPostMethodInvocationProcessor extends BasePostMeth Collection collection = ((Collection) result); if (!collection.isEmpty()) { - checkObjectClass(collection.iterator().next()); result = (T) processCollection(collection); } } else { - checkObjectClass(result); result = processSingleElement(result); } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java index e077e6558d..300430cb81 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java @@ -18,12 +18,8 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import java.util.Collection; - import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.collections.CollectionUtils; -import org.alfresco.util.collections.Filter; /** * AssociationRef Post Method Invocation Processor @@ -48,7 +44,7 @@ public class AssociationRefPostMethodInvocationProcessor extends AbstractPostMet @Override protected T processSingleElement(T object) { - AssociationRef associationRef = (AssociationRef) object; + AssociationRef associationRef = getClassName().cast(object); NodeRef sourceRef = associationRef.getSourceRef(); NodeRef filteredSource = filter(sourceRef); @@ -58,21 +54,4 @@ public class AssociationRefPostMethodInvocationProcessor extends AbstractPostMet return (filteredSource == null || filteredTarget == null) ? null : object; } - - /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processCollection(java.util.Collection) - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - protected Collection processCollection(Collection collection) - { - return CollectionUtils.filter(collection, new Filter() - { - @Override - public Boolean apply(AssociationRef associationRef) - { - return processSingleElement(associationRef) != null; - } - }); - } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java index ba690141f2..9d681bcd02 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -23,7 +23,6 @@ import static org.alfresco.model.ContentModel.TYPE_CONTENT; import java.util.Collection; import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; -import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ClassificationPostMethodInvocationException.NotSupportedClassTypeException; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -135,19 +134,6 @@ public abstract class BasePostMethodInvocationProcessor getPostMethodInvocationProcessor().register(this); } - /** - * Checks if the given object's class is suitable for the processor - * - * @param object The object to process - */ - protected void checkObjectClass(Object object) - { - if (!(object.getClass().equals(getClassName()))) - { - throw new NotSupportedClassTypeException("The object is not an instance of '" + getClassName() + "' but '" + object.getClass() + "'."); - } - } - /** * Checks if the given object is a collection * diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java index 89a62e0714..5e00f06bda 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java @@ -18,12 +18,8 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import java.util.Collection; - import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.collections.CollectionUtils; -import org.alfresco.util.collections.Filter; /** * ChildAssociationRef Post Method Invocation Processor @@ -48,7 +44,7 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends AbstractPo @Override protected T processSingleElement(T object) { - ChildAssociationRef childAssociationRef = ((ChildAssociationRef) object); + ChildAssociationRef childAssociationRef = getClassName().cast(object); NodeRef childRef = childAssociationRef.getChildRef(); NodeRef filteredChildRef = filter(childRef); @@ -58,21 +54,4 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends AbstractPo return (filteredChildRef == null || filteredParentRef == null) ? null : object; } - - /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processCollection(java.util.Collection) - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - protected Collection processCollection(Collection collection) - { - return CollectionUtils.filter(collection, new Filter() - { - @Override - public Boolean apply(ChildAssociationRef childAssociationRef) - { - return processSingleElement(childAssociationRef) != null; - } - }); - } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ClassificationPostMethodInvocationException.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ClassificationPostMethodInvocationException.java deleted file mode 100644 index 8bb41253e4..0000000000 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ClassificationPostMethodInvocationException.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; - -import org.alfresco.error.AlfrescoRuntimeException; - -/** - * Generic class for any runtime exception thrown within the {@link BasePostMethodInvocationProcessor} and subclasses. - * - * @author Tuna Aksoy - * @since 3.0 - */ -public class ClassificationPostMethodInvocationException extends AlfrescoRuntimeException -{ - /** Serial version UID */ - private static final long serialVersionUID = 2614182915625548638L; - - /** - * Base classification post method invocation exception - * - * @param msgId The text which will be shown in the exception - */ - public ClassificationPostMethodInvocationException(String msgId) - { - super(msgId); - } - - /** - * Base classification post method invocation exception - * - * @param msgId The text which will be shown in the exception - * @param cause The cause of the exception - */ - public ClassificationPostMethodInvocationException(String msgId, Throwable cause) - { - super(msgId, cause); - } - - /** - * Represents a fatal error due to a wrong class type - */ - public static class NotSupportedClassTypeException extends ClassificationPostMethodInvocationException - { - /** Serial version UID */ - private static final long serialVersionUID = 7614080640030648878L; - - /** - * @param msgId The text which will be shown in the exception - */ - public NotSupportedClassTypeException(String msgId) - { - super(msgId); - } - - /** - * @param msgId The text which will be shown in the exception - * @param cause The cause of the exception - */ - public NotSupportedClassTypeException(String msgId, Throwable cause) - { - super(msgId, cause); - } - } -} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java index 4abde0e223..193fd47d0a 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java @@ -18,11 +18,7 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import java.util.Collection; - import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.collections.CollectionUtils; -import org.alfresco.util.collections.Filter; /** * NodeRef Post Method Invocation Processor @@ -47,24 +43,7 @@ public class NodeRefPostMethodInvocationProcessor extends AbstractPostMethodInvo @Override protected T processSingleElement(T object) { - NodeRef nodeRef = (NodeRef) object; + NodeRef nodeRef = getClassName().cast(object); return filter(nodeRef) == null ? null : object; } - - /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processCollection(java.util.Collection) - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - protected Collection processCollection(Collection collection) - { - return CollectionUtils.filter(collection, new Filter() - { - @Override - public Boolean apply(NodeRef nodeRef) - { - return processSingleElement(nodeRef) != null; - } - }); - } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java new file mode 100644 index 0000000000..0bb13ad1f1 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java @@ -0,0 +1,51 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import org.alfresco.repo.security.permissions.PermissionCheckValue; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Permission Check Value Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class PermissionCheckValuePostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + protected Class getClassName() + { + return PermissionCheckValue.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) + */ + @Override + protected T processSingleElement(T object) + { + PermissionCheckValue permissionCheckValue = getClassName().cast(object); + NodeRef nodeRef = permissionCheckValue.getNodeRef(); + return filter(nodeRef) == null ? null : object; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java index 5f9e39251b..6f3f773374 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java @@ -18,12 +18,8 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import java.util.Collection; - import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.util.collections.CollectionUtils; -import org.alfresco.util.collections.Filter; /** * StoreRef Post Method Invocation Processor @@ -48,24 +44,8 @@ public class StoreRefPostMethodInvocationProcessor extends AbstractPostMethodInv @Override protected T processSingleElement(T object) { - NodeRef nodeRef = getNodeService().getRootNode((StoreRef) object); + StoreRef storeRef = getClassName().cast(object); + NodeRef nodeRef = getNodeService().getRootNode(storeRef); return filter(nodeRef) == null ? null : object; } - - /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processCollection(java.util.Collection) - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - protected Collection processCollection(Collection collection) - { - return CollectionUtils.filter(collection, new Filter() - { - @Override - public Boolean apply(NodeRef nodeRef) - { - return processSingleElement(nodeRef) != null; - } - }); - } } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java index 6ed0072c4c..ed4ced735c 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java @@ -18,20 +18,8 @@ */ package org.alfresco.module.org_alfresco_module_rm.test.integration.classification; -import java.util.Collections; -import java.util.List; - import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; -import org.alfresco.module.org_alfresco_module_rm.classification.SecurityClearanceService; -import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; -import org.alfresco.repo.security.permissions.AccessDeniedException; -import org.alfresco.repo.security.permissions.impl.model.PermissionModel; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.util.GUID; /** * Enforce classification integration test @@ -42,16 +30,16 @@ import org.alfresco.util.GUID; public class EnforceClassificationTest extends BaseRMTestCase { /** test data */ - private static final String CLASSIFICATION_LEVEL1 = "level1"; - private static final String CLASSIFICATION_LEVEL2 = "level2"; - private static final String CLASSIFICATION_LEVEL3 = "level3"; - private static final String CLASSIFICATION_LEVEL4 = "level4"; - - private static final String CLASSIFICATION_REASON = "Test Reason 1"; - private static final String CLASSIFICATION_AUTHORITY = "classification.authority"; - private static final String RECORD_NAME = "recordname.txt"; - - private ContentClassificationService contentClassificationService; +// private static final String CLASSIFICATION_LEVEL1 = "level1"; +// private static final String CLASSIFICATION_LEVEL2 = "level2"; +// private static final String CLASSIFICATION_LEVEL3 = "level3"; +// private static final String CLASSIFICATION_LEVEL4 = "level4"; +// +// private static final String CLASSIFICATION_REASON = "Test Reason 1"; +// private static final String CLASSIFICATION_AUTHORITY = "classification.authority"; +// private static final String RECORD_NAME = "recordname.txt"; +// +// private ContentClassificationService contentClassificationService; @Override protected void initServices() diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java index 89735d7472..1d4ae13864 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java @@ -28,7 +28,6 @@ import static org.springframework.extensions.webscripts.GUID.generate; import java.util.ArrayList; import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; -import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ClassificationPostMethodInvocationException.NotSupportedClassTypeException; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; import org.alfresco.service.cmr.repository.NodeRef; import org.junit.Test; @@ -46,13 +45,6 @@ public class NodeRefPostMethodInvocationProcessorUnitTest extends BaseUnitTest @InjectMocks private NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor; @Mock private ContentClassificationService mockedContentClassificationService; - @Test (expected = NotSupportedClassTypeException.class) - public void testProccessingAnotherClassType() - { - NodeRef nodeRef = generateNodeRef(); - nodeRefPostMethodInvocationProcessor.process(nodeRef.getStoreRef()); - } - @Test public void testProcessingNonExistingNode() { From acccd7ca3a3b5b5bb693d1158ced32e4779cccc3 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Mon, 22 Jun 2015 21:52:08 +0000 Subject: [PATCH 16/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106772 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../processor/ListPostMethodInvocationProcessor.java | 9 --------- .../processor/SetPostMethodInvocationProcessor.java | 9 --------- 2 files changed, 18 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java index 0176f9c3e8..3c2cb1f6cf 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java @@ -37,13 +37,4 @@ public class ListPostMethodInvocationProcessor extends CollectionPostMethodInvoc { return List.class; } - - /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) - */ - @Override - public T process(T object) - { - return super.process(object); - } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java index c8536b65a7..c0abfd73f3 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java @@ -37,13 +37,4 @@ public class SetPostMethodInvocationProcessor extends CollectionPostMethodInvoca { return Set.class; } - - /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) - */ - @Override - public T process(T object) - { - return super.process(object); - } } From f1cb06d93778f42e6c7701ac5829453a37764bac Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Mon, 22 Jun 2015 22:41:26 +0000 Subject: [PATCH 17/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106774 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 8 + ...esultSetPostMethodInvocationProcessor.java | 100 +++++++++++++ ...tSetPostMethodInvocationProcessorTest.java | 137 ++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ResultSetPostMethodInvocationProcessorTest.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index c3dd709f3b..f53b4a81a6 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -119,6 +119,14 @@ class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ListPostMethodInvocationProcessor"> + + + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..b4694e9054 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java @@ -0,0 +1,100 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.BitSet; +import java.util.Iterator; +import java.util.List; + +import org.alfresco.repo.search.SimpleResultSetMetaData; +import org.alfresco.repo.security.permissions.impl.acegi.FilteringResultSet; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.search.PermissionEvaluationMode; +import org.alfresco.service.cmr.search.ResultSet; + +/** + * ResultSet Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class ResultSetPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + protected Class getClassName() + { + return ResultSet.class; + } + + // FIXME: Change implementation + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.CollectionPostMethodInvocationProcessor#process(java.lang.Object) + */ + @SuppressWarnings({ "unchecked" }) + @Override + public T process(T object) + { + T result = object; + ResultSet resultSet = getClassName().cast(result); + BitSet inclusionMask = new BitSet(resultSet.length()); + FilteringResultSet filteringResultSet = new FilteringResultSet(resultSet, inclusionMask); + + filteringResultSet.setResultSetMetaData( + new SimpleResultSetMetaData( + resultSet.getResultSetMetaData().getLimitedBy(), + PermissionEvaluationMode.EAGER, + resultSet.getResultSetMetaData().getSearchParameters())); + + List nodeRefs = resultSet.getNodeRefs(); + if (!nodeRefs.isEmpty()) + { + Iterator iterator = nodeRefs.iterator(); + BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(iterator.next()); + + for (int i = 0; i < nodeRefs.size(); i++) + { + if (processor.process(nodeRefs.get(i)) == null) + { + inclusionMask.set(i, false); + } + } + } + + List childAssocRefs = getClassName().cast(filteringResultSet).getChildAssocRefs(); + if (!childAssocRefs.isEmpty()) + { + Iterator iterator = childAssocRefs.iterator(); + BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(iterator.next()); + + for (int i = 0; i < childAssocRefs.size(); i++) + { + if (processor.process(nodeRefs.get(i)) == null) + { + inclusionMask.set(i, false); + } + } + } + + return (T) filteringResultSet; + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ResultSetPostMethodInvocationProcessorTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ResultSetPostMethodInvocationProcessorTest.java new file mode 100644 index 0000000000..8955ae82f9 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ResultSetPostMethodInvocationProcessorTest.java @@ -0,0 +1,137 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification; + +import static java.lang.Integer.MAX_VALUE; +import static org.alfresco.repo.site.SiteModel.SITE_MANAGER; +import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; +import static org.alfresco.service.cmr.search.SearchService.LANGUAGE_FTS_ALFRESCO; +import static org.alfresco.service.namespace.NamespaceService.CONTENT_MODEL_1_0_URI; +import static org.alfresco.util.GUID.generate; + +import java.util.List; + +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.SearchParameters; + +/** + * Integration test for ResultTest post method invocation processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class ResultSetPostMethodInvocationProcessorTest extends BaseRMTestCase +{ + private static final String LEVEL1 = "level1"; + private static final String REASON = "Test Reason 1"; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#isCollaborationSiteTest() + */ + @Override + protected boolean isCollaborationSiteTest() + { + return true; + } + + public void testResultSetPostMethodInvocationProcessor() + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private String myUser; + private NodeRef doc1; + private NodeRef doc2; + private String searchQuery = generate(); + private ResultSet result; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + myUser = generate(); + createPerson(myUser); + siteService.setMembership(collabSiteId, myUser, SITE_MANAGER); + + doc1 = fileFolderService.create(documentLibrary, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); + doc2 = fileFolderService.create(documentLibrary, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + //contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + SearchParameters searchParameters = new SearchParameters(); + searchParameters.setQuery("@cm\\:name:" + searchQuery + "*"); + searchParameters.setLanguage(LANGUAGE_FTS_ALFRESCO); + searchParameters.addStore(STORE_REF_WORKSPACE_SPACESSTORE); + searchParameters.setMaxItems(MAX_VALUE); + searchParameters.setNamespace(CONTENT_MODEL_1_0_URI); + result = searchService.query(searchParameters); + + return null; + } + }, myUser); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List nodeRefs = result.getNodeRefs(); + + assertEquals(2, nodeRefs.size()); + assertTrue(nodeRefs.contains(doc1)); + assertTrue(nodeRefs.contains(doc2)); + + return null; + } + }, myUser); + } + }); + } +} From 662b0db31fdccf8f9fb3f2293c706880be0531e3 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Wed, 24 Jun 2015 19:39:48 +0000 Subject: [PATCH 18/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107009 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 5 ++ .../documentlibrary-v2/rm-doclist.lib.js | 7 +- ...gResultsPostMethodInvocationProcessor.java | 81 +++++++++++++++++++ 3 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index f53b4a81a6..0fb83bd483 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -127,6 +127,11 @@ --> + + + diff --git a/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js b/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js index 710eed6a2e..3fcdb888af 100644 --- a/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js +++ b/rm-server/config/alfresco/templates/webscripts/org/alfresco/slingshot/documentlibrary-v2/rm-doclist.lib.js @@ -241,12 +241,7 @@ function rm_doclist_main() { // we have to check if we have read permission on the node parent as an error will be thrown if we try to // get the evaluated properties for a linked record whose parent we do not have read permissions for - var parentReadable; - try - { - parentReadable = (node.parent != null && node.parent.isContainer && node.parent.hasPermission("ReadRecords")); - } - catch(e){} + var parentReadable = (node.parent != null && node.parent.isContainer && node.parent.hasPermission("ReadRecords")); if (!parentReadable) continue; // Get evaluated properties. diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..e4f68bbb9d --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java @@ -0,0 +1,81 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.List; + +import org.alfresco.query.PagingResults; +import org.alfresco.util.Pair; + +/** + * PagingResults Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class PagingResultsPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @SuppressWarnings("rawtypes") + @Override + protected Class getClassName() + { + return PagingResults.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public T process(T object) + { + final PagingResults pagingResults = getClassName().cast(object); + List page = pagingResults.getPage(); + final List processedPage = getPostMethodInvocationProcessor().process(page); + + return (T) new PagingResults() + { + @Override + public String getQueryExecutionId() + { + return pagingResults.getQueryExecutionId(); + } + @Override + public List getPage() + { + return processedPage; + } + @Override + public boolean hasMoreItems() + { + // FIXME: hasMoreItems might not be correct + return pagingResults.hasMoreItems(); + } + @Override + public Pair getTotalResultCount() + { + int size = processedPage.size(); + return new Pair(size, size); + } + }; + } +} From 1ded55a6d8e94ed08446effd07afac5c998b4f5d Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Thu, 25 Jun 2015 22:44:42 +0000 Subject: [PATCH 19/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107163 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- ...DocumentClassificationEnforcementTest.java | 320 +++++++++++++++++ .../EnforceClassificationTest.java | 2 +- .../RecordClassificationEnforcementTest.java | 325 ++++++++++++++++++ ...ionshipClassificationEnforcementTest.java} | 12 +- ...tSetPostMethodInvocationProcessorTest.java | 5 +- 5 files changed, 655 insertions(+), 9 deletions(-) create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentClassificationEnforcementTest.java rename rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/{ => interceptor}/EnforceClassificationTest.java (99%) create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordClassificationEnforcementTest.java rename rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/{ClassificationPostMethodInvocationTest.java => interceptor/RelationshipClassificationEnforcementTest.java} (96%) rename rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/{ => interceptor}/ResultSetPostMethodInvocationProcessorTest.java (96%) diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentClassificationEnforcementTest.java new file mode 100644 index 0000000000..048fa464cb --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentClassificationEnforcementTest.java @@ -0,0 +1,320 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; + +import static com.google.common.collect.Lists.newArrayList; +import static com.google.common.collect.Sets.newHashSet; +import static org.alfresco.repo.site.SiteModel.SITE_MANAGER; +import static org.alfresco.util.GUID.generate; + +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Tests for enforcement of classification when browsing documents in the document library + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class DocumentClassificationEnforcementTest extends BaseRMTestCase +{ + private static final String LEVEL1 = "level1"; + private static final String LEVEL2 = "level2"; + private static final String REASON = "Test Reason 1"; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#isCollaborationSiteTest() + */ + @Override + protected boolean isCollaborationSiteTest() + { + return true; + } + + public void testUserWithNoSecurityClearance() + { + /** + * Given that a test user without security clearance exists + * and two documents are created in the document library + * + * When one of the documents is classified with the highest security level + * + * Then as the admin user I will see both documents + * and as the test user I will only see the unclassified document + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private String myUser; + private NodeRef folder; + private NodeRef doc1; + private NodeRef doc2; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + myUser = generate(); + createPerson(myUser); + siteService.setMembership(collabSiteId, myUser, SITE_MANAGER); + + folder = fileFolderService.create(documentLibrary, generate(), TYPE_FOLDER).getNodeRef(); + doc1 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + doc2 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssociationRefs = nodeService.getChildAssocs(folder); + assertNotNull(childAssociationRefs); + assertEquals(2, childAssociationRefs.size()); + + ArrayList docs = newArrayList(doc1, doc2); + assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssociationRefs = nodeService.getChildAssocs(folder); + assertNotNull(childAssociationRefs); + assertEquals(1, childAssociationRefs.size()); + assertEquals(doc2, childAssociationRefs.get(0).getChildRef()); + + return null; + } + }, myUser); + } + }); + } + + public void testUserWithMidlevelSecurityClearance() + { + /** + * Given that a test user with mid-level security clearance exists + * and three documents are created in the document library + * + * When one of the documents is classified with the highest security level + * and another document is classified with the mid-level security level + * + * Then as the admin user I will see all three documents + * and as the test user I will see the unclassified document + * and the document with the mid-level classification + * and I won't be able to see the document with the classification greater than my clearance level + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private String myUser; + private NodeRef folder; + private NodeRef doc1; + private NodeRef doc2; + private NodeRef doc3; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + myUser = generate(); + createPerson(myUser); + siteService.setMembership(collabSiteId, myUser, SITE_MANAGER); + securityClearanceService.setUserSecurityClearance(myUser, LEVEL2); + + folder = fileFolderService.create(documentLibrary, generate(), TYPE_FOLDER).getNodeRef(); + doc1 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + doc2 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + doc3 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), doc2); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssociationRefs = nodeService.getChildAssocs(folder); + assertNotNull(childAssociationRefs); + assertEquals(3, childAssociationRefs.size()); + + ArrayList docs = newArrayList(doc1, doc2, doc3); + assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssociationRefs = nodeService.getChildAssocs(folder); + assertNotNull(childAssociationRefs); + assertEquals(2, childAssociationRefs.size()); + + ArrayList docs = newArrayList(doc2, doc3); + assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + + return null; + } + }, myUser); + } + }); + } + + public void testUseWithHighestLevelSecurityClearance() + { + /** + * Given that a test user with highest level security clearance exists + * and three documents are created in the document library + * + * When one of the documents is classified with the highest security level + * and another document is classified with the mid-level security level + * + * Then as the admin user I will see all three documents + * and as the test user I will see all three documents + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private String myUser; + private NodeRef folder; + private NodeRef doc1; + private NodeRef doc2; + private NodeRef doc3; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + myUser = generate(); + createPerson(myUser); + siteService.setMembership(collabSiteId, myUser, SITE_MANAGER); + securityClearanceService.setUserSecurityClearance(myUser, LEVEL1); + + folder = fileFolderService.create(documentLibrary, generate(), TYPE_FOLDER).getNodeRef(); + doc1 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + doc2 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + doc3 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), doc2); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssociationRefs = nodeService.getChildAssocs(folder); + assertNotNull(childAssociationRefs); + assertEquals(3, childAssociationRefs.size()); + + ArrayList docs = newArrayList(doc1, doc2, doc3); + assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssociationRefs = nodeService.getChildAssocs(folder); + assertNotNull(childAssociationRefs); + assertEquals(3, childAssociationRefs.size()); + + ArrayList docs = newArrayList(doc1, doc2, doc3); + assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + + return null; + } + }, myUser); + } + }); + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/EnforceClassificationTest.java similarity index 99% rename from rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java rename to rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/EnforceClassificationTest.java index ed4ced735c..870e3086cb 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/EnforceClassificationTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/EnforceClassificationTest.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ -package org.alfresco.module.org_alfresco_module_rm.test.integration.classification; +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordClassificationEnforcementTest.java new file mode 100644 index 0000000000..f426165fd2 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordClassificationEnforcementTest.java @@ -0,0 +1,325 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; + +import static com.google.common.collect.Lists.newArrayList; +import static com.google.common.collect.Sets.newHashSet; +import static org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService.ROLE_USER; +import static org.alfresco.util.GUID.generate; + +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Enforcement of classification when browsing records in the file plan + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class RecordClassificationEnforcementTest extends BaseRMTestCase +{ + private static final String LEVEL1 = "level1"; + private static final String LEVEL2 = "level2"; + private static final String REASON = "Test Reason 1"; + + public void testUserWithNoSecurityClearance() + { + /** + * Given that a test user without security clearance exists + * and the test user is added to the RM Users role + * and a category, a folder and two records are created in the file plan + * + * When the test user is given read permissions on the category + * and one of the records is classified with the highest security level + * + * + * Then as the admin user I will see both records + * and as the test user I will only see the unclassified record + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private String myUser; + private NodeRef category; + private NodeRef folder; + private NodeRef record1; + private NodeRef record2; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + myUser = generate(); + createPerson(myUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, myUser); + + category = filePlanService.createRecordCategory(filePlan, generate()); + folder = recordFolderService.createRecordFolder(category, generate()); + record1 = utils.createRecord(folder, generate()); + record2 = utils.createRecord(folder, generate()); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + filePlanPermissionService.setPermission(category, myUser, READ_RECORDS); + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssocs = nodeService.getChildAssocs(folder); + assertEquals(2, childAssocs.size()); + + List recordList = newArrayList(record1, record2); + assertTrue(recordList.contains(childAssocs.get(0).getChildRef())); + assertTrue(recordList.contains(childAssocs.get(1).getChildRef())); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssocs = nodeService.getChildAssocs(folder); + assertEquals(1, childAssocs.size()); + assertEquals(record2, childAssocs.get(0).getChildRef()); + + return null; + } + }, myUser); + } + }); + } + + public void testUserWithMidlevelSecurityClearance() + { + /** + * Given that a test user with mid-level security clearance exists + * and the test user is added to the RM Users role + * and a category, a folder and three records are created in the file plan + * + * When the test user is given read permissions on the category + * and one of the records is classified with the highest security level + * and another record is classified with the mid-level security level + * + * Then as the admin user I will see all three records + * and as the test user I will see the unclassified record + * and the record with the mid-level classification + * and I won't be able to see the record with the classification greater than my clearance level + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private String myUser; + private NodeRef category; + private NodeRef folder; + private NodeRef record1; + private NodeRef record2; + private NodeRef record3; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + myUser = generate(); + createPerson(myUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, myUser); + securityClearanceService.setUserSecurityClearance(myUser, LEVEL2); + + category = filePlanService.createRecordCategory(filePlan, generate()); + folder = recordFolderService.createRecordFolder(category, generate()); + record1 = utils.createRecord(folder, generate()); + record2 = utils.createRecord(folder, generate()); + record3 = utils.createRecord(folder, generate()); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + filePlanPermissionService.setPermission(category, myUser, READ_RECORDS); + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), record2); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssociationRefs = nodeService.getChildAssocs(folder); + assertNotNull(childAssociationRefs); + assertEquals(3, childAssociationRefs.size()); + + ArrayList docs = newArrayList(record1, record2, record3); + assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssociationRefs = nodeService.getChildAssocs(folder); + assertNotNull(childAssociationRefs); + assertEquals(2, childAssociationRefs.size()); + + ArrayList docs = newArrayList(record2, record3); + assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + + return null; + } + }, myUser); + } + }); + } + + public void testUseWithHighestLevelSecurityClearance() + { + /** + * Given that a test user with highest level security clearance exists + * and the test user is added to the RM Users role + * and a category, a folder and three records are created in the file plan + * + * When the test user is given read permissions on the category + * and one of the records is classified with the highest security level + * and another record is classified with the mid-level security level + * + * Then as the admin user I will see all three records + * and as the test user I will see all three records + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private String myUser; + private NodeRef category; + private NodeRef folder; + private NodeRef record1; + private NodeRef record2; + private NodeRef record3; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + myUser = generate(); + createPerson(myUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, myUser); + securityClearanceService.setUserSecurityClearance(myUser, LEVEL1); + + category = filePlanService.createRecordCategory(filePlan, generate()); + folder = recordFolderService.createRecordFolder(category, generate()); + record1 = utils.createRecord(folder, generate()); + record2 = utils.createRecord(folder, generate()); + record3 = utils.createRecord(folder, generate()); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + filePlanPermissionService.setPermission(category, myUser, READ_RECORDS); + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), record2); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssociationRefs = nodeService.getChildAssocs(folder); + assertNotNull(childAssociationRefs); + assertEquals(3, childAssociationRefs.size()); + + ArrayList docs = newArrayList(record1, record2, record3); + assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + List childAssociationRefs = nodeService.getChildAssocs(folder); + assertNotNull(childAssociationRefs); + assertEquals(3, childAssociationRefs.size()); + + ArrayList docs = newArrayList(record1, record2, record3); + assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + + return null; + } + }, myUser); + } + }); + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ClassificationPostMethodInvocationTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RelationshipClassificationEnforcementTest.java similarity index 96% rename from rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ClassificationPostMethodInvocationTest.java rename to rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RelationshipClassificationEnforcementTest.java index e1cd6d2be9..f852c78172 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ClassificationPostMethodInvocationTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RelationshipClassificationEnforcementTest.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ -package org.alfresco.module.org_alfresco_module_rm.test.integration.classification; +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; @@ -32,18 +32,18 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; /** - * Classification Post Method Invocation Test + * Enforcement of classification for records with relationship * * @author Tuna Aksoy * @since 3.0 */ -public class ClassificationPostMethodInvocationTest extends BaseRMTestCase +public class RelationshipClassificationEnforcementTest extends BaseRMTestCase { private static final String LEVEL1 = "level1"; private static final String LEVEL3 = "level3"; private static final String REASON = "Test Reason 1"; - public void testClassificationPostMethodInvocation() + public void testRelationshipClassification() { /** * Given a test user has been created @@ -56,9 +56,9 @@ public class ClassificationPostMethodInvocationTest extends BaseRMTestCase * and a relationship between those two records has been created * * Then the admin user should see both records in the folder - * and the admin user should see in the relationship table + * and the admin user should see in the relationship table * (in the details page of the record) the other record - * + * * and the test user should see only the unclassified record in the same folder * and the relationship table should be empty. */ diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ResultSetPostMethodInvocationProcessorTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/ResultSetPostMethodInvocationProcessorTest.java similarity index 96% rename from rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ResultSetPostMethodInvocationProcessorTest.java rename to rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/ResultSetPostMethodInvocationProcessorTest.java index 8955ae82f9..2dc13c667b 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/ResultSetPostMethodInvocationProcessorTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/ResultSetPostMethodInvocationProcessorTest.java @@ -16,8 +16,9 @@ * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ -package org.alfresco.module.org_alfresco_module_rm.test.integration.classification; +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; +import static com.google.common.collect.Sets.newHashSet; import static java.lang.Integer.MAX_VALUE; import static org.alfresco.repo.site.SiteModel.SITE_MANAGER; import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; @@ -87,7 +88,7 @@ public class ResultSetPostMethodInvocationProcessorTest extends BaseRMTestCase @Override public Void run() { - //contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); return null; } From 03e696e5246c628756b5851c829b39b4afcf40e4 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Thu, 25 Jun 2015 22:45:52 +0000 Subject: [PATCH 20/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107164 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 18 ++++-- .../BasePostMethodInvocationProcessor.java | 64 +++++++++++++++++++ 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index 0fb83bd483..19a684a701 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -1,12 +1,12 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:aop="http://www.springframework.org/schema/aop" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/aop + http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> @@ -60,13 +60,17 @@ + + + + , Pair> cache; + /** * @return the nodeService */ @@ -71,6 +80,14 @@ public abstract class BasePostMethodInvocationProcessor return this.contentClassificationService; } + /** + * @return the securityClearanceService + */ + protected SecurityClearanceService getSecurityClearanceService() + { + return this.securityClearanceService; + } + /** * @return the postMethodInvocationProcessor */ @@ -79,6 +96,14 @@ public abstract class BasePostMethodInvocationProcessor return this.postMethodInvocationProcessor; } + /** + * @return the cache + */ + protected SimpleCache, Pair> getCache() + { + return this.cache; + } + /** * @param nodeService the nodeService to set */ @@ -103,6 +128,14 @@ public abstract class BasePostMethodInvocationProcessor this.contentClassificationService = contentClassificationService; } + /** + * @param securityClearanceService the securityClearanceService to set + */ + public void setSecurityClearanceService(SecurityClearanceService securityClearanceService) + { + this.securityClearanceService = securityClearanceService; + } + /** * @param postMethodInvocationProcessor the postMethodInvocationProcessor to set */ @@ -111,6 +144,14 @@ public abstract class BasePostMethodInvocationProcessor this.postMethodInvocationProcessor = postMethodInvocationProcessor; } + /** + * @param cache the cache to set + */ + public void setCache(SimpleCache, Pair> cache) + { + this.cache = cache; + } + /** * Gets the class name * @@ -164,6 +205,29 @@ public abstract class BasePostMethodInvocationProcessor filter = null; } +// if (filter != null) +// { +// String uniqueCacheKey = getFullyAuthenticatedUser() /*+ userClearance?*/; +// +// Pair cacheKey = new Pair(uniqueCacheKey, filter); +// Pair cacheValue = getCache().get(cacheKey); +// +// if (cacheValue == null || !cacheValue.getFirst().booleanValue()) +// { +// if (getNodeService().exists(nodeRef) && +// getDictionaryService().isSubClass(getNodeService().getType(nodeRef), TYPE_CONTENT) && +// !getContentClassificationService().hasClearance(nodeRef)) +// { +// filter = null; +// } +// getCache().put(new Pair(uniqueCacheKey, nodeRef), new Pair(true, filter)); +// } +// else +// { +// filter = getCache().get(cacheKey).getSecond(); +// } +// } + return filter; } } From 06ed0a60150bf5ab6892050737e995ea0924f3e2 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Fri, 26 Jun 2015 14:47:03 +0000 Subject: [PATCH 21/33] RM-2130 Post method invocation processor for QueryEngineResults. +review RM @taksoy git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107246 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../PostMethodInvocationProcessor.java | 24 +++++ ...eResultsPostMethodInvocationProcessor.java | 67 ++++++++++++++ ...PostMethodInvocationProcessorUnitTest.java | 89 +++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java create mode 100644 rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessorUnitTest.java diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java index 775d03a169..523db04e28 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java @@ -98,6 +98,30 @@ public class PostMethodInvocationProcessor return result; } + /** + * Gets the processor from the available processors. + * + * @param clazz The class of the post invocation object. + * @return The suitable processor for the given class. + */ + protected BasePostMethodInvocationProcessor getProcessorForClass(Class clazz) + { + mandatory("clazz", clazz); + BasePostMethodInvocationProcessor result = null; + + Set, BasePostMethodInvocationProcessor>> processorsEntrySet = getProcessors().entrySet(); + for (Map.Entry, BasePostMethodInvocationProcessor> processorEntry : processorsEntrySet) + { + if (processorEntry.getKey().isAssignableFrom(clazz)) + { + result = processorEntry.getValue(); + break; + } + } + + return result; + } + /** * Processes the given object * diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..3705335115 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java @@ -0,0 +1,67 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.search.impl.querymodel.QueryEngineResults; +import org.alfresco.service.cmr.search.ResultSet; + +/** + * A post method invocation processor for {@link QueryEngineResults}. + * + * @author Tom Page + * @since 3.0 + */ +public class QueryEngineResultsPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** The post method invocation processor for {@link ResultSet ResultSets}. */ + private BasePostMethodInvocationProcessor resultSetProcessor; + + @Override + protected Class getClassName() + { + return QueryEngineResults.class; + } + + @SuppressWarnings("unchecked") + @Override + public T process(T object) + { + if (resultSetProcessor == null) + { + resultSetProcessor = getPostMethodInvocationProcessor().getProcessorForClass(ResultSet.class); + } + + QueryEngineResults queryEngineResults = getClassName().cast(object); + Map, ResultSet> resultsMap = queryEngineResults.getResults(); + Map, ResultSet> returnMap = new HashMap<>(); + for (Set key : resultsMap.keySet()) + { + ResultSet newResultSet = resultSetProcessor.process(resultsMap.get(key)); + if (newResultSet != null) + { + returnMap.put(key, newResultSet); + } + } + return (T) new QueryEngineResults(returnMap); + } +} diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessorUnitTest.java new file mode 100644 index 0000000000..ed9ad9ef16 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessorUnitTest.java @@ -0,0 +1,89 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Sets; +import org.alfresco.repo.search.impl.querymodel.QueryEngineResults; +import org.alfresco.service.cmr.search.ResultSet; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +/** + * Unit tests for {@link QueryEngineResultPostMethodInvocationProcessor}. + * + * @author Tom Page + * @since 3.0 + */ +public class QueryEngineResultsPostMethodInvocationProcessorUnitTest +{ + private static final Set KEY_1 = Sets.newHashSet("KEY_1"); + private static final Set KEY_2 = Sets.newHashSet("KEY_2"); + private static final Set KEY_3 = Sets.newHashSet("KEY_3"); + private static final Set KEY_4 = Sets.newHashSet("KEY_4"); + private static final ResultSet UNCLASSIFIED_RESULT_SET = mock(ResultSet.class); + private static final ResultSet CLASSIFIED_RESULT_SET = mock(ResultSet.class); + + @InjectMocks + private QueryEngineResultsPostMethodInvocationProcessor processor = new QueryEngineResultsPostMethodInvocationProcessor(); + @Mock + private PostMethodInvocationProcessor mockPostMethodInvocationProcessor; + @Mock + private ResultSetPostMethodInvocationProcessor mockResultSetPMIP; + + @Before + public void setUp() + { + initMocks(this); + + when(mockPostMethodInvocationProcessor.getProcessorForClass(ResultSet.class)).thenReturn(mockResultSetPMIP); + + when(mockResultSetPMIP.process(UNCLASSIFIED_RESULT_SET)).thenReturn(UNCLASSIFIED_RESULT_SET); + when(mockResultSetPMIP.process(CLASSIFIED_RESULT_SET)).thenReturn(null); + } + + /** Check that {@code process} filters out the classified result sets. */ + @Test + public void testProcess() + { + Map, ResultSet> resultsMap = new HashMap<>(); + resultsMap.put(KEY_1, UNCLASSIFIED_RESULT_SET); + resultsMap.put(KEY_2, CLASSIFIED_RESULT_SET); + resultsMap.put(KEY_3, UNCLASSIFIED_RESULT_SET); + resultsMap.put(KEY_4, CLASSIFIED_RESULT_SET); + QueryEngineResults queryEngineResults = new QueryEngineResults(resultsMap); + + QueryEngineResults returnedQueryEngineResults = processor.process(queryEngineResults); + + Map, ResultSet> expectedResultSet = new HashMap<>(); + expectedResultSet.put(KEY_1, UNCLASSIFIED_RESULT_SET); + expectedResultSet.put(KEY_3, UNCLASSIFIED_RESULT_SET); + assertEquals("Unexpected results from query.", expectedResultSet, returnedQueryEngineResults.getResults()); + } +} From 423850002ec2b6e2beef9d1d593537ad62c2123e Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Fri, 26 Jun 2015 15:28:22 +0000 Subject: [PATCH 22/33] RM-2130 (Post method invocation processor for QueryEngineResults) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107252 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../PostMethodInvocationProcessor.java | 24 --------------- ...eResultsPostMethodInvocationProcessor.java | 30 ++++++++++++------- ...PostMethodInvocationProcessorUnitTest.java | 6 ++-- 3 files changed, 23 insertions(+), 37 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java index 523db04e28..775d03a169 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java @@ -98,30 +98,6 @@ public class PostMethodInvocationProcessor return result; } - /** - * Gets the processor from the available processors. - * - * @param clazz The class of the post invocation object. - * @return The suitable processor for the given class. - */ - protected BasePostMethodInvocationProcessor getProcessorForClass(Class clazz) - { - mandatory("clazz", clazz); - BasePostMethodInvocationProcessor result = null; - - Set, BasePostMethodInvocationProcessor>> processorsEntrySet = getProcessors().entrySet(); - for (Map.Entry, BasePostMethodInvocationProcessor> processorEntry : processorsEntrySet) - { - if (processorEntry.getKey().isAssignableFrom(clazz)) - { - result = processorEntry.getValue(); - break; - } - } - - return result; - } - /** * Processes the given object * diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java index 3705335115..760b95afe6 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java @@ -20,6 +20,7 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.pr import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import org.alfresco.repo.search.impl.querymodel.QueryEngineResults; @@ -33,35 +34,42 @@ import org.alfresco.service.cmr.search.ResultSet; */ public class QueryEngineResultsPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { - /** The post method invocation processor for {@link ResultSet ResultSets}. */ - private BasePostMethodInvocationProcessor resultSetProcessor; - + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ @Override protected Class getClassName() { return QueryEngineResults.class; } + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ @SuppressWarnings("unchecked") @Override public T process(T object) { - if (resultSetProcessor == null) - { - resultSetProcessor = getPostMethodInvocationProcessor().getProcessorForClass(ResultSet.class); - } - QueryEngineResults queryEngineResults = getClassName().cast(object); Map, ResultSet> resultsMap = queryEngineResults.getResults(); Map, ResultSet> returnMap = new HashMap<>(); - for (Set key : resultsMap.keySet()) + BasePostMethodInvocationProcessor processor = null; + + for (Entry, ResultSet> entry : resultsMap.entrySet()) { - ResultSet newResultSet = resultSetProcessor.process(resultsMap.get(key)); + ResultSet value = entry.getValue(); + if (processor == null) + { + processor = getPostMethodInvocationProcessor().getProcessor(value); + } + + ResultSet newResultSet = processor.process(value); if (newResultSet != null) { - returnMap.put(key, newResultSet); + returnMap.put(entry.getKey(), newResultSet); } } + return (T) new QueryEngineResults(returnMap); } } diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessorUnitTest.java index ed9ad9ef16..7718b2e492 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessorUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessorUnitTest.java @@ -27,13 +27,15 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -import com.google.common.collect.Sets; import org.alfresco.repo.search.impl.querymodel.QueryEngineResults; import org.alfresco.service.cmr.search.ResultSet; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; + +import com.google.common.collect.Sets; /** * Unit tests for {@link QueryEngineResultPostMethodInvocationProcessor}. @@ -62,7 +64,7 @@ public class QueryEngineResultsPostMethodInvocationProcessorUnitTest { initMocks(this); - when(mockPostMethodInvocationProcessor.getProcessorForClass(ResultSet.class)).thenReturn(mockResultSetPMIP); + when(mockPostMethodInvocationProcessor.getProcessor(Mockito.any())).thenReturn(mockResultSetPMIP); when(mockResultSetPMIP.process(UNCLASSIFIED_RESULT_SET)).thenReturn(UNCLASSIFIED_RESULT_SET); when(mockResultSetPMIP.process(CLASSIFIED_RESULT_SET)).thenReturn(null); From b1e8da11987b15d314d6946afd6267faee7c87aa Mon Sep 17 00:00:00 2001 From: Tom Page Date: Fri, 26 Jun 2015 15:36:13 +0000 Subject: [PATCH 23/33] RM-2130 Make CollectionPostMethodInvocationProcessor concrete. +review RM-113 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107253 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- ...llectionPostMethodInvocationProcessor.java | 11 +++-- .../ListPostMethodInvocationProcessor.java | 40 ------------------- .../SetPostMethodInvocationProcessor.java | 40 ------------------- 3 files changed, 7 insertions(+), 84 deletions(-) delete mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java delete mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java index 7c0160f65f..109c86cc38 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -27,11 +27,8 @@ import java.util.Iterator; * @author Tuna Aksoy * @since 3.0 */ -public abstract class CollectionPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +public class CollectionPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { - /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) - */ @SuppressWarnings({ "rawtypes" }) @Override public T process(T object) @@ -57,4 +54,10 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe return result; } + + @Override + protected Class getClassName() + { + return Collection.class; + } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java deleted file mode 100644 index 3c2cb1f6cf..0000000000 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; - -import java.util.List; - -/** - * List Post Method Invocation Processor - * - * @author Tuna Aksoy - * @since 3.0 - */ -public class ListPostMethodInvocationProcessor extends CollectionPostMethodInvocationProcessor -{ - /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() - */ - @SuppressWarnings("rawtypes") - @Override - protected Class getClassName() - { - return List.class; - } -} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java deleted file mode 100644 index c0abfd73f3..0000000000 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; - -import java.util.Set; - -/** - * Set Post Method Invocation Processor - * - * @author Tuna Aksoy - * @since 3.0 - */ -public class SetPostMethodInvocationProcessor extends CollectionPostMethodInvocationProcessor -{ - /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() - */ - @SuppressWarnings("rawtypes") - @Override - protected Class getClassName() - { - return Set.class; - } -} From 74267d0119d16d430a8e8156fcde832eab107f78 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Fri, 26 Jun 2015 16:00:26 +0000 Subject: [PATCH 24/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107257 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 24 +++++++------------ ...llectionPostMethodInvocationProcessor.java | 20 ++++++++++------ 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index 19a684a701..22e25be2d7 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -110,34 +110,26 @@ class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.CollectionPostMethodInvocationProcessor"> - - - - - - + + + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java index 109c86cc38..e23ce5ab6e 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -29,7 +29,19 @@ import java.util.Iterator; */ public class CollectionPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { - @SuppressWarnings({ "rawtypes" }) + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + protected Class getClassName() + { + return Collection.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @SuppressWarnings("rawtypes") @Override public T process(T object) { @@ -54,10 +66,4 @@ public class CollectionPostMethodInvocationProcessor extends BasePostMethodInvoc return result; } - - @Override - protected Class getClassName() - { - return Collection.class; - } } From 8fa46a4e14f7c05a791c3ae401bb7cef8c3b3563 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sat, 27 Jun 2015 22:23:19 +0000 Subject: [PATCH 25/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107270 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 4 - ...llectionPostMethodInvocationProcessor.java | 4 +- ...esultSetPostMethodInvocationProcessor.java | 82 +++-- ...owseClassificationEnforcementTestBase.java | 63 ++++ ...tBrowseClassificationEnforcementTest.java} | 160 ++++----- ...ntSearchClassificationEnforcementTest.java | 317 ++++++++++++++++++ ...dBrowseClassificationEnforcementTest.java} | 168 +++++----- ...tSetPostMethodInvocationProcessorTest.java | 138 -------- ...archClassificationEnforcementTestBase.java | 71 ++++ 9 files changed, 675 insertions(+), 332 deletions(-) create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/BrowseClassificationEnforcementTestBase.java rename rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/{DocumentClassificationEnforcementTest.java => DocumentBrowseClassificationEnforcementTest.java} (64%) create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentSearchClassificationEnforcementTest.java rename rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/{RecordClassificationEnforcementTest.java => RecordBrowseClassificationEnforcementTest.java} (66%) delete mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/ResultSetPostMethodInvocationProcessorTest.java create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SearchClassificationEnforcementTestBase.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index 22e25be2d7..937e508e6b 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -105,18 +105,14 @@ - - getClassName() { - return Collection.class; + // FIXME!!! + return List.class; } /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java index b4694e9054..2378faa442 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java @@ -18,16 +18,18 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; +import static org.alfresco.service.cmr.search.PermissionEvaluationMode.EAGER; + import java.util.BitSet; -import java.util.Iterator; -import java.util.List; import org.alfresco.repo.search.SimpleResultSetMetaData; import org.alfresco.repo.security.permissions.impl.acegi.FilteringResultSet; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.search.PermissionEvaluationMode; import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.ResultSetMetaData; +import org.alfresco.service.cmr.search.ResultSetRow; +import org.alfresco.service.cmr.search.SearchParameters; /** * ResultSet Post Method Invocation Processor @@ -46,7 +48,6 @@ public class ResultSetPostMethodInvocationProcessor extends BasePostMethodInvoca return ResultSet.class; } - // FIXME: Change implementation /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.CollectionPostMethodInvocationProcessor#process(java.lang.Object) */ @@ -55,46 +56,61 @@ public class ResultSetPostMethodInvocationProcessor extends BasePostMethodInvoca public T process(T object) { T result = object; - ResultSet resultSet = getClassName().cast(result); - BitSet inclusionMask = new BitSet(resultSet.length()); - FilteringResultSet filteringResultSet = new FilteringResultSet(resultSet, inclusionMask); - filteringResultSet.setResultSetMetaData( - new SimpleResultSetMetaData( - resultSet.getResultSetMetaData().getLimitedBy(), - PermissionEvaluationMode.EAGER, - resultSet.getResultSetMetaData().getSearchParameters())); - - List nodeRefs = resultSet.getNodeRefs(); - if (!nodeRefs.isEmpty()) + if (result != null) { - Iterator iterator = nodeRefs.iterator(); - BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(iterator.next()); + ResultSet returnedObject = getClassName().cast(object); - for (int i = 0; i < nodeRefs.size(); i++) + BitSet inclusionMask = new BitSet(returnedObject.length()); + FilteringResultSet filteringResultSet = new FilteringResultSet(returnedObject, inclusionMask); + + ResultSetMetaData resultSetMetaData = returnedObject.getResultSetMetaData(); + SearchParameters searchParameters = resultSetMetaData.getSearchParameters(); + + BasePostMethodInvocationProcessor nodeRefProcessor = null; + BasePostMethodInvocationProcessor childAssociationRefProcessor = null; + + for (int i = 0; i < returnedObject.length(); i++) { - if (processor.process(nodeRefs.get(i)) == null) + ResultSetRow row = returnedObject.getRow(i); + NodeRef nodeRef = row.getNodeRef(); + + if (nodeRefProcessor == null) + { + nodeRefProcessor = getPostMethodInvocationProcessor().getProcessor(nodeRef); + } + + NodeRef processedNodeRef = nodeRefProcessor.process(nodeRef); + if (processedNodeRef == null) { inclusionMask.set(i, false); } - } - } - - List childAssocRefs = getClassName().cast(filteringResultSet).getChildAssocRefs(); - if (!childAssocRefs.isEmpty()) - { - Iterator iterator = childAssocRefs.iterator(); - BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(iterator.next()); - - for (int i = 0; i < childAssocRefs.size(); i++) - { - if (processor.process(nodeRefs.get(i)) == null) + else { - inclusionMask.set(i, false); + ChildAssociationRef childAssocRef = row.getChildAssocRef(); + + if (childAssociationRefProcessor == null) + { + childAssociationRefProcessor = getPostMethodInvocationProcessor().getProcessor(childAssocRef); + } + + ChildAssociationRef childAssociationRef = childAssociationRefProcessor.process(childAssocRef); + if (childAssociationRef == null) + { + inclusionMask.set(i, false); + } + else + { + inclusionMask.set(i, true); + } } } + + SimpleResultSetMetaData simpleResultSetMetaData = new SimpleResultSetMetaData(resultSetMetaData.getLimitedBy(), EAGER, searchParameters); + filteringResultSet.setResultSetMetaData(simpleResultSetMetaData); + result = (T) filteringResultSet; } - return (T) filteringResultSet; + return result; } } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/BrowseClassificationEnforcementTestBase.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/BrowseClassificationEnforcementTestBase.java new file mode 100644 index 0000000000..ebfc0e51ed --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/BrowseClassificationEnforcementTestBase.java @@ -0,0 +1,63 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; + +import static org.alfresco.repo.security.authentication.AuthenticationUtil.getAdminUserName; + +import java.util.List; + +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Base class for classification enforcement tests for the browse action + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class BrowseClassificationEnforcementTestBase extends BaseRMTestCase +{ + protected String testUser; + protected static final String LEVEL1 = "level1"; + protected static final String LEVEL2 = "level2"; + protected static final String REASON = "Test Reason 1"; + + protected List browse(NodeRef folder, String userName) + { + return doTestInTransaction(new Test>() + { + @Override + public List run() + { + return nodeService.getChildAssocs(folder); + } + }, userName); + } + + protected List browseAsAdmin(NodeRef folder) + { + return browse(folder, getAdminUserName()); + } + + protected List browseAsTestUser(NodeRef folder) + { + return browse(folder, testUser); + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentBrowseClassificationEnforcementTest.java similarity index 64% rename from rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentClassificationEnforcementTest.java rename to rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentBrowseClassificationEnforcementTest.java index 048fa464cb..b7c8b364e7 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentClassificationEnforcementTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentBrowseClassificationEnforcementTest.java @@ -23,10 +23,8 @@ import static com.google.common.collect.Sets.newHashSet; import static org.alfresco.repo.site.SiteModel.SITE_MANAGER; import static org.alfresco.util.GUID.generate; -import java.util.ArrayList; import java.util.List; -import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; @@ -36,12 +34,8 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Tuna Aksoy * @since 3.0 */ -public class DocumentClassificationEnforcementTest extends BaseRMTestCase +public class DocumentBrowseClassificationEnforcementTest extends BrowseClassificationEnforcementTestBase { - private static final String LEVEL1 = "level1"; - private static final String LEVEL2 = "level2"; - private static final String REASON = "Test Reason 1"; - /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#isCollaborationSiteTest() */ @@ -56,18 +50,21 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase /** * Given that a test user without security clearance exists * and two documents are created in the document library + * and one of the documents is classified with the highest security level * - * When one of the documents is classified with the highest security level + * When I browse the document library as admin + * Then I will see both documents * - * Then as the admin user I will see both documents - * and as the test user I will only see the unclassified document + * When I browse the document library as the test user + * Then I will only see the unclassified document */ doBehaviourDrivenTest(new BehaviourDrivenTest() { - private String myUser; private NodeRef folder; private NodeRef doc1; private NodeRef doc2; + private List resultsForAdmin; + private List resultsForTestUser; /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() @@ -75,13 +72,15 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public void given() throws Exception { - myUser = generate(); - createPerson(myUser); - siteService.setMembership(collabSiteId, myUser, SITE_MANAGER); + testUser = generate(); + createPerson(testUser); + siteService.setMembership(collabSiteId, testUser, SITE_MANAGER); folder = fileFolderService.create(documentLibrary, generate(), TYPE_FOLDER).getNodeRef(); doc1 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); doc2 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); } /** @@ -90,7 +89,8 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public void when() throws Exception { - contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + resultsForAdmin = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); } /** @@ -104,13 +104,12 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssociationRefs = nodeService.getChildAssocs(folder); - assertNotNull(childAssociationRefs); - assertEquals(2, childAssociationRefs.size()); + assertNotNull(resultsForAdmin); + assertEquals(2, resultsForAdmin.size()); - ArrayList docs = newArrayList(doc1, doc2); - assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + List docs = newArrayList(doc1, doc2); + assertTrue(docs.contains(resultsForAdmin.get(0).getChildRef())); + assertTrue(docs.contains(resultsForAdmin.get(1).getChildRef())); return null; } @@ -121,14 +120,13 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssociationRefs = nodeService.getChildAssocs(folder); - assertNotNull(childAssociationRefs); - assertEquals(1, childAssociationRefs.size()); - assertEquals(doc2, childAssociationRefs.get(0).getChildRef()); + assertNotNull(resultsForTestUser); + assertEquals(1, resultsForTestUser.size()); + assertEquals(doc2, resultsForTestUser.get(0).getChildRef()); return null; } - }, myUser); + }, testUser); } }); } @@ -138,22 +136,25 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase /** * Given that a test user with mid-level security clearance exists * and three documents are created in the document library - * - * When one of the documents is classified with the highest security level + * and one of the documents is classified with the highest security level * and another document is classified with the mid-level security level * - * Then as the admin user I will see all three documents - * and as the test user I will see the unclassified document + * When I browse the document library as admin + * Then I will see all three documents + * + * When I browse the document library as the test user + * Then I will see the unclassified document * and the document with the mid-level classification * and I won't be able to see the document with the classification greater than my clearance level */ doBehaviourDrivenTest(new BehaviourDrivenTest() { - private String myUser; private NodeRef folder; private NodeRef doc1; private NodeRef doc2; private NodeRef doc3; + private List resultsForAdmin; + private List resultsForTestUser; /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() @@ -161,15 +162,18 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public void given() throws Exception { - myUser = generate(); - createPerson(myUser); - siteService.setMembership(collabSiteId, myUser, SITE_MANAGER); - securityClearanceService.setUserSecurityClearance(myUser, LEVEL2); + testUser = generate(); + createPerson(testUser); + siteService.setMembership(collabSiteId, testUser, SITE_MANAGER); + securityClearanceService.setUserSecurityClearance(testUser, LEVEL2); folder = fileFolderService.create(documentLibrary, generate(), TYPE_FOLDER).getNodeRef(); doc1 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); doc2 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); doc3 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), doc2); } /** @@ -178,8 +182,8 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public void when() throws Exception { - contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); - contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), doc2); + resultsForAdmin = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); } /** @@ -193,14 +197,13 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssociationRefs = nodeService.getChildAssocs(folder); - assertNotNull(childAssociationRefs); - assertEquals(3, childAssociationRefs.size()); + assertNotNull(resultsForAdmin); + assertEquals(3, resultsForAdmin.size()); - ArrayList docs = newArrayList(doc1, doc2, doc3); - assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + List docs = newArrayList(doc1, doc2, doc3); + assertTrue(docs.contains(resultsForAdmin.get(0).getChildRef())); + assertTrue(docs.contains(resultsForAdmin.get(1).getChildRef())); + assertTrue(docs.contains(resultsForAdmin.get(2).getChildRef())); return null; } @@ -211,17 +214,16 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssociationRefs = nodeService.getChildAssocs(folder); - assertNotNull(childAssociationRefs); - assertEquals(2, childAssociationRefs.size()); + assertNotNull(resultsForTestUser); + assertEquals(2, resultsForTestUser.size()); - ArrayList docs = newArrayList(doc2, doc3); - assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + List docs = newArrayList(doc2, doc3); + assertTrue(docs.contains(resultsForTestUser.get(0).getChildRef())); + assertTrue(docs.contains(resultsForTestUser.get(1).getChildRef())); return null; } - }, myUser); + }, testUser); } }); } @@ -231,20 +233,23 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase /** * Given that a test user with highest level security clearance exists * and three documents are created in the document library - * - * When one of the documents is classified with the highest security level + * and one of the documents is classified with the highest security level * and another document is classified with the mid-level security level * - * Then as the admin user I will see all three documents - * and as the test user I will see all three documents + * When I browse the document library as admin + * The I will see all three documents + * + * When I browse the document library as the test user + * The I will see all three documents */ doBehaviourDrivenTest(new BehaviourDrivenTest() { - private String myUser; private NodeRef folder; private NodeRef doc1; private NodeRef doc2; private NodeRef doc3; + private List resultsForAdmin; + private List resultsForTestUser; /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() @@ -252,15 +257,18 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public void given() throws Exception { - myUser = generate(); - createPerson(myUser); - siteService.setMembership(collabSiteId, myUser, SITE_MANAGER); - securityClearanceService.setUserSecurityClearance(myUser, LEVEL1); + testUser = generate(); + createPerson(testUser); + siteService.setMembership(collabSiteId, testUser, SITE_MANAGER); + securityClearanceService.setUserSecurityClearance(testUser, LEVEL1); folder = fileFolderService.create(documentLibrary, generate(), TYPE_FOLDER).getNodeRef(); doc1 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); doc2 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); doc3 = fileFolderService.create(folder, generate(), TYPE_CONTENT).getNodeRef(); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), doc2); } /** @@ -269,8 +277,8 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public void when() throws Exception { - contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); - contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), doc2); + resultsForAdmin = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); } /** @@ -284,14 +292,13 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssociationRefs = nodeService.getChildAssocs(folder); - assertNotNull(childAssociationRefs); - assertEquals(3, childAssociationRefs.size()); + assertNotNull(resultsForAdmin); + assertEquals(3, resultsForAdmin.size()); - ArrayList docs = newArrayList(doc1, doc2, doc3); - assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + List docs = newArrayList(doc1, doc2, doc3); + assertTrue(docs.contains(resultsForAdmin.get(0).getChildRef())); + assertTrue(docs.contains(resultsForAdmin.get(1).getChildRef())); + assertTrue(docs.contains(resultsForAdmin.get(2).getChildRef())); return null; } @@ -302,18 +309,17 @@ public class DocumentClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssociationRefs = nodeService.getChildAssocs(folder); - assertNotNull(childAssociationRefs); - assertEquals(3, childAssociationRefs.size()); + assertNotNull(resultsForTestUser); + assertEquals(3, resultsForTestUser.size()); - ArrayList docs = newArrayList(doc1, doc2, doc3); - assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + List docs = newArrayList(doc1, doc2, doc3); + assertTrue(docs.contains(resultsForTestUser.get(0).getChildRef())); + assertTrue(docs.contains(resultsForTestUser.get(1).getChildRef())); + assertTrue(docs.contains(resultsForTestUser.get(2).getChildRef())); return null; } - }, myUser); + }, testUser); } }); } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentSearchClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentSearchClassificationEnforcementTest.java new file mode 100644 index 0000000000..33e829353a --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentSearchClassificationEnforcementTest.java @@ -0,0 +1,317 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; + +import static com.google.common.collect.Sets.newHashSet; +import static org.alfresco.repo.site.SiteModel.SITE_MANAGER; +import static org.alfresco.util.GUID.generate; + +import java.util.List; + +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Tests for enforcement of classification when searching documents in the document library + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class DocumentSearchClassificationEnforcementTest extends SearchClassificationEnforcementTestBase +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#isCollaborationSiteTest() + */ + @Override + protected boolean isCollaborationSiteTest() + { + return true; + } + + public void testUserWithNoSecurityClearance() + { + /** + * Given that a test user without security clearance exists + * and two documents are created in the document library + * and one of the documents is classified with the highest security level + * + * When I search for the documents as admin + * Then I will see both documents + * + * When I search for the documents as the test user + * Then I will only see the unclassified document + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private NodeRef folder; + private NodeRef doc1; + private NodeRef doc2; + private String searchQuery = generate(); + private List resultsForAdmin; + private List resultsForTestUser; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + testUser = generate(); + createPerson(testUser); + siteService.setMembership(collabSiteId, testUser, SITE_MANAGER); + + folder = fileFolderService.create(documentLibrary, generate(), TYPE_FOLDER).getNodeRef(); + doc1 = fileFolderService.create(folder, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); + doc2 = fileFolderService.create(folder, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + resultsForAdmin = searchAsAdmin(searchQuery); + resultsForTestUser = searchAsTestUser(searchQuery); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForAdmin); + assertEquals(2, resultsForAdmin.size()); + assertTrue(resultsForAdmin.contains(doc1)); + assertTrue(resultsForAdmin.contains(doc2)); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(1, resultsForTestUser.size()); + assertTrue(resultsForTestUser.contains(doc2)); + + return null; + } + }, testUser); + } + }); + } + + public void testUserWithMidlevelSecurityClearance() + { + /** + * Given that a test user with mid-level security clearance exists + * and three documents are created in the document library + * and one of the documents is classified with the highest security level + * and another document is classified with the mid-level security level + * + * When I search for the documents as admin + * Then I will see all three documents + * + * When I search for the documents as the test user + * Then I will see the unclassified document + * and the document with the mid-level classification + * and I won't be able to see the document with the classification greater than my clearance level + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private NodeRef folder; + private NodeRef doc1; + private NodeRef doc2; + private NodeRef doc3; + private String searchQuery = generate(); + private List resultsForAdmin; + private List resultsForTestUser; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + testUser = generate(); + createPerson(testUser); + siteService.setMembership(collabSiteId, testUser, SITE_MANAGER); + securityClearanceService.setUserSecurityClearance(testUser, LEVEL2); + + folder = fileFolderService.create(documentLibrary, generate(), TYPE_FOLDER).getNodeRef(); + doc1 = fileFolderService.create(folder, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); + doc2 = fileFolderService.create(folder, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); + doc3 = fileFolderService.create(folder, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), doc2); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + resultsForAdmin = searchAsAdmin(searchQuery); + resultsForTestUser = searchAsTestUser(searchQuery); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForAdmin); + assertEquals(3, resultsForAdmin.size()); + assertTrue(resultsForAdmin.contains(doc1)); + assertTrue(resultsForAdmin.contains(doc2)); + assertTrue(resultsForAdmin.contains(doc3)); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(2, resultsForTestUser.size()); + assertTrue(resultsForTestUser.contains(doc2)); + assertTrue(resultsForTestUser.contains(doc3)); + + return null; + } + }, testUser); + } + }); + } + + public void testUseWithHighestLevelSecurityClearance() + { + /** + * Given that a test user with highest level security clearance exists + * and three documents are created in the document library + * and one of the documents is classified with the highest security level + * and another document is classified with the mid-level security level + * + * When I search for the documents as admin + * Then I will see all three documents + * + * When I search for the documents as the test user + * Then I will see all three documents + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private NodeRef folder; + private NodeRef doc1; + private NodeRef doc2; + private NodeRef doc3; + private String searchQuery = generate(); + private List resultsForAdmin; + private List resultsForTestUser; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + testUser = generate(); + createPerson(testUser); + siteService.setMembership(collabSiteId, testUser, SITE_MANAGER); + securityClearanceService.setUserSecurityClearance(testUser, LEVEL1); + + folder = fileFolderService.create(documentLibrary, generate(), TYPE_FOLDER).getNodeRef(); + doc1 = fileFolderService.create(folder, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); + doc2 = fileFolderService.create(folder, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); + doc3 = fileFolderService.create(folder, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), doc2); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + resultsForAdmin = searchAsAdmin(searchQuery); + resultsForTestUser = searchAsTestUser(searchQuery); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForAdmin); + assertEquals(3, resultsForAdmin.size()); + assertTrue(resultsForAdmin.contains(doc1)); + assertTrue(resultsForAdmin.contains(doc2)); + assertTrue(resultsForAdmin.contains(doc3)); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(3, resultsForTestUser.size()); + assertTrue(resultsForTestUser.contains(doc1)); + assertTrue(resultsForTestUser.contains(doc2)); + assertTrue(resultsForTestUser.contains(doc3)); + + return null; + } + }, testUser); + } + }); + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordBrowseClassificationEnforcementTest.java similarity index 66% rename from rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordClassificationEnforcementTest.java rename to rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordBrowseClassificationEnforcementTest.java index f426165fd2..d7a28a7d98 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordClassificationEnforcementTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordBrowseClassificationEnforcementTest.java @@ -23,10 +23,8 @@ import static com.google.common.collect.Sets.newHashSet; import static org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService.ROLE_USER; import static org.alfresco.util.GUID.generate; -import java.util.ArrayList; import java.util.List; -import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; @@ -36,33 +34,31 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Tuna Aksoy * @since 3.0 */ -public class RecordClassificationEnforcementTest extends BaseRMTestCase +public class RecordBrowseClassificationEnforcementTest extends BrowseClassificationEnforcementTestBase { - private static final String LEVEL1 = "level1"; - private static final String LEVEL2 = "level2"; - private static final String REASON = "Test Reason 1"; - public void testUserWithNoSecurityClearance() { /** * Given that a test user without security clearance exists * and the test user is added to the RM Users role * and a category, a folder and two records are created in the file plan - * - * When the test user is given read permissions on the category + * and the test user is given read permissions on the category * and one of the records is classified with the highest security level * + * When I browse the file plan as admin + * Then I will see both documents * - * Then as the admin user I will see both records - * and as the test user I will only see the unclassified record + * When I browse the file plan as the test user + * Then I will only see the unclassified record */ doBehaviourDrivenTest(new BehaviourDrivenTest() { - private String myUser; private NodeRef category; private NodeRef folder; private NodeRef record1; private NodeRef record2; + private List resultsForAdmin; + private List resultsForTestUser; /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() @@ -70,14 +66,16 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public void given() throws Exception { - myUser = generate(); - createPerson(myUser); - filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, myUser); + testUser = generate(); + createPerson(testUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, testUser); category = filePlanService.createRecordCategory(filePlan, generate()); folder = recordFolderService.createRecordFolder(category, generate()); record1 = utils.createRecord(folder, generate()); record2 = utils.createRecord(folder, generate()); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); } /** @@ -86,8 +84,10 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public void when() throws Exception { - filePlanPermissionService.setPermission(category, myUser, READ_RECORDS); - contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + filePlanPermissionService.setPermission(category, testUser, READ_RECORDS); + + resultsForAdmin = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); } /** @@ -101,12 +101,12 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssocs = nodeService.getChildAssocs(folder); - assertEquals(2, childAssocs.size()); + assertNotNull(resultsForAdmin); + assertEquals(2, resultsForAdmin.size()); - List recordList = newArrayList(record1, record2); - assertTrue(recordList.contains(childAssocs.get(0).getChildRef())); - assertTrue(recordList.contains(childAssocs.get(1).getChildRef())); + List records = newArrayList(record1, record2); + assertTrue(records.contains(resultsForAdmin.get(0).getChildRef())); + assertTrue(records.contains(resultsForAdmin.get(1).getChildRef())); return null; } @@ -117,13 +117,13 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssocs = nodeService.getChildAssocs(folder); - assertEquals(1, childAssocs.size()); - assertEquals(record2, childAssocs.get(0).getChildRef()); + assertNotNull(resultsForTestUser); + assertEquals(1, resultsForTestUser.size()); + assertEquals(record2, resultsForTestUser.get(0).getChildRef()); return null; } - }, myUser); + }, testUser); } }); } @@ -134,24 +134,27 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase * Given that a test user with mid-level security clearance exists * and the test user is added to the RM Users role * and a category, a folder and three records are created in the file plan - * - * When the test user is given read permissions on the category + * and the test user is given read permissions on the category * and one of the records is classified with the highest security level * and another record is classified with the mid-level security level * - * Then as the admin user I will see all three records - * and as the test user I will see the unclassified record + * When I browse the file plan as admin + * Then I will see all three records + * + * When I browse the file plan as the test user + * Then I will see the unclassified record * and the record with the mid-level classification * and I won't be able to see the record with the classification greater than my clearance level */ doBehaviourDrivenTest(new BehaviourDrivenTest() { - private String myUser; private NodeRef category; private NodeRef folder; private NodeRef record1; private NodeRef record2; private NodeRef record3; + private List resultsForAdmin; + private List resultsForTestUser; /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() @@ -159,16 +162,19 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public void given() throws Exception { - myUser = generate(); - createPerson(myUser); - filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, myUser); - securityClearanceService.setUserSecurityClearance(myUser, LEVEL2); + testUser = generate(); + createPerson(testUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, testUser); + securityClearanceService.setUserSecurityClearance(testUser, LEVEL2); category = filePlanService.createRecordCategory(filePlan, generate()); folder = recordFolderService.createRecordFolder(category, generate()); record1 = utils.createRecord(folder, generate()); record2 = utils.createRecord(folder, generate()); record3 = utils.createRecord(folder, generate()); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), record2); } /** @@ -177,9 +183,10 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public void when() throws Exception { - filePlanPermissionService.setPermission(category, myUser, READ_RECORDS); - contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); - contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), record2); + filePlanPermissionService.setPermission(category, testUser, READ_RECORDS); + + resultsForAdmin = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); } /** @@ -193,14 +200,13 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssociationRefs = nodeService.getChildAssocs(folder); - assertNotNull(childAssociationRefs); - assertEquals(3, childAssociationRefs.size()); + assertNotNull(resultsForAdmin); + assertEquals(3, resultsForAdmin.size()); - ArrayList docs = newArrayList(record1, record2, record3); - assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + List records = newArrayList(record1, record2, record3); + assertTrue(records.contains(resultsForAdmin.get(0).getChildRef())); + assertTrue(records.contains(resultsForAdmin.get(1).getChildRef())); + assertTrue(records.contains(resultsForAdmin.get(2).getChildRef())); return null; } @@ -211,17 +217,16 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssociationRefs = nodeService.getChildAssocs(folder); - assertNotNull(childAssociationRefs); - assertEquals(2, childAssociationRefs.size()); + assertNotNull(resultsForTestUser); + assertEquals(2, resultsForTestUser.size()); - ArrayList docs = newArrayList(record2, record3); - assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); + List records = newArrayList(record2, record3); + assertTrue(records.contains(resultsForTestUser.get(0).getChildRef())); + assertTrue(records.contains(resultsForTestUser.get(1).getChildRef())); return null; } - }, myUser); + }, testUser); } }); } @@ -232,22 +237,25 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase * Given that a test user with highest level security clearance exists * and the test user is added to the RM Users role * and a category, a folder and three records are created in the file plan - * - * When the test user is given read permissions on the category + * and the test user is given read permissions on the category * and one of the records is classified with the highest security level * and another record is classified with the mid-level security level * - * Then as the admin user I will see all three records - * and as the test user I will see all three records + * When I browse the file plan as admin + * The I will see all three records + * + * When I browse the file plan as the test user + * The I will see all three records */ doBehaviourDrivenTest(new BehaviourDrivenTest() { - private String myUser; private NodeRef category; private NodeRef folder; private NodeRef record1; private NodeRef record2; private NodeRef record3; + private List resultsForAdmin; + private List resultsForTestUser; /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() @@ -255,16 +263,19 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public void given() throws Exception { - myUser = generate(); - createPerson(myUser); - filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, myUser); - securityClearanceService.setUserSecurityClearance(myUser, LEVEL1); + testUser = generate(); + createPerson(testUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, testUser); + securityClearanceService.setUserSecurityClearance(testUser, LEVEL1); category = filePlanService.createRecordCategory(filePlan, generate()); folder = recordFolderService.createRecordFolder(category, generate()); record1 = utils.createRecord(folder, generate()); record2 = utils.createRecord(folder, generate()); record3 = utils.createRecord(folder, generate()); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), record2); } /** @@ -273,9 +284,10 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public void when() throws Exception { - filePlanPermissionService.setPermission(category, myUser, READ_RECORDS); - contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); - contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), record2); + filePlanPermissionService.setPermission(category, testUser, READ_RECORDS); + + resultsForAdmin = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); } /** @@ -289,14 +301,13 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssociationRefs = nodeService.getChildAssocs(folder); - assertNotNull(childAssociationRefs); - assertEquals(3, childAssociationRefs.size()); + assertNotNull(resultsForAdmin); + assertEquals(3, resultsForAdmin.size()); - ArrayList docs = newArrayList(record1, record2, record3); - assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + List records = newArrayList(record1, record2, record3); + assertTrue(records.contains(resultsForAdmin.get(0).getChildRef())); + assertTrue(records.contains(resultsForAdmin.get(1).getChildRef())); + assertTrue(records.contains(resultsForAdmin.get(2).getChildRef())); return null; } @@ -307,18 +318,17 @@ public class RecordClassificationEnforcementTest extends BaseRMTestCase @Override public Void run() { - List childAssociationRefs = nodeService.getChildAssocs(folder); - assertNotNull(childAssociationRefs); - assertEquals(3, childAssociationRefs.size()); + assertNotNull(resultsForTestUser); + assertEquals(3, resultsForTestUser.size()); - ArrayList docs = newArrayList(record1, record2, record3); - assertTrue(docs.contains(childAssociationRefs.get(0).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(1).getChildRef())); - assertTrue(docs.contains(childAssociationRefs.get(2).getChildRef())); + List records = newArrayList(record1, record2, record3); + assertTrue(records.contains(resultsForTestUser.get(0).getChildRef())); + assertTrue(records.contains(resultsForTestUser.get(1).getChildRef())); + assertTrue(records.contains(resultsForTestUser.get(2).getChildRef())); return null; } - }, myUser); + }, testUser); } }); } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/ResultSetPostMethodInvocationProcessorTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/ResultSetPostMethodInvocationProcessorTest.java deleted file mode 100644 index 2dc13c667b..0000000000 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/ResultSetPostMethodInvocationProcessorTest.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; - -import static com.google.common.collect.Sets.newHashSet; -import static java.lang.Integer.MAX_VALUE; -import static org.alfresco.repo.site.SiteModel.SITE_MANAGER; -import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; -import static org.alfresco.service.cmr.search.SearchService.LANGUAGE_FTS_ALFRESCO; -import static org.alfresco.service.namespace.NamespaceService.CONTENT_MODEL_1_0_URI; -import static org.alfresco.util.GUID.generate; - -import java.util.List; - -import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.search.ResultSet; -import org.alfresco.service.cmr.search.SearchParameters; - -/** - * Integration test for ResultTest post method invocation processor - * - * @author Tuna Aksoy - * @since 3.0 - */ -public class ResultSetPostMethodInvocationProcessorTest extends BaseRMTestCase -{ - private static final String LEVEL1 = "level1"; - private static final String REASON = "Test Reason 1"; - - /** - * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#isCollaborationSiteTest() - */ - @Override - protected boolean isCollaborationSiteTest() - { - return true; - } - - public void testResultSetPostMethodInvocationProcessor() - { - doBehaviourDrivenTest(new BehaviourDrivenTest() - { - private String myUser; - private NodeRef doc1; - private NodeRef doc2; - private String searchQuery = generate(); - private ResultSet result; - - /** - * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() - */ - @Override - public void given() throws Exception - { - myUser = generate(); - createPerson(myUser); - siteService.setMembership(collabSiteId, myUser, SITE_MANAGER); - - doc1 = fileFolderService.create(documentLibrary, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); - doc2 = fileFolderService.create(documentLibrary, searchQuery + generate(), TYPE_CONTENT).getNodeRef(); - } - - /** - * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() - */ - @Override - public void when() throws Exception - { - doTestInTransaction(new Test() - { - @Override - public Void run() - { - contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), doc1); - - return null; - } - }); - - doTestInTransaction(new Test() - { - @Override - public Void run() - { - SearchParameters searchParameters = new SearchParameters(); - searchParameters.setQuery("@cm\\:name:" + searchQuery + "*"); - searchParameters.setLanguage(LANGUAGE_FTS_ALFRESCO); - searchParameters.addStore(STORE_REF_WORKSPACE_SPACESSTORE); - searchParameters.setMaxItems(MAX_VALUE); - searchParameters.setNamespace(CONTENT_MODEL_1_0_URI); - result = searchService.query(searchParameters); - - return null; - } - }, myUser); - } - - /** - * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() - */ - @Override - public void then() throws Exception - { - doTestInTransaction(new Test() - { - @Override - public Void run() - { - List nodeRefs = result.getNodeRefs(); - - assertEquals(2, nodeRefs.size()); - assertTrue(nodeRefs.contains(doc1)); - assertTrue(nodeRefs.contains(doc2)); - - return null; - } - }, myUser); - } - }); - } -} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SearchClassificationEnforcementTestBase.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SearchClassificationEnforcementTestBase.java new file mode 100644 index 0000000000..0c0608569d --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SearchClassificationEnforcementTestBase.java @@ -0,0 +1,71 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; + +import static java.lang.Integer.MAX_VALUE; +import static org.alfresco.repo.security.authentication.AuthenticationUtil.getAdminUserName; +import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; +import static org.alfresco.service.cmr.search.SearchService.LANGUAGE_FTS_ALFRESCO; + +import java.util.List; + +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.search.SearchParameters; + +/** + * Base class for classification enforcement tests for the search action + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class SearchClassificationEnforcementTestBase extends BaseRMTestCase +{ + protected String testUser; + protected static final String LEVEL1 = "level1"; + protected static final String LEVEL2 = "level2"; + protected static final String REASON = "Test Reason 1"; + + protected List search(String searchQuery, String userName) + { + return doTestInTransaction(new Test>() + { + @Override + public List run() + { + SearchParameters searchParameters = new SearchParameters(); + searchParameters.setQuery("cm:name:" + searchQuery + "*"); + searchParameters.setLanguage(LANGUAGE_FTS_ALFRESCO); + searchParameters.addStore(STORE_REF_WORKSPACE_SPACESSTORE); + searchParameters.setMaxItems(MAX_VALUE); + return searchService.query(searchParameters).getNodeRefs(); + } + }, userName); + } + + protected List searchAsAdmin(String searchQuery) + { + return search(searchQuery, getAdminUserName()); + } + + protected List searchAsTestUser(String searchQuery) + { + return search(searchQuery, testUser); + } +} From d320b4dad6ccc15181e6b66bf2effb949158092d Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sun, 28 Jun 2015 13:39:10 +0000 Subject: [PATCH 26/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107272 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 73 +--- rm-server/pom.xml | 2 +- .../ArrayPostMethodInvocationProcessor.java | 3 + ...ationRefPostMethodInvocationProcessor.java | 2 + .../BasePostMethodInvocationProcessor.java | 18 +- ...ationRefPostMethodInvocationProcessor.java | 2 + ...llectionPostMethodInvocationProcessor.java | 3 + .../NodeRefPostMethodInvocationProcessor.java | 2 + ...gResultsPostMethodInvocationProcessor.java | 2 + ...eckValuePostMethodInvocationProcessor.java | 2 + ...eResultsPostMethodInvocationProcessor.java | 2 + ...esultSetPostMethodInvocationProcessor.java | 2 + ...StoreRefPostMethodInvocationProcessor.java | 2 + ...ntSearchClassificationEnforcementTest.java | 18 + ...rdBrowseClassificationEnforcementTest.java | 23 +- ...rdSearchClassificationEnforcementTest.java | 340 ++++++++++++++++++ ...archClassificationEnforcementTestBase.java | 17 +- 17 files changed, 414 insertions(+), 99 deletions(-) create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordSearchClassificationEnforcementTest.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index 937e508e6b..c3222767b6 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -2,12 +2,18 @@ + + + @@ -62,73 +68,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rm-server/pom.xml b/rm-server/pom.xml index 2115a712cf..32bd7ddd86 100644 --- a/rm-server/pom.xml +++ b/rm-server/pom.xml @@ -430,7 +430,7 @@ org.springframework spring-test 2.5 - test + provided org.alfresco diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java index 672958aab9..f1fce3b821 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java @@ -25,12 +25,15 @@ import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; +import org.springframework.stereotype.Component; + /** * Array Post Method Invocation Processor * * @author Tuna Aksoy * @since 3.0 */ +@Component public class ArrayPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java index 300430cb81..990aa3df7c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java @@ -20,6 +20,7 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.pr import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.stereotype.Component; /** * AssociationRef Post Method Invocation Processor @@ -27,6 +28,7 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Tuna Aksoy * @since 3.0 */ +@Component public class AssociationRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor { /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java index 4addffbf90..ceb2bc0ab0 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -22,6 +22,8 @@ import static org.alfresco.model.ContentModel.TYPE_CONTENT; import java.util.Collection; +import javax.annotation.PostConstruct; + import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.classification.SecurityClearanceService; import org.alfresco.repo.cache.SimpleCache; @@ -29,6 +31,8 @@ import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.util.Pair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; /** * Base class for post method invocation processors @@ -36,25 +40,32 @@ import org.alfresco.util.Pair; * @author Tuna Aksoy * @since 3.0 */ +@ContextConfiguration(locations = {"classpath:alfresco/module/org_alfresco_module_rm/classified-content-context.xml"}) public abstract class BasePostMethodInvocationProcessor { /** Node service */ + @Autowired private NodeService nodeService; /** Dictionary service */ + @Autowired private DictionaryService dictionaryService; /** Content classification service */ + @Autowired private ContentClassificationService contentClassificationService; /** Security Clearance Service */ + @Autowired private SecurityClearanceService securityClearanceService; /** Post method invocation processor */ + @Autowired private PostMethodInvocationProcessor postMethodInvocationProcessor; /** Cache to hold the filtered node information */ - private SimpleCache, Pair> cache; + @Autowired + private SimpleCache, Pair> basePostMethodInvocationProcessorCache; /** * @return the nodeService @@ -101,7 +112,7 @@ public abstract class BasePostMethodInvocationProcessor */ protected SimpleCache, Pair> getCache() { - return this.cache; + return this.basePostMethodInvocationProcessorCache; } /** @@ -149,7 +160,7 @@ public abstract class BasePostMethodInvocationProcessor */ public void setCache(SimpleCache, Pair> cache) { - this.cache = cache; + this.basePostMethodInvocationProcessorCache = cache; } /** @@ -170,6 +181,7 @@ public abstract class BasePostMethodInvocationProcessor /** * Registers the post method invocation processors */ + @PostConstruct public void register() { getPostMethodInvocationProcessor().register(this); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java index 5e00f06bda..288610dcc8 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java @@ -20,6 +20,7 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.pr import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.stereotype.Component; /** * ChildAssociationRef Post Method Invocation Processor @@ -27,6 +28,7 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Tuna Aksoy * @since 3.0 */ +@Component public class ChildAssociationRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor { /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java index 01d226d133..6e87a8d5ed 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -22,12 +22,15 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; +import org.springframework.stereotype.Component; + /** * Collection Post Method Invocation Processor * * @author Tuna Aksoy * @since 3.0 */ +@Component public class CollectionPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java index 193fd47d0a..9e7a267fda 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java @@ -19,6 +19,7 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.stereotype.Component; /** * NodeRef Post Method Invocation Processor @@ -26,6 +27,7 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Tuna Aksoy * @since 3.0 */ +@Component public class NodeRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor { /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java index e4f68bbb9d..0497efd59c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java @@ -22,6 +22,7 @@ import java.util.List; import org.alfresco.query.PagingResults; import org.alfresco.util.Pair; +import org.springframework.stereotype.Component; /** * PagingResults Post Method Invocation Processor @@ -29,6 +30,7 @@ import org.alfresco.util.Pair; * @author Tuna Aksoy * @since 3.0 */ +@Component public class PagingResultsPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java index 0bb13ad1f1..e7e68c335c 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java @@ -20,6 +20,7 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.pr import org.alfresco.repo.security.permissions.PermissionCheckValue; import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.stereotype.Component; /** * Permission Check Value Post Method Invocation Processor @@ -27,6 +28,7 @@ import org.alfresco.service.cmr.repository.NodeRef; * @author Tuna Aksoy * @since 3.0 */ +@Component public class PermissionCheckValuePostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor { /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java index 760b95afe6..298f56f95e 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java @@ -25,6 +25,7 @@ import java.util.Set; import org.alfresco.repo.search.impl.querymodel.QueryEngineResults; import org.alfresco.service.cmr.search.ResultSet; +import org.springframework.stereotype.Component; /** * A post method invocation processor for {@link QueryEngineResults}. @@ -32,6 +33,7 @@ import org.alfresco.service.cmr.search.ResultSet; * @author Tom Page * @since 3.0 */ +@Component public class QueryEngineResultsPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java index 2378faa442..81e5a322ae 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java @@ -30,6 +30,7 @@ import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.ResultSetMetaData; import org.alfresco.service.cmr.search.ResultSetRow; import org.alfresco.service.cmr.search.SearchParameters; +import org.springframework.stereotype.Component; /** * ResultSet Post Method Invocation Processor @@ -37,6 +38,7 @@ import org.alfresco.service.cmr.search.SearchParameters; * @author Tuna Aksoy * @since 3.0 */ +@Component public class ResultSetPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { /** diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java index 6f3f773374..2093953cff 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java @@ -20,6 +20,7 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.pr import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; +import org.springframework.stereotype.Component; /** * StoreRef Post Method Invocation Processor @@ -27,6 +28,7 @@ import org.alfresco.service.cmr.repository.StoreRef; * @author Tuna Aksoy * @since 3.0 */ +@Component public class StoreRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor { /** diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentSearchClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentSearchClassificationEnforcementTest.java index 33e829353a..0a56a158d4 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentSearchClassificationEnforcementTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentSearchClassificationEnforcementTest.java @@ -19,12 +19,16 @@ package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; import static com.google.common.collect.Sets.newHashSet; +import static java.lang.Integer.MAX_VALUE; import static org.alfresco.repo.site.SiteModel.SITE_MANAGER; +import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; +import static org.alfresco.service.cmr.search.SearchService.LANGUAGE_FTS_ALFRESCO; import static org.alfresco.util.GUID.generate; import java.util.List; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.search.SearchParameters; /** * Tests for enforcement of classification when searching documents in the document library @@ -314,4 +318,18 @@ public class DocumentSearchClassificationEnforcementTest extends SearchClassific } }); } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor.SearchClassificationEnforcementTestBase#search(java.lang.String) + */ + @Override + protected List search(String searchQuery) + { + SearchParameters searchParameters = new SearchParameters(); + searchParameters.setQuery("cm:name:" + searchQuery + "*"); + searchParameters.setLanguage(LANGUAGE_FTS_ALFRESCO); + searchParameters.addStore(STORE_REF_WORKSPACE_SPACESSTORE); + searchParameters.setMaxItems(MAX_VALUE); + return searchService.query(searchParameters).getNodeRefs(); + } } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordBrowseClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordBrowseClassificationEnforcementTest.java index d7a28a7d98..29fb0fd92a 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordBrowseClassificationEnforcementTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordBrowseClassificationEnforcementTest.java @@ -20,7 +20,7 @@ package org.alfresco.module.org_alfresco_module_rm.test.integration.classificati import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; -import static org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService.ROLE_USER; +import static org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService.ROLE_ADMIN; import static org.alfresco.util.GUID.generate; import java.util.List; @@ -40,9 +40,8 @@ public class RecordBrowseClassificationEnforcementTest extends BrowseClassificat { /** * Given that a test user without security clearance exists - * and the test user is added to the RM Users role + * and the test user is added to the RM Admin role * and a category, a folder and two records are created in the file plan - * and the test user is given read permissions on the category * and one of the records is classified with the highest security level * * When I browse the file plan as admin @@ -68,7 +67,7 @@ public class RecordBrowseClassificationEnforcementTest extends BrowseClassificat { testUser = generate(); createPerson(testUser); - filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, testUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_ADMIN, testUser); category = filePlanService.createRecordCategory(filePlan, generate()); folder = recordFolderService.createRecordFolder(category, generate()); @@ -84,8 +83,6 @@ public class RecordBrowseClassificationEnforcementTest extends BrowseClassificat @Override public void when() throws Exception { - filePlanPermissionService.setPermission(category, testUser, READ_RECORDS); - resultsForAdmin = browseAsAdmin(folder); resultsForTestUser = browseAsTestUser(folder); } @@ -132,9 +129,8 @@ public class RecordBrowseClassificationEnforcementTest extends BrowseClassificat { /** * Given that a test user with mid-level security clearance exists - * and the test user is added to the RM Users role + * and the test user is added to the RM Admin role * and a category, a folder and three records are created in the file plan - * and the test user is given read permissions on the category * and one of the records is classified with the highest security level * and another record is classified with the mid-level security level * @@ -164,7 +160,7 @@ public class RecordBrowseClassificationEnforcementTest extends BrowseClassificat { testUser = generate(); createPerson(testUser); - filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, testUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_ADMIN, testUser); securityClearanceService.setUserSecurityClearance(testUser, LEVEL2); category = filePlanService.createRecordCategory(filePlan, generate()); @@ -183,8 +179,6 @@ public class RecordBrowseClassificationEnforcementTest extends BrowseClassificat @Override public void when() throws Exception { - filePlanPermissionService.setPermission(category, testUser, READ_RECORDS); - resultsForAdmin = browseAsAdmin(folder); resultsForTestUser = browseAsTestUser(folder); } @@ -235,9 +229,8 @@ public class RecordBrowseClassificationEnforcementTest extends BrowseClassificat { /** * Given that a test user with highest level security clearance exists - * and the test user is added to the RM Users role + * and the test user is added to the RM Admin role * and a category, a folder and three records are created in the file plan - * and the test user is given read permissions on the category * and one of the records is classified with the highest security level * and another record is classified with the mid-level security level * @@ -265,7 +258,7 @@ public class RecordBrowseClassificationEnforcementTest extends BrowseClassificat { testUser = generate(); createPerson(testUser); - filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_USER, testUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_ADMIN, testUser); securityClearanceService.setUserSecurityClearance(testUser, LEVEL1); category = filePlanService.createRecordCategory(filePlan, generate()); @@ -284,8 +277,6 @@ public class RecordBrowseClassificationEnforcementTest extends BrowseClassificat @Override public void when() throws Exception { - filePlanPermissionService.setPermission(category, testUser, READ_RECORDS); - resultsForAdmin = browseAsAdmin(folder); resultsForTestUser = browseAsTestUser(folder); } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordSearchClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordSearchClassificationEnforcementTest.java new file mode 100644 index 0000000000..5e158eeb63 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordSearchClassificationEnforcementTest.java @@ -0,0 +1,340 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; + +import static com.google.common.collect.Sets.newHashSet; +import static org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService.ROLE_ADMIN; +import static org.alfresco.util.GUID.generate; + +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchParameters; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.Pair; + +/** + * Enforcement of classification when searching records in the file plan + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class RecordSearchClassificationEnforcementTest extends SearchClassificationEnforcementTestBase +{ + public void testUserWithNoSecurityClearance() + { + /** + * Given that a test user without security clearance exists + * and the test user is added to the RM Admin role + * and a category, a folder and two records are created in the file plan + * and one of the records is classified with the highest security level + * + * When I search for the records as admin + * Then I will see both records + * + * When I search for the records as the test user + * Then I will only see the unclassified record + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private NodeRef category; + private NodeRef folder; + private NodeRef record1; + private NodeRef record2; + private String searchQuery = generate(); + private List resultsForAdmin; + private List resultsForTestUser; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + testUser = generate(); + createPerson(testUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_ADMIN, testUser); + + category = filePlanService.createRecordCategory(filePlan, generate()); + folder = recordFolderService.createRecordFolder(category, generate()); + record1 = utils.createRecord(folder, searchQuery + generate()); + record2 = utils.createRecord(folder, searchQuery + generate()); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + resultsForAdmin = searchAsAdmin(searchQuery); + resultsForTestUser = searchAsTestUser(searchQuery); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForAdmin); + assertEquals(2, resultsForAdmin.size()); + assertTrue(resultsForAdmin.contains(record1)); + assertTrue(resultsForAdmin.contains(record2)); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(1, resultsForTestUser.size()); + assertTrue(resultsForTestUser.contains(record2)); + + return null; + } + }, testUser); + } + }); + } + + public void testUserWithMidlevelSecurityClearance() + { + /** + * Given that a test user with mid-level security clearance exists + * and the test user is added to the RM Admin role + * and a category, a folder and three records are created in the file plan + * and one of the records is classified with the highest security level + * and another record is classified with the mid-level security level + * + * When I search for the records as admin + * The I will see all three records + * + * When I search for the records as the test user + * Then I will see the unclassified document + * and the document with the mid-level classification + * and I won't be able to see the document with the classification greater than my clearance level + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private NodeRef category; + private NodeRef folder; + private NodeRef record1; + private NodeRef record2; + private NodeRef record3; + private String searchQuery = generate(); + private List resultsForAdmin; + private List resultsForTestUser; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + testUser = generate(); + createPerson(testUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_ADMIN, testUser); + securityClearanceService.setUserSecurityClearance(testUser, LEVEL2); + + category = filePlanService.createRecordCategory(filePlan, generate()); + folder = recordFolderService.createRecordFolder(category, generate()); + record1 = utils.createRecord(folder, searchQuery + generate()); + record2 = utils.createRecord(folder, searchQuery + generate()); + record3 = utils.createRecord(folder, searchQuery + generate()); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), record2); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + resultsForAdmin = searchAsAdmin(searchQuery); + resultsForTestUser = searchAsTestUser(searchQuery); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForAdmin); + assertEquals(3, resultsForAdmin.size()); + assertTrue(resultsForAdmin.contains(record1)); + assertTrue(resultsForAdmin.contains(record2)); + assertTrue(resultsForAdmin.contains(record3)); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(2, resultsForTestUser.size()); + assertTrue(resultsForTestUser.contains(record2)); + assertTrue(resultsForTestUser.contains(record3)); + + return null; + } + }, testUser); + } + }); + } + + public void testUseWithHighestLevelSecurityClearance() + { + /** + * Given that a test user with highest level security clearance exists + * and the test user is added to the RM Admin role + * and a category, a folder and three records are created in the file plan + * and one of the records is classified with the highest security level + * and another record is classified with the mid-level security level + * + * When I search for the records as admin + * The I will see all three records + * + * When I search for the records as the test user + * The I will see all three records + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private NodeRef category; + private NodeRef folder; + private NodeRef record1; + private NodeRef record2; + private NodeRef record3; + private String searchQuery = generate(); + private List resultsForAdmin; + private List resultsForTestUser; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + testUser = generate(); + createPerson(testUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_ADMIN, testUser); + securityClearanceService.setUserSecurityClearance(testUser, LEVEL1); + + category = filePlanService.createRecordCategory(filePlan, generate()); + folder = recordFolderService.createRecordFolder(category, generate()); + record1 = utils.createRecord(folder, searchQuery + generate()); + record2 = utils.createRecord(folder, searchQuery + generate()); + record3 = utils.createRecord(folder, searchQuery + generate()); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), record2); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + resultsForAdmin = searchAsAdmin(searchQuery); + resultsForTestUser = searchAsTestUser(searchQuery); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForAdmin); + assertEquals(3, resultsForAdmin.size()); + assertTrue(resultsForAdmin.contains(record1)); + assertTrue(resultsForAdmin.contains(record2)); + assertTrue(resultsForAdmin.contains(record3)); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(3, resultsForTestUser.size()); + assertTrue(resultsForTestUser.contains(record1)); + assertTrue(resultsForTestUser.contains(record2)); + assertTrue(resultsForTestUser.contains(record3)); + + return null; + } + }, testUser); + } + }); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor.SearchClassificationEnforcementTestBase#search(java.lang.String) + */ + @Override + protected List search(String searchQuery) + { + String query = "cm:name:" + searchQuery + "*"; + RecordsManagementSearchParameters searchParameters = new RecordsManagementSearchParameters(); + searchParameters.setIncludeUndeclaredRecords(true); + List> result = rmSearchService.search(siteId, query, searchParameters); + + List filteredResult = new ArrayList<>(); + for (Pair pair : result) + { + filteredResult.add(pair.getSecond()); + } + + return filteredResult; + } +} diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SearchClassificationEnforcementTestBase.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SearchClassificationEnforcementTestBase.java index 0c0608569d..458528b61c 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SearchClassificationEnforcementTestBase.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SearchClassificationEnforcementTestBase.java @@ -18,16 +18,12 @@ */ package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; -import static java.lang.Integer.MAX_VALUE; import static org.alfresco.repo.security.authentication.AuthenticationUtil.getAdminUserName; -import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; -import static org.alfresco.service.cmr.search.SearchService.LANGUAGE_FTS_ALFRESCO; import java.util.List; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.search.SearchParameters; /** * Base class for classification enforcement tests for the search action @@ -35,26 +31,23 @@ import org.alfresco.service.cmr.search.SearchParameters; * @author Tuna Aksoy * @since 3.0 */ -public class SearchClassificationEnforcementTestBase extends BaseRMTestCase +public abstract class SearchClassificationEnforcementTestBase extends BaseRMTestCase { protected String testUser; protected static final String LEVEL1 = "level1"; protected static final String LEVEL2 = "level2"; protected static final String REASON = "Test Reason 1"; - protected List search(String searchQuery, String userName) + protected abstract List search(String searchQuery); + + private List search(String searchQuery, String userName) { return doTestInTransaction(new Test>() { @Override public List run() { - SearchParameters searchParameters = new SearchParameters(); - searchParameters.setQuery("cm:name:" + searchQuery + "*"); - searchParameters.setLanguage(LANGUAGE_FTS_ALFRESCO); - searchParameters.addStore(STORE_REF_WORKSPACE_SPACESSTORE); - searchParameters.setMaxItems(MAX_VALUE); - return searchService.query(searchParameters).getNodeRefs(); + return search(searchQuery); } }, userName); } From c64b092294a271914f6537f0eca5eca008f36581 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sun, 28 Jun 2015 15:45:01 +0000 Subject: [PATCH 27/33] RM-2130 (Check classification after method execution, filtering results where appropriate) - Fixed failing integration test +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107273 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- ...ecordsManagementSearchServiceImplTest.java | 51 ++++--------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementSearchServiceImplTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementSearchServiceImplTest.java index 012db1a363..0a7fb2272a 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementSearchServiceImplTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementSearchServiceImplTest.java @@ -18,6 +18,8 @@ */ package org.alfresco.module.org_alfresco_module_rm.test.legacy.service; +import static org.alfresco.util.GUID.generate; + import java.util.List; import org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchParameters; @@ -26,14 +28,12 @@ import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.util.Pair; -import org.alfresco.util.TestWithUserUtils; /** * Search service implementation unit test. * * @author Roy Wetherall */ -@SuppressWarnings("unused") public class RecordsManagementSearchServiceImplTest extends BaseRMTestCase { @Override @@ -47,19 +47,11 @@ public class RecordsManagementSearchServiceImplTest extends BaseRMTestCase private static final String SEARCH3 = "search3"; private static final String SEARCH4 = "search4"; - private static final String USER1 = "user1"; - private static final String USER2 = "user2"; + private static final String USER1 = generate(); private NodeRef folderLevelRecordFolder; private NodeRef recordLevelRecordFolder; - private NodeRef recordOne; - private NodeRef recordTwo; - private NodeRef recordThree; - private NodeRef recordFour; - private NodeRef recordFive; - private NodeRef recordSix; - private int numberOfReports; /** @@ -75,15 +67,13 @@ public class RecordsManagementSearchServiceImplTest extends BaseRMTestCase @Override public Void run() { - // Create test users - TestWithUserUtils.createUser(USER1, USER1, rootNodeRef, nodeService, authenticationService); - TestWithUserUtils.createUser(USER2, USER2, rootNodeRef, nodeService, authenticationService); - // Count the number of pre-defined reports List searches = rmSearchService.getSavedSearches(siteId); assertNotNull(searches); numberOfReports = searches.size(); + createPerson(USER1); + return null; } }, AuthenticationUtil.getSystemUserName()); @@ -105,37 +95,18 @@ public class RecordsManagementSearchServiceImplTest extends BaseRMTestCase folderLevelRecordFolder = mhRecordFolder42; recordLevelRecordFolder = mhRecordFolder43; - recordOne = utils.createRecord(folderLevelRecordFolder, "recordOne.txt", null, "record one - folder level - elephant"); - recordTwo = utils.createRecord(folderLevelRecordFolder, "recordTwo.txt", null, "record two - folder level - snake"); - recordThree = utils.createRecord(folderLevelRecordFolder, "recordThree.txt", null, "record three - folder level - monkey"); - recordFour = utils.createRecord(recordLevelRecordFolder, "recordFour.txt", null, "record four - record level - elephant"); - recordFive = utils.createRecord(recordLevelRecordFolder, "recordFive.txt", null, "record five - record level - snake"); - recordSix = utils.createRecord(recordLevelRecordFolder, "recordSix.txt", null, "record six - record level - monkey"); + utils.createRecord(folderLevelRecordFolder, "recordOne.txt", null, "record one - folder level - elephant"); + utils.createRecord(folderLevelRecordFolder, "recordTwo.txt", null, "record two - folder level - snake"); + utils.createRecord(folderLevelRecordFolder, "recordThree.txt", null, "record three - folder level - monkey"); + utils.createRecord(recordLevelRecordFolder, "recordFour.txt", null, "record four - record level - elephant"); + utils.createRecord(recordLevelRecordFolder, "recordFive.txt", null, "record five - record level - snake"); + utils.createRecord(recordLevelRecordFolder, "recordSix.txt", null, "record six - record level - monkey"); return null; } }, AuthenticationUtil.getSystemUserName()); } - @Override - protected void tearDown() throws Exception - { - doTestInTransaction(new Test() - { - @Override - public Void run() - { - // Delete test users - TestWithUserUtils.deleteUser(USER1, USER1, rootNodeRef, nodeService, authenticationService); - TestWithUserUtils.deleteUser(USER2, USER2, rootNodeRef, nodeService, authenticationService); - - return null; - } - }, AuthenticationUtil.getSystemUserName()); - - super.tearDown(); - } - public void testSearch() { // Full text search From 158eaecf16e77bb34c14c97f7f89728b0adc55a7 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sun, 28 Jun 2015 17:29:54 +0000 Subject: [PATCH 28/33] RM-2130 (Check classification after method execution, filtering results where appropriate) - Fixed failing integration tests +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107274 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- ...ecordsManagementActionServiceImplTest.java | 177 ++++++++---------- ...ecordsManagementSearchServiceImplTest.java | 9 +- 2 files changed, 80 insertions(+), 106 deletions(-) diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementActionServiceImplTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementActionServiceImplTest.java index b87e6474ad..600fb85e64 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementActionServiceImplTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementActionServiceImplTest.java @@ -24,80 +24,53 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import junit.framework.TestCase; - import org.alfresco.model.ContentModel; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.BeforeRMActionExecution; import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnRMActionExecution; import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementAction; -import org.alfresco.module.org_alfresco_module_rm.action.RecordsManagementActionService; -import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; import org.alfresco.module.org_alfresco_module_rm.test.util.TestAction; import org.alfresco.module.org_alfresco_module_rm.test.util.TestAction2; -import org.alfresco.repo.policy.JavaBehaviour; -import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.policy.Behaviour.NotificationFrequency; +import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.ServiceRegistry; 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.namespace.NamespaceService; import org.alfresco.service.namespace.QName; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.ApplicationContextHelper; -import org.springframework.context.ApplicationContext; /** * Records management action service implementation test * * @author Roy Wetherall */ -public class RecordsManagementActionServiceImplTest extends TestCase - implements RecordsManagementModel, - BeforeRMActionExecution, +public class RecordsManagementActionServiceImplTest extends BaseRMTestCase + implements BeforeRMActionExecution, OnRMActionExecution { - private static final String[] CONFIG_LOCATIONS = new String[] { - "classpath:alfresco/application-context.xml", - "classpath:test-context.xml"}; - - private ApplicationContext ctx; - - private ServiceRegistry serviceRegistry; - private TransactionService transactionService; private RetryingTransactionHelper txnHelper; - private NodeService nodeService; - private RecordsManagementActionService rmActionService; - private PolicyComponent policyComponent; - private NodeRef nodeRef; - private List nodeRefs; + private NodeRef nodeRef; + private List nodeRefs; private boolean beforeMarker; private boolean onMarker; private boolean inTest; - @Override - protected void setUp() throws Exception - { - ctx = ApplicationContextHelper.getApplicationContext(CONFIG_LOCATIONS); + @Override + protected void setUp() throws Exception + { + super.setUp(); - this.serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); - this.transactionService = serviceRegistry.getTransactionService(); this.txnHelper = transactionService.getRetryingTransactionHelper(); - this.nodeService = serviceRegistry.getNodeService(); - this.rmActionService = (RecordsManagementActionService)ctx.getBean("RecordsManagementActionService"); - this.policyComponent = (PolicyComponent)ctx.getBean("policyComponent"); + // Set the current security context as system + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName()); - // Set the current security context as admin - AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); - - RetryingTransactionCallback setUpCallback = new RetryingTransactionCallback() + RetryingTransactionCallback setUpCallback = new RetryingTransactionCallback() { public Void execute() throws Throwable { @@ -128,17 +101,17 @@ public class RecordsManagementActionServiceImplTest extends TestCase beforeMarker = false; onMarker = false; inTest = false; - } + } - @Override - protected void tearDown() - { + @Override + protected void tearDown() + { AuthenticationUtil.clearCurrentSecurityContext(); - } + } - public void testGetActions() - { - RetryingTransactionCallback testCallback = new RetryingTransactionCallback() + public void testGetActions() + { + RetryingTransactionCallback testCallback = new RetryingTransactionCallback() { public Void execute() throws Throwable { @@ -147,36 +120,36 @@ public class RecordsManagementActionServiceImplTest extends TestCase } }; txnHelper.doInTransaction(testCallback); - } + } - private void getActionsImpl() - { - List result = this.rmActionService.getRecordsManagementActions(); - assertNotNull(result); - Map resultMap = new HashMap(8); - for (RecordsManagementAction action : result) - { - resultMap.put(action.getName(), action); - } - - assertTrue(resultMap.containsKey(TestAction.NAME)); - assertTrue(resultMap.containsKey(TestAction2.NAME)); - - result = this.rmActionService.getDispositionActions(); - resultMap = new HashMap(8); + private void getActionsImpl() + { + List result = this.rmActionService.getRecordsManagementActions(); + assertNotNull(result); + Map resultMap = new HashMap(8); for (RecordsManagementAction action : result) { resultMap.put(action.getName(), action); } - assertTrue(resultMap.containsKey(TestAction.NAME)); - assertFalse(resultMap.containsKey(TestAction2.NAME)); - // get some specific actions and check the label - RecordsManagementAction cutoff = this.rmActionService.getDispositionAction("cutoff"); - assertNotNull(cutoff); - assertEquals("Cut off", cutoff.getLabel()); + assertTrue(resultMap.containsKey(TestAction.NAME)); + assertTrue(resultMap.containsKey(TestAction2.NAME)); - RecordsManagementAction freeze = this.rmActionService.getRecordsManagementAction("freeze"); + result = this.rmActionService.getDispositionActions(); + resultMap = new HashMap(8); + for (RecordsManagementAction action : result) + { + resultMap.put(action.getName(), action); + } + assertTrue(resultMap.containsKey(TestAction.NAME)); + assertFalse(resultMap.containsKey(TestAction2.NAME)); + + // get some specific actions and check the label + RecordsManagementAction cutoff = this.rmActionService.getDispositionAction("cutoff"); + assertNotNull(cutoff); + assertEquals("Cut off", cutoff.getLabel()); + + RecordsManagementAction freeze = this.rmActionService.getRecordsManagementAction("freeze"); assertNotNull(freeze); assertEquals("Freeze", freeze.getLabel()); assertEquals("Freeze", freeze.getLabel()); @@ -184,7 +157,7 @@ public class RecordsManagementActionServiceImplTest extends TestCase // test non-existent actions assertNull(this.rmActionService.getDispositionAction("notThere")); assertNull(this.rmActionService.getRecordsManagementAction("notThere")); - } + } public void testExecution() { @@ -225,37 +198,37 @@ public class RecordsManagementActionServiceImplTest extends TestCase } } - private void executionImpl() - { - inTest = true; - try - { - policyComponent.bindClassBehaviour( - RecordsManagementPolicies.BEFORE_RM_ACTION_EXECUTION, - this, - new JavaBehaviour(this, "beforeRMActionExecution", NotificationFrequency.EVERY_EVENT)); - policyComponent.bindClassBehaviour( + private void executionImpl() + { + inTest = true; + try + { + policyComponent.bindClassBehaviour( + RecordsManagementPolicies.BEFORE_RM_ACTION_EXECUTION, + this, + new JavaBehaviour(this, "beforeRMActionExecution", NotificationFrequency.EVERY_EVENT)); + policyComponent.bindClassBehaviour( RecordsManagementPolicies.ON_RM_ACTION_EXECUTION, this, new JavaBehaviour(this, "onRMActionExecution", NotificationFrequency.EVERY_EVENT)); - assertFalse(beforeMarker); - assertFalse(onMarker); - assertFalse(this.nodeService.hasAspect(this.nodeRef, ASPECT_RECORD)); + assertFalse(beforeMarker); + assertFalse(onMarker); + assertFalse(this.nodeService.hasAspect(this.nodeRef, ASPECT_RECORD)); - Map params = new HashMap(1); - params.put(TestAction.PARAM, TestAction.PARAM_VALUE); - this.rmActionService.executeRecordsManagementAction(this.nodeRef, TestAction.NAME, params); + Map params = new HashMap(1); + params.put(TestAction.PARAM, TestAction.PARAM_VALUE); + this.rmActionService.executeRecordsManagementAction(this.nodeRef, TestAction.NAME, params); - assertTrue(beforeMarker); + assertTrue(beforeMarker); assertTrue(onMarker); assertTrue(this.nodeService.hasAspect(this.nodeRef, ASPECT_RECORD)); - } - finally - { - inTest = false; - } - } + } + finally + { + inTest = false; + } + } public void testBulkExecution() { @@ -270,20 +243,20 @@ public class RecordsManagementActionServiceImplTest extends TestCase txnHelper.doInTransaction(testCallback); } - private void bulkExecutionImpl() - { - for (NodeRef nodeRef : this.nodeRefs) + private void bulkExecutionImpl() + { + for (NodeRef nodeRef : this.nodeRefs) { - assertFalse(this.nodeService.hasAspect(nodeRef, ASPECT_RECORD)); + assertFalse(this.nodeService.hasAspect(nodeRef, ASPECT_RECORD)); } - Map params = new HashMap(1); + Map params = new HashMap(1); params.put(TestAction.PARAM, TestAction.PARAM_VALUE); this.rmActionService.executeRecordsManagementAction(this.nodeRefs, TestAction.NAME, params); - for (NodeRef nodeRef : this.nodeRefs) + for (NodeRef nodeRef : this.nodeRefs) { assertTrue(this.nodeService.hasAspect(nodeRef, ASPECT_RECORD)); } - } + } } diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementSearchServiceImplTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementSearchServiceImplTest.java index 0a7fb2272a..4cd6e709cf 100644 --- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementSearchServiceImplTest.java +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementSearchServiceImplTest.java @@ -47,7 +47,7 @@ public class RecordsManagementSearchServiceImplTest extends BaseRMTestCase private static final String SEARCH3 = "search3"; private static final String SEARCH4 = "search4"; - private static final String USER1 = generate(); + private String user; private NodeRef folderLevelRecordFolder; private NodeRef recordLevelRecordFolder; @@ -72,7 +72,8 @@ public class RecordsManagementSearchServiceImplTest extends BaseRMTestCase assertNotNull(searches); numberOfReports = searches.size(); - createPerson(USER1); + user = generate(); + createPerson(user); return null; } @@ -163,7 +164,7 @@ public class RecordsManagementSearchServiceImplTest extends BaseRMTestCase return null; } - }, USER1); + }, user); // Get searches (as admin user) doTestInTransaction(new Test() @@ -222,7 +223,7 @@ public class RecordsManagementSearchServiceImplTest extends BaseRMTestCase return null; } - }, USER1); + }, user); // Update search (as admin user) doTestInTransaction(new Test() From afa0ac02294e1d5b901018bc0f468304a00f7c5d Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Sun, 28 Jun 2015 19:50:07 +0000 Subject: [PATCH 29/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107275 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- rm-server/pom.xml | 2 +- .../BasePostMethodInvocationProcessor.java | 2 -- ...sociationRefPostMethodInvocationProcessor.java | 15 +++++++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/rm-server/pom.xml b/rm-server/pom.xml index 32bd7ddd86..2115a712cf 100644 --- a/rm-server/pom.xml +++ b/rm-server/pom.xml @@ -430,7 +430,7 @@ org.springframework spring-test 2.5 - provided + test org.alfresco diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java index ceb2bc0ab0..c9fe37f231 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -32,7 +32,6 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.util.Pair; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; /** * Base class for post method invocation processors @@ -40,7 +39,6 @@ import org.springframework.test.context.ContextConfiguration; * @author Tuna Aksoy * @since 3.0 */ -@ContextConfiguration(locations = {"classpath:alfresco/module/org_alfresco_module_rm/classified-content-context.xml"}) public abstract class BasePostMethodInvocationProcessor { /** Node service */ diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java index 288610dcc8..b6d2b85786 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java @@ -46,14 +46,25 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends AbstractPo @Override protected T processSingleElement(T object) { + T result; + ChildAssociationRef childAssociationRef = getClassName().cast(object); NodeRef childRef = childAssociationRef.getChildRef(); NodeRef filteredChildRef = filter(childRef); NodeRef parentRef = childAssociationRef.getParentRef(); - NodeRef filteredParentRef = filter(parentRef); + NodeRef filteredParentRef; + if (parentRef == null) + { + result = filteredChildRef == null ? null : object; + } + else + { + filteredParentRef = filter(parentRef); + result = (filteredChildRef == null || filteredParentRef == null) ? null : object; + } - return (filteredChildRef == null || filteredParentRef == null) ? null : object; + return result; } } From 4b39c868cea1e63303f1317c7fb1f28276701107 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 29 Jun 2015 08:48:10 +0000 Subject: [PATCH 30/33] RM-2130 Add support for other collections than Lists. Unfortunately most methods in the CollectionUtils helper class convert collections to lists, and so is not suitable for our usage. +review RM @taksoy git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107282 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- ...AbstractPostMethodInvocationProcessor.java | 37 +------------------ .../BasePostMethodInvocationProcessor.java | 13 ------- ...llectionPostMethodInvocationProcessor.java | 21 ++++++++--- 3 files changed, 16 insertions(+), 55 deletions(-) diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java index 2269dedac1..894e6e0216 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java @@ -18,10 +18,6 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import java.util.Collection; - -import org.alfresco.util.collections.CollectionUtils; -import org.alfresco.util.collections.Filter; /** * Abstract Post Method Invocation Processor @@ -39,29 +35,9 @@ public abstract class AbstractPostMethodInvocationProcessor extends BasePostMeth */ protected abstract T processSingleElement(T object); - /** - * Processes a collection - * - * @param collection The collection to process - * @return Processed collection - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - protected Collection processCollection(Collection collection) - { - return CollectionUtils.filter(collection, new Filter() - { - @Override - public Boolean apply(Object element) - { - return processSingleElement(element) != null; - } - }); - } - /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) */ - @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public T process(T object) { @@ -69,18 +45,7 @@ public abstract class AbstractPostMethodInvocationProcessor extends BasePostMeth if (result != null) { - if (isCollection(result)) - { - Collection collection = ((Collection) result); - if (!collection.isEmpty()) - { - result = (T) processCollection(collection); - } - } - else - { - result = processSingleElement(result); - } + result = processSingleElement(result); } return result; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java index c9fe37f231..9e8a9ff221 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -20,8 +20,6 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.pr import static org.alfresco.model.ContentModel.TYPE_CONTENT; -import java.util.Collection; - import javax.annotation.PostConstruct; import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; @@ -185,17 +183,6 @@ public abstract class BasePostMethodInvocationProcessor getPostMethodInvocationProcessor().register(this); } - /** - * Checks if the given object is a collection - * - * @param object Object to check - * @return true if the code is a collection, false otherwise - */ - protected boolean isCollection(T object) - { - return Collection.class.isAssignableFrom(object.getClass()); - } - /** * Filters the node if the give node reference exist and it is a * content but the logged in user is not cleared to see the it. diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java index 6e87a8d5ed..8548035977 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -20,7 +20,6 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.pr import java.util.Collection; import java.util.Iterator; -import java.util.List; import org.springframework.stereotype.Component; @@ -39,8 +38,7 @@ public class CollectionPostMethodInvocationProcessor extends BasePostMethodInvoc @Override protected Class getClassName() { - // FIXME!!! - return List.class; + return Collection.class; } /** @@ -58,12 +56,23 @@ public class CollectionPostMethodInvocationProcessor extends BasePostMethodInvoc if (!collection.isEmpty()) { Iterator iterator = collection.iterator(); - if (iterator.hasNext()) + while (iterator.hasNext()) { - BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(iterator.next()); + Object next = iterator.next(); + // TODO: Can we guarantee that all the elements of a collection can be processed by the same processor? + BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(next); if (processor != null) { - result = processor.process(object); + Object processed = processor.process(next); + if (processed == null) + { + iterator.remove(); + } + else if (!processed.equals(next)) + { + // TODO Support this, as it will be hit by e.g. collections of collections. + throw new IllegalStateException("Modifying members of a collection is not yet supported."); + } } } } From a476d21d08b3df6447bb8d5650114417e59f7a79 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Mon, 29 Jun 2015 14:34:17 +0000 Subject: [PATCH 31/33] RM-2367 (Automate AC: Access to saved search) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107344 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- ...edSearchClassificationEnforcementTest.java | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SavedSearchClassificationEnforcementTest.java diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SavedSearchClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SavedSearchClassificationEnforcementTest.java new file mode 100644 index 0000000000..e8c3c514aa --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SavedSearchClassificationEnforcementTest.java @@ -0,0 +1,174 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor; + +import static com.google.common.collect.Sets.newHashSet; +import static java.lang.Integer.MAX_VALUE; +import static org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService.ROLE_ADMIN; +import static org.alfresco.module.org_alfresco_module_rm.search.SavedSearchDetails.QUERY; +import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; +import static org.alfresco.service.cmr.search.SearchService.LANGUAGE_FTS_ALFRESCO; +import static org.alfresco.util.GUID.generate; + +import java.util.List; + +import org.alfresco.module.org_alfresco_module_rm.search.RecordsManagementSearchParameters; +import org.alfresco.module.org_alfresco_module_rm.search.SavedSearchDetails; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.search.SearchParameters; +import org.json.JSONObject; + +/** + * Integration test for saved searches with classification enforcement + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class SavedSearchClassificationEnforcementTest extends SearchClassificationEnforcementTestBase +{ + public void testSavedSearchWithClassificationEnforcement() + { + /** + * Given that a test user with mid-level security clearance exists + * and the test user is added to the RM Admin role + * and a category, a folder and five records are created in the file plan + * and two of the records are classified with the highest security level + * and another record is classified with the mid-level security level + * + * When I view the results of the saved search as admin + * The I will see all five records + * + * When I view the results of the saved search as the test user + * Then I will see the unclassified documents + * and the document with the mid-level classification + * and I won't be able to see the documents with the classification greater than my clearance level + */ + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + private NodeRef category; + private NodeRef folder; + private NodeRef record1; + private NodeRef record2; + private NodeRef record3; + private NodeRef record4; + private NodeRef record5; + private String savedSearchName = generate(); + private String searchQuery = generate(); + private List resultsForAdmin; + private List resultsForTestUser; + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#given() + */ + @Override + public void given() throws Exception + { + testUser = generate(); + createPerson(testUser); + filePlanRoleService.assignRoleToAuthority(filePlan, ROLE_ADMIN, testUser); + securityClearanceService.setUserSecurityClearance(testUser, LEVEL2); + + category = filePlanService.createRecordCategory(filePlan, generate()); + folder = recordFolderService.createRecordFolder(category, generate()); + record1 = utils.createRecord(folder, searchQuery + generate()); + record2 = utils.createRecord(folder, searchQuery + generate()); + record3 = utils.createRecord(folder, searchQuery + generate()); + record4 = utils.createRecord(folder, searchQuery + generate()); + record5 = utils.createRecord(folder, searchQuery + generate()); + + RecordsManagementSearchParameters searchParameters = new RecordsManagementSearchParameters(); + searchParameters.setIncludeUndeclaredRecords(true); + rmSearchService.saveSearch(siteId, savedSearchName, generate(), searchQuery + "*", searchParameters, true); + + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record1); + contentClassificationService.classifyContent(LEVEL2, generate(), newHashSet(REASON), record3); + contentClassificationService.classifyContent(LEVEL1, generate(), newHashSet(REASON), record5); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + SavedSearchDetails savedSearchDetails = rmSearchService.getSavedSearch(siteId, savedSearchName); + JSONObject jsonObject = new JSONObject(savedSearchDetails.toJSONString()); + String query = (String) jsonObject.get(QUERY); + + resultsForAdmin = searchAsAdmin(query); + resultsForTestUser = searchAsTestUser(query); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#then() + */ + @Override + public void then() throws Exception + { + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForAdmin); + assertEquals(5, resultsForAdmin.size()); + assertTrue(resultsForAdmin.contains(record1)); + assertTrue(resultsForAdmin.contains(record2)); + assertTrue(resultsForAdmin.contains(record3)); + assertTrue(resultsForAdmin.contains(record4)); + assertTrue(resultsForAdmin.contains(record5)); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(3, resultsForTestUser.size()); + assertTrue(resultsForTestUser.contains(record2)); + assertTrue(resultsForTestUser.contains(record3)); + assertTrue(resultsForTestUser.contains(record4)); + + return null; + } + }, testUser); + } + }); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.integration.classification.interceptor.SearchClassificationEnforcementTestBase#search(java.lang.String) + */ + @Override + protected List search(String searchQuery) + { + SearchParameters searchParameters = new SearchParameters(); + searchParameters.setQuery(searchQuery); + searchParameters.setLanguage(LANGUAGE_FTS_ALFRESCO); + searchParameters.addStore(STORE_REF_WORKSPACE_SPACESSTORE); + searchParameters.setMaxItems(MAX_VALUE); + searchParameters.setNamespace(RM_URI); + searchParameters.addQueryTemplate("keywords", "%(cm:name cm:title cm:description TEXT)"); + return searchService.query(searchParameters).getNodeRefs(); + } +} From e9a5f28f85a28e732836864767de1a2ec9ec5f47 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 29 Jun 2015 15:18:49 +0000 Subject: [PATCH 32/33] RM-2130 Support for specific instantiable collections. It's impossible to instantiate/clone a generic collection, so if a member of the collection changes then our only option is to attempt to remove it. This has two problems. Firstly, this is far more brutal than we desire in many cases. Secondly, some collections do not implement the remove method (e.g. anything returned by Arrays.asList()). As an attempt to work around this issue we've created some specific implementation processors. This introduces new potential problems - e.g. if someone has used an exotic type of list it will be replaced with an ArrayList by the ListPostMethodInvocationProcessor. +review RM git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107355 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- ...llectionPostMethodInvocationProcessor.java | 95 ++++++++---- .../ListPostMethodInvocationProcessor.java | 47 ++++++ ...llectionPostMethodInvocationProcessor.java | 61 ++++++++ .../SetPostMethodInvocationProcessor.java | 47 ++++++ ...ortedSetPostMethodInvocationProcessor.java | 45 ++++++ ...PostMethodInvocationProcessorUnitTest.java | 137 ++++++++++++++++++ ...PostMethodInvocationProcessorUnitTest.java | 112 ++++++++++++++ ...PostMethodInvocationProcessorUnitTest.java | 85 +---------- ...PostMethodInvocationProcessorUnitTest.java | 94 ++++++++++++ 9 files changed, 614 insertions(+), 109 deletions(-) create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ModifiableCollectionPostMethodInvocationProcessor.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java create mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SortedSetPostMethodInvocationProcessor.java create mode 100644 rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessorUnitTest.java create mode 100644 rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessorUnitTest.java create mode 100644 rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SortedSetPostMethodInvocationProcessorUnitTest.java diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java index 8548035977..af099d9994 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -24,7 +24,7 @@ import java.util.Iterator; import org.springframework.stereotype.Component; /** - * Collection Post Method Invocation Processor + * Collection Post Method Invocation Processor. * * @author Tuna Aksoy * @since 3.0 @@ -44,40 +44,81 @@ public class CollectionPostMethodInvocationProcessor extends BasePostMethodInvoc /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) */ - @SuppressWarnings("rawtypes") + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public T process(T object) { - T result = object; + Collection collection = ((Collection) object); - if (result != null) + if (collection != null) { - Collection collection = ((Collection) result); - if (!collection.isEmpty()) + BasePostMethodInvocationProcessor processor = pickProcessor(collection); + if (processor != null) { - Iterator iterator = collection.iterator(); - while (iterator.hasNext()) - { - Object next = iterator.next(); - // TODO: Can we guarantee that all the elements of a collection can be processed by the same processor? - BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(next); - if (processor != null) - { - Object processed = processor.process(next); - if (processed == null) - { - iterator.remove(); - } - else if (!processed.equals(next)) - { - // TODO Support this, as it will be hit by e.g. collections of collections. - throw new IllegalStateException("Modifying members of a collection is not yet supported."); - } - } - } + object = (T) processCollection(collection, processor); } } - return result; + return object; + } + + /** + * Process a collection using the supplied processor. + * + * @param collection The collection to be processed. + * @param processor A collection suitable for access by someone with the current security clearance. + */ + protected Collection processCollection(Collection collection, BasePostMethodInvocationProcessor processor) + { + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) + { + Object next = iterator.next(); + Object processed = processor.process(next); + try + { + if (processed == null) + { + iterator.remove(); + } + else if (!processed.equals(next)) + { + // Modifying members of this type of collection is not supported, so filter the whole collection. + return null; + } + } + catch (UnsupportedOperationException e) + { + // If the collection cannot be modified and it contains classified data then the whole thing must be filtered. + return null; + } + } + return collection; + } + + /** + * Pick a suitable processor for the members of the collection. We assume that all the elements of a collection can + * be processed by the same processor. + * + * @param collection The collection to be processed. + * @return The chosen processor, or {@code null} if no suitable processor could be found. + */ + @SuppressWarnings("rawtypes") + private BasePostMethodInvocationProcessor pickProcessor(Collection collection) + { + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) + { + Object next = iterator.next(); + if (next != null) + { + BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(next); + if (processor != null) + { + return processor; + } + } + } + return null; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..65124b6a8e --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessor.java @@ -0,0 +1,47 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * List Post Method Invocation Processor. This replaces the existing list with a filtered {@link ArrayList}. By doing + * this we gain the ability to replace members of a list, which is not possible using the + * {@link CollectionPostMethodInvocationProcessor}. The downside is that whatever type of list was provided gets + * replaced with an {@code ArrayList}. + * + * @author Tom Page + * @since 3.0 + */ +public class ListPostMethodInvocationProcessor extends ModifiableCollectionPostMethodInvocationProcessor +{ + @Override + protected Class getClassName() + { + return List.class; + } + + @Override + protected Collection createEmptyCollection(Collection collection) + { + return new ArrayList<>(); + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ModifiableCollectionPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ModifiableCollectionPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..95bd18d07a --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ModifiableCollectionPostMethodInvocationProcessor.java @@ -0,0 +1,61 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * List Post Method Invocation Processor. This replaces the existing list with a filtered {@link ArrayList}. By doing + * this we gain the ability to replace members of a list, which is not possible using the + * {@link CollectionPostMethodInvocationProcessor}. The downside is that whatever type of list was provided gets + * replaced with an {@code ArrayList}. + * + * @author Tom Page + * @since 3.0 + */ +public abstract class ModifiableCollectionPostMethodInvocationProcessor extends CollectionPostMethodInvocationProcessor +{ + @Override + abstract protected Class getClassName(); + + /** + * Create an empty modifiable collection. + * + * @param collection The source collection to try to mimic. + * @return The new empty collection. + */ + abstract protected Collection createEmptyCollection(Collection collection); + + /** {@inheritDoc} */ + @Override + protected Collection processCollection(Collection collection, BasePostMethodInvocationProcessor processor) + { + Collection returnList = createEmptyCollection(collection); + for (T member : collection) + { + T processed = processor.process(member); + if (processed != null) + { + returnList.add(processed); + } + } + return returnList; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..ab16dd9130 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SetPostMethodInvocationProcessor.java @@ -0,0 +1,47 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * Set Post Method Invocation Processor. This replaces the existing set with a filtered {@link HashSet}. By doing + * this we gain the ability to replace members of a set, which is not possible using the + * {@link CollectionPostMethodInvocationProcessor}. The downside is that whatever type of set was provided gets + * replaced with an {@code HashSet}. + * + * @author Tom Page + * @since 3.0 + */ +public class SetPostMethodInvocationProcessor extends ModifiableCollectionPostMethodInvocationProcessor +{ + @Override + protected Class getClassName() + { + return Set.class; + } + + @Override + protected Collection createEmptyCollection(Collection collection) + { + return new HashSet<>(); + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SortedSetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SortedSetPostMethodInvocationProcessor.java new file mode 100644 index 0000000000..77030ff263 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SortedSetPostMethodInvocationProcessor.java @@ -0,0 +1,45 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import java.util.Collection; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * Sorted Set Post Method Invocation Processor. This replaces the existing set with a filtered {@link TreeSet}. + * + * @author Tom Page + * @since 3.0 + */ +public class SortedSetPostMethodInvocationProcessor extends ModifiableCollectionPostMethodInvocationProcessor +{ + @Override + protected Class getClassName() + { + return SortedSet.class; + } + + @Override + protected Collection createEmptyCollection(Collection collection) + { + SortedSet sortedSet = (SortedSet) collection; + return new TreeSet<>(sortedSet.comparator()); + } +} diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessorUnitTest.java new file mode 100644 index 0000000000..09a682d9d5 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessorUnitTest.java @@ -0,0 +1,137 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +/** + * Unit tests for the {@link CollectionPostMethodInvocationProcessor}. + * + * @author Tom Page + * @since 3.0 + */ +public class CollectionPostMethodInvocationProcessorUnitTest +{ + private static final String NON_FILTERED = "NON_FILTERED"; + private static final String FILTERED = "FILTERED"; + private static final String CHANGED_INPUT = "CHANGED_INPUT"; + private static final String CHANGED_OUTPUT = "CHANGED_OUTPUT"; + + @InjectMocks CollectionPostMethodInvocationProcessor collectionPostMethodInvocationProcessor; + @Mock PostMethodInvocationProcessor mockPostMethodInvocationProcessor; + @Mock BasePostMethodInvocationProcessor mockStringProcessor; + + @Before + public void setUp() + { + initMocks(this); + + when(mockPostMethodInvocationProcessor.getProcessor(isA(String.class))).thenReturn(mockStringProcessor); + + when(mockStringProcessor.process(NON_FILTERED)).thenReturn(NON_FILTERED); + when(mockStringProcessor.process(FILTERED)).thenReturn(null); + when(mockStringProcessor.process(CHANGED_INPUT)).thenReturn(CHANGED_OUTPUT); + } + + @Test + public void testProcess_copesWithNull() + { + Object result = collectionPostMethodInvocationProcessor.process(null); + + assertNull("Expected null collection to be passed through.", result); + } + + @Test + public void testProcess_nullMember() + { + List collection = new ArrayList<>(); + collection.add(null); + + Object result = collectionPostMethodInvocationProcessor.process(collection); + + assertEquals("Expected collection containing null to be passed through.", collection, result); + } + + @Test + public void testProcess_nonFilteredMember() + { + Object collection = Arrays.asList(NON_FILTERED); + + Object result = collectionPostMethodInvocationProcessor.process(collection); + + assertEquals("Expected element to still be present in result.", collection, result); + } + + @Test + public void testProcess_filteredMemberInModifiableList() + { + List collection = new ArrayList<>(Arrays.asList(FILTERED)); + + Collection result = collectionPostMethodInvocationProcessor.process(collection); + + assertTrue("Expected an empty list.", result.isEmpty()); + } + + @Test + public void testProcess_filteredMemberInUnmodifiableList() + { + List collection = Arrays.asList(FILTERED, NON_FILTERED); + + Collection result = collectionPostMethodInvocationProcessor.process(collection); + + assertNull("Since the collection could not be modified the whole thing should be filtered.", result); + } + + @Test + public void testProcess_modifiedMember() + { + List collection = Arrays.asList(NON_FILTERED, CHANGED_INPUT); + + Collection result = collectionPostMethodInvocationProcessor.process(collection); + + assertNull("Since the Collection interface does not support replacement, the whole collection should be filtered.", + result); + } + + @Test + public void testProcess_noProcessorDefined() + { + List collection = Arrays.asList(1, 4, 91); + + Collection result = collectionPostMethodInvocationProcessor.process(collection); + + assertEquals("If no processor is defined for the members then the whole list should be returned.", collection, + result); + } +} diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessorUnitTest.java new file mode 100644 index 0000000000..e7cc4db762 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ListPostMethodInvocationProcessorUnitTest.java @@ -0,0 +1,112 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +/** + * Unit tests for {@link ListPostMethodInvocationProcessor}. + * + * @author Tom Page + * @since 3.0 + */ +public class ListPostMethodInvocationProcessorUnitTest +{ + private static final String NON_FILTERED = "NON_FILTERED"; + private static final String FILTERED = "FILTERED"; + private static final String CHANGED_INPUT = "CHANGED_INPUT"; + private static final String CHANGED_OUTPUT = "CHANGED_OUTPUT"; + + @InjectMocks ListPostMethodInvocationProcessor listPostMethodInvocationProcessor; + @Mock PostMethodInvocationProcessor mockPostMethodInvocationProcessor; + @Mock BasePostMethodInvocationProcessor mockStringProcessor; + + @Before + public void setUp() + { + initMocks(this); + + when(mockPostMethodInvocationProcessor.getProcessor(isA(List.class))).thenReturn(listPostMethodInvocationProcessor); + when(mockPostMethodInvocationProcessor.getProcessor(isA(String.class))).thenReturn(mockStringProcessor); + + when(mockStringProcessor.process(NON_FILTERED)).thenReturn(NON_FILTERED); + when(mockStringProcessor.process(FILTERED)).thenReturn(null); + when(mockStringProcessor.process(CHANGED_INPUT)).thenReturn(CHANGED_OUTPUT); + } + + @Test + public void testProcessCollection_emptyList() + { + List collection = new ArrayList<>(); + + Collection result = listPostMethodInvocationProcessor.processCollection(collection, mockStringProcessor); + + assertEquals(collection, result); + } + + @Test + public void testProcessCollection_completelyFiltered() + { + List collection = Arrays.asList(FILTERED, FILTERED); + + Collection result = listPostMethodInvocationProcessor.processCollection(collection, mockStringProcessor); + + assertTrue("Expected all members of the list to be removed.", result.isEmpty()); + } + + @Test + public void testProcessCollection_supportsReplacement() + { + List collection = Arrays.asList(NON_FILTERED, CHANGED_INPUT); + + Collection result = listPostMethodInvocationProcessor.processCollection(collection, mockStringProcessor); + + List expected = Arrays.asList(NON_FILTERED, CHANGED_OUTPUT); + assertEquals(expected, result); + } + + @Test + public void testProcess_listOfLists() + { + List innerListA = Arrays.asList(FILTERED, NON_FILTERED, CHANGED_INPUT); + List innerListB = Arrays.asList(CHANGED_INPUT, FILTERED, NON_FILTERED); + List> collection = Arrays.asList(innerListA, innerListB); + + Collection> result = listPostMethodInvocationProcessor.process(collection); + + List expectedInnerListA = Arrays.asList(NON_FILTERED, CHANGED_OUTPUT); + List expectedInnerListB = Arrays.asList(CHANGED_OUTPUT, NON_FILTERED); + List> expected = Arrays.asList(expectedInnerListA, expectedInnerListB); + assertEquals(expected, result); + } +} diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java index 1d4ae13864..c8ddc99bd7 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java @@ -18,15 +18,10 @@ */ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; -import static com.google.common.collect.ImmutableList.copyOf; -import static com.google.common.collect.Lists.newArrayList; -import static java.util.Collections.unmodifiableCollection; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.when; import static org.springframework.extensions.webscripts.GUID.generate; -import java.util.ArrayList; - import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; import org.alfresco.service.cmr.repository.NodeRef; @@ -90,83 +85,9 @@ public class NodeRefPostMethodInvocationProcessorUnitTest extends BaseUnitTest } @Test - public void testCollection_bothNodesConent_userClearedForBoth() + public void testProcessingNull() { - NodeRef nodeRef1 = generateNodeRef(); - NodeRef nodeRef2 = generateNodeRef(); - ArrayList nodeRefs = newArrayList(nodeRef1, nodeRef2); - - when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(true); - when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(true); - - when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(true); - when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(true); - - assertEquals(nodeRefs, nodeRefPostMethodInvocationProcessor.process(nodeRefs)); - } - - @Test - public void testCollection_bothNodesContent_userClearedForOne() - { - NodeRef nodeRef1 = generateNodeRef(); - NodeRef nodeRef2 = generateNodeRef(); - ArrayList nodeRefs = newArrayList(nodeRef1, nodeRef2); - - when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(true); - when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(true); - - when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(true); - when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(false); - - assertEquals(newArrayList(nodeRef1), nodeRefPostMethodInvocationProcessor.process(nodeRefs)); - } - - @SuppressWarnings("rawtypes") - @Test - public void testCollection_bothNodesContent_userClearedForNone() - { - NodeRef nodeRef1 = generateNodeRef(); - NodeRef nodeRef2 = generateNodeRef(); - ArrayList nodeRefs = newArrayList(nodeRef1, nodeRef2); - - when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(true); - when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(false); - - when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(true); - when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(false); - - assertEquals(new ArrayList(), nodeRefPostMethodInvocationProcessor.process(unmodifiableCollection(nodeRefs))); - } - - @Test - public void testCollection_onlyOneNodeContent_userClearedForBoth() - { - NodeRef nodeRef1 = generateNodeRef(); - NodeRef nodeRef2 = generateNodeRef(); - ArrayList nodeRefs = newArrayList(nodeRef1, nodeRef2); - - when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(false); - when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(true); - - when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(true); - when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(true); - - assertEquals(nodeRefs, nodeRefPostMethodInvocationProcessor.process(copyOf(nodeRefs))); - } - - @Test - public void testCollection_bothNodesNotContent_userClearedForBoth() - { - NodeRef nodeRef1 = generateNodeRef(); - NodeRef nodeRef2 = generateNodeRef(); - ArrayList nodeRefs = newArrayList(nodeRef1, nodeRef2); - - when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef1), TYPE_CONTENT)).thenReturn(false); - when(mockedContentClassificationService.hasClearance(nodeRef1)).thenReturn(true); - - when(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef2), TYPE_CONTENT)).thenReturn(false); - when(mockedContentClassificationService.hasClearance(nodeRef2)).thenReturn(true); - - assertEquals(nodeRefs, nodeRefPostMethodInvocationProcessor.process(copyOf(nodeRefs))); + assertEquals("Expected null to be passed through without error.", null, + nodeRefPostMethodInvocationProcessor.process((NodeRef) null)); } } diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SortedSetPostMethodInvocationProcessorUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SortedSetPostMethodInvocationProcessorUnitTest.java new file mode 100644 index 0000000000..918140d06e --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/SortedSetPostMethodInvocationProcessorUnitTest.java @@ -0,0 +1,94 @@ +/* + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +/** + * Unit tests for {@link SortedSetPostMethodInvocationProcessor}. + * + * @author Tom Page + * @since 3.0 + */ +public class SortedSetPostMethodInvocationProcessorUnitTest +{ + private static final String NON_FILTERED = "NON_FILTERED"; + private static final String FILTERED = "FILTERED"; + private static final String SHORT_INPUT = "SHORT_INPUT"; + private static final String REALLY_LONG_OUTPUT_STRING = "REALLY_LONG_OUTPUT_STRING"; + + @InjectMocks SortedSetPostMethodInvocationProcessor sortedSetPostMethodInvocationProcessor; + @Mock BasePostMethodInvocationProcessor mockStringProcessor; + + @Before + public void setUp() + { + initMocks(this); + + when(mockStringProcessor.process(NON_FILTERED)).thenReturn(NON_FILTERED); + when(mockStringProcessor.process(FILTERED)).thenReturn(null); + when(mockStringProcessor.process(SHORT_INPUT)).thenReturn(REALLY_LONG_OUTPUT_STRING); + } + + /** + * Given I have a sorted set of input strings + * When I pass it to the SortedSet processor + * Then I expect items above my clearance to be filtered + * And I expect items below my clearance to be passed through + * And I expect items that get changed by the filtering process to be changed + * And I expect the output set to be sorted using the same comparator as the input. + */ + @Test + public void testProcessCollection() + { + // Create a custom comparator that sorts based on the length of the strings. + Comparator comparator = new Comparator() + { + public int compare(String o1, String o2) + { + return o1.length() - o2.length(); + } + }; + SortedSet collection = new TreeSet<>(comparator); + collection.add(SHORT_INPUT); + collection.add(NON_FILTERED); + collection.add(FILTERED); + + Collection result = sortedSetPostMethodInvocationProcessor.processCollection(collection, mockStringProcessor); + + Iterator iterator = result.iterator(); + assertEquals("Expected the first element to be the shortest", NON_FILTERED, iterator.next()); + assertEquals("Expected the second element to be the longest", REALLY_LONG_OUTPUT_STRING, iterator.next()); + assertFalse("Expected two elements in output", iterator.hasNext()); + } +} From 7a3bdd36992bdbda27add5c8bab64bbcab5de571 Mon Sep 17 00:00:00 2001 From: Tuna Aksoy Date: Mon, 29 Jun 2015 17:03:48 +0000 Subject: [PATCH 33/33] RM-2130 (Check classification after method execution, filtering results where appropriate) +review RM-94 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@107363 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../classified-content-context.xml | 2 - ...AbstractPostMethodInvocationProcessor.java | 53 ----------------- .../ArrayPostMethodInvocationProcessor.java | 48 +++++++-------- ...ationRefPostMethodInvocationProcessor.java | 28 ++++++--- .../BasePostMethodInvocationProcessor.java | 55 ++--------------- ...ationRefPostMethodInvocationProcessor.java | 42 +++++++------ .../NodeRefPostMethodInvocationProcessor.java | 20 +++++-- ...gResultsPostMethodInvocationProcessor.java | 59 +++++++++++-------- ...eckValuePostMethodInvocationProcessor.java | 22 +++++-- ...eResultsPostMethodInvocationProcessor.java | 35 ++++++----- ...esultSetPostMethodInvocationProcessor.java | 2 +- ...StoreRefPostMethodInvocationProcessor.java | 20 +++++-- 12 files changed, 173 insertions(+), 213 deletions(-) delete mode 100644 rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml index c3222767b6..5f8035cfc2 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml @@ -66,8 +66,6 @@ - - diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java deleted file mode 100644 index 894e6e0216..0000000000 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AbstractPostMethodInvocationProcessor.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; - - -/** - * Abstract Post Method Invocation Processor - * - * @author Tuna Aksoy - * @since 3.0 - */ -public abstract class AbstractPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor -{ - /** - * Abstract method to process a single element - * - * @param object The element to process - * @return Processed element - */ - protected abstract T processSingleElement(T object); - - /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) - */ - @Override - public T process(T object) - { - T result = object; - - if (result != null) - { - result = processSingleElement(result); - } - - return result; - } -} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java index f1fce3b821..1584276c36 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java @@ -19,7 +19,6 @@ package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; import static java.lang.reflect.Array.newInstance; -import static org.alfresco.util.ParameterCheck.mandatory; import java.lang.reflect.Array; import java.util.ArrayList; @@ -52,39 +51,40 @@ public class ArrayPostMethodInvocationProcessor extends BasePostMethodInvocation @Override public T process(T object) { - mandatory("object", object); - T result = object; - T[] objects = (T[]) result; - T obj = objects[0]; - BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(obj); - if (processor != null) + if (result != null) { - int length = objects.length; - List processedObjects = new ArrayList(); + T[] objects = (T[]) result; + T obj = objects[0]; - for (int i = 0; i < length; i++) + BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(obj); + if (processor != null) { - Object processedObject = processor.process(objects[i]); - if (processedObject != null) + int length = objects.length; + List processedObjects = new ArrayList(); + + for (int i = 0; i < length; i++) { - processedObjects.add(processedObject); + Object processedObject = processor.process(objects[i]); + if (processedObject != null) + { + processedObjects.add(processedObject); + } } + + int size = processedObjects.size(); + T[] objs = (T[]) newInstance(obj.getClass(), size); + + for (int i = 0; i < size; i++) + { + objs[i] = (T) processedObjects.get(i); + } + + result = (T) objs; } - - int size = processedObjects.size(); - T[] objs = (T[]) newInstance(obj.getClass(), size); - - for (int i = 0; i < size; i++) - { - objs[i] = (T) processedObjects.get(i); - } - - result = (T) objs; } return result; } - } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java index 990aa3df7c..e7e83dfe8b 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java @@ -29,7 +29,7 @@ import org.springframework.stereotype.Component; * @since 3.0 */ @Component -public class AssociationRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor +public class AssociationRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() @@ -41,19 +41,29 @@ public class AssociationRefPostMethodInvocationProcessor extends AbstractPostMet } /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) */ @Override - protected T processSingleElement(T object) + public T process(T object) { - AssociationRef associationRef = getClassName().cast(object); + T result = object; - NodeRef sourceRef = associationRef.getSourceRef(); - NodeRef filteredSource = filter(sourceRef); + if (result != null) + { + AssociationRef associationRef = getClassName().cast(result); - NodeRef targetRef = associationRef.getTargetRef(); - NodeRef filteredTarget = filter(targetRef); + NodeRef sourceRef = associationRef.getSourceRef(); + NodeRef filteredSource = filter(sourceRef); - return (filteredSource == null || filteredTarget == null) ? null : object; + NodeRef targetRef = associationRef.getTargetRef(); + NodeRef filteredTarget = filter(targetRef); + + if (filteredSource == null || filteredTarget == null) + { + result = null; + } + } + + return result; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java index 9e8a9ff221..9024286533 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -24,11 +24,9 @@ import javax.annotation.PostConstruct; import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.classification.SecurityClearanceService; -import org.alfresco.repo.cache.SimpleCache; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.util.Pair; import org.springframework.beans.factory.annotation.Autowired; /** @@ -59,10 +57,6 @@ public abstract class BasePostMethodInvocationProcessor @Autowired private PostMethodInvocationProcessor postMethodInvocationProcessor; - /** Cache to hold the filtered node information */ - @Autowired - private SimpleCache, Pair> basePostMethodInvocationProcessorCache; - /** * @return the nodeService */ @@ -103,14 +97,6 @@ public abstract class BasePostMethodInvocationProcessor return this.postMethodInvocationProcessor; } - /** - * @return the cache - */ - protected SimpleCache, Pair> getCache() - { - return this.basePostMethodInvocationProcessorCache; - } - /** * @param nodeService the nodeService to set */ @@ -152,11 +138,12 @@ public abstract class BasePostMethodInvocationProcessor } /** - * @param cache the cache to set + * Registers the post method invocation processors */ - public void setCache(SimpleCache, Pair> cache) + @PostConstruct + public void register() { - this.basePostMethodInvocationProcessorCache = cache; + getPostMethodInvocationProcessor().register(this); } /** @@ -172,16 +159,7 @@ public abstract class BasePostMethodInvocationProcessor * @param object The object to check * @return The given object */ - public abstract T process(T object); - - /** - * Registers the post method invocation processors - */ - @PostConstruct - public void register() - { - getPostMethodInvocationProcessor().register(this); - } + protected abstract T process(T object); /** * Filters the node if the give node reference exist and it is a @@ -202,29 +180,6 @@ public abstract class BasePostMethodInvocationProcessor filter = null; } -// if (filter != null) -// { -// String uniqueCacheKey = getFullyAuthenticatedUser() /*+ userClearance?*/; -// -// Pair cacheKey = new Pair(uniqueCacheKey, filter); -// Pair cacheValue = getCache().get(cacheKey); -// -// if (cacheValue == null || !cacheValue.getFirst().booleanValue()) -// { -// if (getNodeService().exists(nodeRef) && -// getDictionaryService().isSubClass(getNodeService().getType(nodeRef), TYPE_CONTENT) && -// !getContentClassificationService().hasClearance(nodeRef)) -// { -// filter = null; -// } -// getCache().put(new Pair(uniqueCacheKey, nodeRef), new Pair(true, filter)); -// } -// else -// { -// filter = getCache().get(cacheKey).getSecond(); -// } -// } - return filter; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java index b6d2b85786..acd003e9d2 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.java @@ -29,7 +29,7 @@ import org.springframework.stereotype.Component; * @since 3.0 */ @Component -public class ChildAssociationRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor +public class ChildAssociationRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() @@ -41,28 +41,34 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends AbstractPo } /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) */ @Override - protected T processSingleElement(T object) + public T process(T object) { - T result; + T result = object; - ChildAssociationRef childAssociationRef = getClassName().cast(object); - - NodeRef childRef = childAssociationRef.getChildRef(); - NodeRef filteredChildRef = filter(childRef); - - NodeRef parentRef = childAssociationRef.getParentRef(); - NodeRef filteredParentRef; - if (parentRef == null) + if (result != null) { - result = filteredChildRef == null ? null : object; - } - else - { - filteredParentRef = filter(parentRef); - result = (filteredChildRef == null || filteredParentRef == null) ? null : object; + ChildAssociationRef childAssociationRef = getClassName().cast(result); + + NodeRef childRef = childAssociationRef.getChildRef(); + NodeRef filteredChildRef = filter(childRef); + + NodeRef parentRef = childAssociationRef.getParentRef(); + NodeRef filteredParentRef; + if (parentRef == null && filteredChildRef == null) + { + result = null; + } + else + { + filteredParentRef = filter(parentRef); + if (filteredChildRef == null || filteredParentRef == null) + { + result = null; + } + } } return result; diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java index 9e7a267fda..d358357077 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.java @@ -28,7 +28,7 @@ import org.springframework.stereotype.Component; * @since 3.0 */ @Component -public class NodeRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor +public class NodeRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() @@ -40,12 +40,22 @@ public class NodeRefPostMethodInvocationProcessor extends AbstractPostMethodInvo } /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) */ @Override - protected T processSingleElement(T object) + public T process(T object) { - NodeRef nodeRef = getClassName().cast(object); - return filter(nodeRef) == null ? null : object; + T result = object; + + if (result != null) + { + NodeRef nodeRef = getClassName().cast(result); + if (filter(nodeRef) == null) + { + result = null; + } + } + + return result; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java index 0497efd59c..345f82e88b 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java @@ -50,34 +50,41 @@ public class PagingResultsPostMethodInvocationProcessor extends BasePostMethodIn @Override public T process(T object) { - final PagingResults pagingResults = getClassName().cast(object); - List page = pagingResults.getPage(); - final List processedPage = getPostMethodInvocationProcessor().process(page); + T result = object; - return (T) new PagingResults() + if (result != null) { - @Override - public String getQueryExecutionId() + final PagingResults pagingResults = getClassName().cast(result); + List page = pagingResults.getPage(); + final List processedPage = getPostMethodInvocationProcessor().process(page); + + result = (T) new PagingResults() { - return pagingResults.getQueryExecutionId(); - } - @Override - public List getPage() - { - return processedPage; - } - @Override - public boolean hasMoreItems() - { - // FIXME: hasMoreItems might not be correct - return pagingResults.hasMoreItems(); - } - @Override - public Pair getTotalResultCount() - { - int size = processedPage.size(); - return new Pair(size, size); - } - }; + @Override + public String getQueryExecutionId() + { + return pagingResults.getQueryExecutionId(); + } + @Override + public List getPage() + { + return processedPage; + } + @Override + public boolean hasMoreItems() + { + // hasMoreItems might not be correct. Cannot determine the correct value as request details are needed. + return pagingResults.hasMoreItems(); + } + @Override + public Pair getTotalResultCount() + { + int size = processedPage.size(); + return new Pair(size, size); + } + }; + } + + return result; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java index e7e68c335c..946059818a 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.java @@ -29,7 +29,7 @@ import org.springframework.stereotype.Component; * @since 3.0 */ @Component -public class PermissionCheckValuePostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor +public class PermissionCheckValuePostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() @@ -41,13 +41,23 @@ public class PermissionCheckValuePostMethodInvocationProcessor extends AbstractP } /** - * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) */ @Override - protected T processSingleElement(T object) + public T process(T object) { - PermissionCheckValue permissionCheckValue = getClassName().cast(object); - NodeRef nodeRef = permissionCheckValue.getNodeRef(); - return filter(nodeRef) == null ? null : object; + T result = object; + + if (result != null) + { + PermissionCheckValue permissionCheckValue = getClassName().cast(result); + NodeRef nodeRef = permissionCheckValue.getNodeRef(); + if (filter(nodeRef) == null) + { + result = null; + } + } + + return result; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java index 298f56f95e..397fe98922 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java @@ -52,26 +52,33 @@ public class QueryEngineResultsPostMethodInvocationProcessor extends BasePostMet @Override public T process(T object) { - QueryEngineResults queryEngineResults = getClassName().cast(object); - Map, ResultSet> resultsMap = queryEngineResults.getResults(); - Map, ResultSet> returnMap = new HashMap<>(); - BasePostMethodInvocationProcessor processor = null; + T result = object; - for (Entry, ResultSet> entry : resultsMap.entrySet()) + if (result != null) { - ResultSet value = entry.getValue(); - if (processor == null) + QueryEngineResults queryEngineResults = getClassName().cast(result); + Map, ResultSet> resultsMap = queryEngineResults.getResults(); + Map, ResultSet> returnMap = new HashMap<>(); + BasePostMethodInvocationProcessor processor = null; + + for (Entry, ResultSet> entry : resultsMap.entrySet()) { - processor = getPostMethodInvocationProcessor().getProcessor(value); + ResultSet value = entry.getValue(); + if (processor == null) + { + processor = getPostMethodInvocationProcessor().getProcessor(value); + } + + ResultSet newResultSet = processor.process(value); + if (newResultSet != null) + { + returnMap.put(entry.getKey(), newResultSet); + } } - ResultSet newResultSet = processor.process(value); - if (newResultSet != null) - { - returnMap.put(entry.getKey(), newResultSet); - } + result = (T) new QueryEngineResults(returnMap); } - return (T) new QueryEngineResults(returnMap); + return result; } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java index 81e5a322ae..4123b3967a 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java @@ -61,7 +61,7 @@ public class ResultSetPostMethodInvocationProcessor extends BasePostMethodInvoca if (result != null) { - ResultSet returnedObject = getClassName().cast(object); + ResultSet returnedObject = getClassName().cast(result); BitSet inclusionMask = new BitSet(returnedObject.length()); FilteringResultSet filteringResultSet = new FilteringResultSet(returnedObject, inclusionMask); diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java index 2093953cff..f0f310c86f 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.java @@ -29,7 +29,7 @@ import org.springframework.stereotype.Component; * @since 3.0 */ @Component -public class StoreRefPostMethodInvocationProcessor extends AbstractPostMethodInvocationProcessor +public class StoreRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor { /** * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() @@ -44,10 +44,20 @@ public class StoreRefPostMethodInvocationProcessor extends AbstractPostMethodInv * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) */ @Override - protected T processSingleElement(T object) + public T process(T object) { - StoreRef storeRef = getClassName().cast(object); - NodeRef nodeRef = getNodeService().getRootNode(storeRef); - return filter(nodeRef) == null ? null : object; + T result = object; + + if (result != null) + { + StoreRef storeRef = getClassName().cast(result); + NodeRef nodeRef = getNodeService().getRootNode(storeRef); + if (filter(nodeRef) == null) + { + result = null; + } + } + + return result; } }