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 1ae526ec16..60876950c6 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,18 @@ - + - + + @@ -29,6 +40,33 @@ + + + + + + + + + + + + + + + + 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 c0c2cb2f46..8df31092a8 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,12 @@ - - - + 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..c4d07fd3a5 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; /** @@ -43,6 +45,9 @@ public class RMActionProxyFactoryBean extends ProxyFactoryBean /** Records management audit service */ protected RecordsManagementAuditService recordsManagementAuditService; + /** transaction service */ + private TransactionService transactionService; + /** * Set action service * @@ -73,6 +78,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,8 +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; } 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 b02e13a6cf..ee11effb22 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 @@ -69,6 +69,8 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem private ExemptionCategoryFieldsValidator exemptionCategoryFieldsValidator = new ExemptionCategoryFieldsValidator(); private ClassificationSchemeEntityValidator exemptionCategoryValidator = new ClassificationSchemeEntityValidator<>(exemptionCategoryFieldsValidator); + private boolean isInitialised = false; + public ClassificationServiceBootstrap(AuthenticationUtil authUtil, TransactionService txService, AttributeService attributeService, @@ -93,6 +95,11 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem public ExemptionCategoryManager getExemptionCategoryManager() { return exemptionCategoryManager; } public ClearanceLevelManager getClearanceLevelManager() { return clearanceLevelManager; } + public boolean isInitialised() + { + return isInitialised; + } + @Override public void onBootstrap(ApplicationEvent event) { authenticationUtil.runAsSystem(new org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork() @@ -116,6 +123,7 @@ public class ClassificationServiceBootstrap extends AbstractLifecycleBean implem exemptionCategoryManager.setExemptionCategories(exemptionCategories); initConfiguredClearanceLevels(classificationLevelManager.getClassificationLevels()); + isInitialised = true; return null; } }; 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 26ff70be95..8d9f857e37 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 @@ -34,6 +34,7 @@ import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationE import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.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.repository.NodeRef; import org.alfresco.service.namespace.QName; @@ -63,18 +64,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/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..f3a366b6c6 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/ClassificationMethodInterceptor.java @@ -0,0 +1,129 @@ +/* + * 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 new file mode 100644 index 0000000000..5bb5be1062 --- /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/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..1584276c36 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ArrayPostMethodInvocationProcessor.java @@ -0,0 +1,90 @@ +/* + * 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 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 +{ + /** + * @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) + { + T result = object; + + if (result != null) + { + 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/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..e7e83dfe8b --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/AssociationRefPostMethodInvocationProcessor.java @@ -0,0 +1,69 @@ +/* + * 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.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.stereotype.Component; + +/** + * AssociationRef Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +@Component +public class AssociationRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + protected 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) + { + T result = object; + + if (result != null) + { + AssociationRef associationRef = getClassName().cast(result); + + NodeRef sourceRef = associationRef.getSourceRef(); + NodeRef filteredSource = filter(sourceRef); + + 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 new file mode 100644 index 0000000000..9024286533 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/BasePostMethodInvocationProcessor.java @@ -0,0 +1,185 @@ +/* + * 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.model.ContentModel.TYPE_CONTENT; + +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.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Base class for post method invocation processors + * + * @author Tuna Aksoy + * @since 3.0 + */ +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; + + /** + * @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; + } + + /** + * @return the securityClearanceService + */ + protected SecurityClearanceService getSecurityClearanceService() + { + return this.securityClearanceService; + } + + /** + * @return the postMethodInvocationProcessor + */ + protected PostMethodInvocationProcessor getPostMethodInvocationProcessor() + { + return this.postMethodInvocationProcessor; + } + + /** + * @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; + } + + /** + * @param securityClearanceService the securityClearanceService to set + */ + public void setSecurityClearanceService(SecurityClearanceService securityClearanceService) + { + this.securityClearanceService = securityClearanceService; + } + + /** + * @param postMethodInvocationProcessor the postMethodInvocationProcessor to set + */ + public void setPostMethodInvocationProcessor(PostMethodInvocationProcessor postMethodInvocationProcessor) + { + this.postMethodInvocationProcessor = postMethodInvocationProcessor; + } + + /** + * Registers the post method invocation processors + */ + @PostConstruct + public void register() + { + getPostMethodInvocationProcessor().register(this); + } + + /** + * Gets the class name + * + * @return The class name + */ + protected abstract Class getClassName(); + + /** + * Performs checks on the given object and throws exception if not all checks pass + * + * @param object The object to check + * @return The given object + */ + protected abstract T process(T object); + + /** + * 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 NodeRef filter(NodeRef nodeRef) + { + NodeRef filter = nodeRef; + + if (getNodeService().exists(nodeRef) && + getDictionaryService().isSubClass(getNodeService().getType(nodeRef), TYPE_CONTENT) && + !getContentClassificationService().hasClearance(nodeRef)) + { + 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 new file mode 100644 index 0000000000..acd003e9d2 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ChildAssociationRefPostMethodInvocationProcessor.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 org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.stereotype.Component; + +/** + * ChildAssociationRef Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +@Component +public class ChildAssociationRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + protected 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) + { + T result = object; + + if (result != null) + { + 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/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..af099d9994 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/CollectionPostMethodInvocationProcessor.java @@ -0,0 +1,124 @@ +/* + * 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.springframework.stereotype.Component; + +/** + * Collection Post Method Invocation Processor. + * + * @author Tuna Aksoy + * @since 3.0 + */ +@Component +public class CollectionPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @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", "unchecked" }) + @Override + public T process(T object) + { + Collection collection = ((Collection) object); + + if (collection != null) + { + BasePostMethodInvocationProcessor processor = pickProcessor(collection); + if (processor != null) + { + object = (T) processCollection(collection, processor); + } + } + + 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/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..d358357077 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessor.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 org.alfresco.service.cmr.repository.NodeRef; +import org.springframework.stereotype.Component; + +/** + * NodeRef Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +@Component +public class NodeRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + protected 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) + { + 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 new file mode 100644 index 0000000000..345f82e88b --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PagingResultsPostMethodInvocationProcessor.java @@ -0,0 +1,90 @@ +/* + * 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; +import org.springframework.stereotype.Component; + +/** + * PagingResults Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +@Component +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) + { + T result = object; + + if (result != null) + { + final PagingResults pagingResults = getClassName().cast(result); + List page = pagingResults.getPage(); + final List processedPage = getPostMethodInvocationProcessor().process(page); + + result = (T) new PagingResults() + { + @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 new file mode 100644 index 0000000000..946059818a --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PermissionCheckValuePostMethodInvocationProcessor.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.classification.interceptor.processor; + +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 + * + * @author Tuna Aksoy + * @since 3.0 + */ +@Component +public class PermissionCheckValuePostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @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.BasePostMethodInvocationProcessor#process(java.lang.Object) + */ + @Override + public T process(T 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/PostMethodInvocationProcessor.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java new file mode 100644 index 0000000000..775d03a169 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PostMethodInvocationProcessor.java @@ -0,0 +1,126 @@ +/* + * 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.lang.reflect.Array; +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 + * + * @author Tuna Aksoy + * @since 3.0 + */ +public class PostMethodInvocationProcessor +{ + /** Logger */ + private static Logger LOG = Logger.getLogger(PostMethodInvocationProcessor.class); + + /** 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 + */ + private Map, BasePostMethodInvocationProcessor> getProcessors() + { + return this.processors; + } + + /** + * Gets the processor from the available processors + * + * @param object The post invocation object + * @return The suitable processor for the given class + */ + protected BasePostMethodInvocationProcessor getProcessor(Object object) + { + mandatory("object", object); + + BasePostMethodInvocationProcessor result = null; + Class clazz = object.getClass(); + + if (clazz.isArray()) + { + result = getProcessors().get(Array.class); + } + + if (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 + * + * @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..85585653be --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/PreMethodInvocationProcessor.java @@ -0,0 +1,288 @@ +/* + * 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 +{ + /** Key to mark the transaction as processing */ + 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"); + } + +// /** 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. + * + * @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 /*getTransactionService().*/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/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..397fe98922 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessor.java @@ -0,0 +1,84 @@ +/* + * 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.Map.Entry; +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}. + * + * @author Tom Page + * @since 3.0 + */ +@Component +public class QueryEngineResultsPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @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) + { + T result = object; + + if (result != 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()) + { + ResultSet value = entry.getValue(); + if (processor == null) + { + processor = getPostMethodInvocationProcessor().getProcessor(value); + } + + ResultSet newResultSet = processor.process(value); + if (newResultSet != null) + { + returnMap.put(entry.getKey(), newResultSet); + } + } + + result = (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 new file mode 100644 index 0000000000..4123b3967a --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/ResultSetPostMethodInvocationProcessor.java @@ -0,0 +1,118 @@ +/* + * 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.service.cmr.search.PermissionEvaluationMode.EAGER; + +import java.util.BitSet; + +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.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 + * + * @author Tuna Aksoy + * @since 3.0 + */ +@Component +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; + } + + /** + * @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; + + if (result != null) + { + ResultSet returnedObject = getClassName().cast(result); + + 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++) + { + 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); + } + else + { + 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 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 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/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..f0f310c86f --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/StoreRefPostMethodInvocationProcessor.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.classification.interceptor.processor; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.springframework.stereotype.Component; + +/** + * StoreRef Post Method Invocation Processor + * + * @author Tuna Aksoy + * @since 3.0 + */ +@Component +public class StoreRefPostMethodInvocationProcessor extends BasePostMethodInvocationProcessor +{ + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#getClassName() + */ + @Override + protected Class getClassName() + { + return StoreRef.class; + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.AbstractPostMethodInvocationProcessor#processSingleElement(java.lang.Object) + */ + @Override + public T process(T 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; + } +} 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..bdea4ef915 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/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/DocumentBrowseClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentBrowseClassificationEnforcementTest.java new file mode 100644 index 0000000000..b7c8b364e7 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentBrowseClassificationEnforcementTest.java @@ -0,0 +1,326 @@ +/* + * 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.List; + +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 DocumentBrowseClassificationEnforcementTest extends BrowseClassificationEnforcementTestBase +{ + /** + * @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 browse the document library as admin + * Then I will see both documents + * + * When I browse the document library 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 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, generate(), TYPE_CONTENT).getNodeRef(); + doc2 = fileFolderService.create(folder, 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 = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); + } + + /** + * @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()); + + List docs = newArrayList(doc1, doc2); + assertTrue(docs.contains(resultsForAdmin.get(0).getChildRef())); + assertTrue(docs.contains(resultsForAdmin.get(1).getChildRef())); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(1, resultsForTestUser.size()); + assertEquals(doc2, resultsForTestUser.get(0).getChildRef()); + + 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 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 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() + */ + @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, 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); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + resultsForAdmin = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); + } + + /** + * @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()); + + 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; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(2, resultsForTestUser.size()); + + List docs = newArrayList(doc2, doc3); + assertTrue(docs.contains(resultsForTestUser.get(0).getChildRef())); + assertTrue(docs.contains(resultsForTestUser.get(1).getChildRef())); + + 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 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 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() + */ + @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, 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); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + resultsForAdmin = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); + } + + /** + * @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()); + + 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; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(3, resultsForTestUser.size()); + + 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; + } + }, 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..0a56a158d4 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/DocumentSearchClassificationEnforcementTest.java @@ -0,0 +1,335 @@ +/* + * 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.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 + * + * @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); + } + }); + } + + /** + * @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/EnforceClassificationTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/EnforceClassificationTest.java new file mode 100644 index 0000000000..870e3086cb --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/EnforceClassificationTest.java @@ -0,0 +1,99 @@ +/* + * 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 org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase; + +/** + * 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); +// } +// }); + } +} 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 new file mode 100644 index 0000000000..29fb0fd92a --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RecordBrowseClassificationEnforcementTest.java @@ -0,0 +1,326 @@ +/* + * 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_ADMIN; +import static org.alfresco.util.GUID.generate; + +import java.util.List; + +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 RecordBrowseClassificationEnforcementTest extends BrowseClassificationEnforcementTestBase +{ + 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 browse the file plan as admin + * Then I will see both documents + * + * When I browse the file plan 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 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, generate()); + record2 = utils.createRecord(folder, 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 = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); + } + + /** + * @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()); + + List records = newArrayList(record1, record2); + assertTrue(records.contains(resultsForAdmin.get(0).getChildRef())); + assertTrue(records.contains(resultsForAdmin.get(1).getChildRef())); + + return null; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(1, resultsForTestUser.size()); + assertEquals(record2, resultsForTestUser.get(0).getChildRef()); + + 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 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 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() + */ + @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, 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); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + resultsForAdmin = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); + } + + /** + * @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()); + + 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; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(2, resultsForTestUser.size()); + + List records = newArrayList(record2, record3); + assertTrue(records.contains(resultsForTestUser.get(0).getChildRef())); + assertTrue(records.contains(resultsForTestUser.get(1).getChildRef())); + + 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 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 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() + */ + @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, 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); + } + + /** + * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase.BehaviourDrivenTest#when() + */ + @Override + public void when() throws Exception + { + resultsForAdmin = browseAsAdmin(folder); + resultsForTestUser = browseAsTestUser(folder); + } + + /** + * @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()); + + 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; + } + }); + + doTestInTransaction(new Test() + { + @Override + public Void run() + { + assertNotNull(resultsForTestUser); + assertEquals(3, resultsForTestUser.size()); + + 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; + } + }, testUser); + } + }); + } +} 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/RelationshipClassificationEnforcementTest.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RelationshipClassificationEnforcementTest.java new file mode 100644 index 0000000000..f852c78172 --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/RelationshipClassificationEnforcementTest.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.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.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; + +/** + * Enforcement of classification for records with relationship + * + * @author Tuna Aksoy + * @since 3.0 + */ +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 testRelationshipClassification() + { + /** + * 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); + } + }); + } +} 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(); + } +} 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..458528b61c --- /dev/null +++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/integration/classification/interceptor/SearchClassificationEnforcementTestBase.java @@ -0,0 +1,64 @@ +/* + * 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.NodeRef; + +/** + * Base class for classification enforcement tests for the search action + * + * @author Tuna Aksoy + * @since 3.0 + */ +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 abstract List search(String searchQuery); + + private List search(String searchQuery, String userName) + { + return doTestInTransaction(new Test>() + { + @Override + public List run() + { + return search(searchQuery); + } + }, userName); + } + + protected List searchAsAdmin(String searchQuery) + { + return search(searchQuery, getAdminUserName()); + } + + protected List searchAsTestUser(String searchQuery) + { + return search(searchQuery, testUser); + } +} 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 012db1a363..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 @@ -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 String user; 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,14 @@ 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(); + user = generate(); + createPerson(user); + return null; } }, AuthenticationUtil.getSystemUserName()); @@ -105,37 +96,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 @@ -192,7 +164,7 @@ public class RecordsManagementSearchServiceImplTest extends BaseRMTestCase return null; } - }, USER1); + }, user); // Get searches (as admin user) doTestInTransaction(new Test() @@ -251,7 +223,7 @@ public class RecordsManagementSearchServiceImplTest extends BaseRMTestCase return null; } - }, USER1); + }, user); // Update search (as admin user) doTestInTransaction(new Test() 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)); + } +} 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 new file mode 100644 index 0000000000..c8ddc99bd7 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/NodeRefPostMethodInvocationProcessorUnitTest.java @@ -0,0 +1,93 @@ +/* + * 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.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 + public void testProcessingNonExistingNode() + { + NodeRef nodeRef = new NodeRef(generate() + "://" + generate() + "/"); + + 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(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(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(mockedDictionaryService.isSubClass(mockedNodeService.getType(nodeRef), TYPE_CONTENT)).thenReturn(true); + when(mockedContentClassificationService.hasClearance(nodeRef)).thenReturn(false); + + assertEquals(null, nodeRefPostMethodInvocationProcessor.process(nodeRef)); + } + + @Test + public void testProcessingNull() + { + 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/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..7718b2e492 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/classification/interceptor/processor/QueryEngineResultsPostMethodInvocationProcessorUnitTest.java @@ -0,0 +1,91 @@ +/* + * 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 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}. + * + * @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.getProcessor(Mockito.any())).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()); + } +} 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()); + } +}