RM-2123 Create a new service for content classification.

Move methods to do with content from the ClassificationService and the
SecurityClearanceService into the ContentClassificationService.

Remove the dependency of SecurityClearanceService on ClassificationService
which will allow us to reverse this dependency in the next commit.  This is
needed in order to filter classifications by the current user's clearance.
Nb. This included adding a method in the SecurityClearanceService called
isClearedForClassification, which looks quite similar to a new API Roy
created hasClearance (see ContentClassificationService).  In the future we
should look to see if we can consolidate these.

Remove dependency of ClassificationServiceBootstrap on the services, so that
it can be passed into them. This allows us to provide access to the POJO
managers in the services (this is made harder as the POJO managers aren't
Spring beans).  In order to initialise these objects, change the POJO
managers to use setters rather than constructor arguments. This allows us
to store a reference to the manager before the data has been loaded.

Move the attribute service keys for classification levels and reasons into
the ClassifiedContentModel.

Expect NO_CLEARANCE to be passed into the ClearanceLevelManager, as
otherwise we have to have logic to exclude it (see initialise in the old
SecurityClearanceService) and then more logic to include it again (see the
old constructor for ClearanceLevelManager).

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@104375 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Tom Page
2015-05-18 15:03:57 +00:00
parent 5c66e55735
commit 24780dc472
26 changed files with 1326 additions and 978 deletions

View File

@@ -29,7 +29,7 @@ import org.junit.Test;
/**
* Unit tests for the {@link ClassificationLevelManager}.
*
*
* @author tpage
*/
public class ClassificationLevelManagerUnitTest
@@ -43,7 +43,8 @@ public class ClassificationLevelManagerUnitTest
@Before public void setup()
{
classificationLevelManager = new ClassificationLevelManager(LEVELS);
classificationLevelManager = new ClassificationLevelManager();
classificationLevelManager.setClassificationLevels(LEVELS);
}
@Test public void findClassificationById_found()

View File

@@ -29,7 +29,7 @@ import org.junit.Test;
/**
* Unit tests for the {@link ClassificationReasonManager}.
*
*
* @author tpage
*/
public class ClassificationReasonManagerUnitTest
@@ -43,7 +43,8 @@ public class ClassificationReasonManagerUnitTest
@Before public void setup()
{
classificationReasonManager = new ClassificationReasonManager(REASONS);
classificationReasonManager = new ClassificationReasonManager();
classificationReasonManager.setClassificationReasons(REASONS);
}
@Test public void findClassificationById_found()

View File

@@ -0,0 +1,236 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.classification;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import com.google.common.collect.ImmutableList;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.MissingConfiguration;
import org.alfresco.module.org_alfresco_module_rm.test.util.MockAuthenticationUtilHelper;
import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
import org.alfresco.service.cmr.attributes.AttributeService;
import org.apache.log4j.Appender;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
* Unit tests for the {@link ClassificationServiceBootstrap}.
*
* @author tpage
*/
public class ClassificationServiceBootstrapUnitTest
{
private static final List<ClassificationLevel> DEFAULT_CLASSIFICATION_LEVELS = asLevelList("Top Secret", "rm.classification.topSecret",
"Secret", "rm.classification.secret",
"Confidential", "rm.classification.confidential",
"No Clearance", "rm.classification.noClearance");
private static final List<ClassificationLevel> ALT_CLASSIFICATION_LEVELS = asLevelList("Board", "B",
"Executive Management", "EM",
"Employee", "E",
"Public", "P");
private static final List<ClassificationReason> PLACEHOLDER_CLASSIFICATION_REASONS = asList(new ClassificationReason("id1", "label1"),
new ClassificationReason("id2", "label2"));
private static final List<ClassificationReason> ALTERNATIVE_CLASSIFICATION_REASONS = asList(new ClassificationReason("id8", "label8"),
new ClassificationReason("id9", "label9"));
/**
* A convenience method for turning lists of level id Strings into lists
* of {@code ClassificationLevel} objects.
*
* @param idsAndLabels A varargs/array of Strings like so: [ id0, label0, id1, label1... ]
* @throws IllegalArgumentException if {@code idsAndLabels} has a non-even length.
*/
public static List<ClassificationLevel> asLevelList(String ... idsAndLabels)
{
if (idsAndLabels.length % 2 != 0)
{
throw new IllegalArgumentException(String.format("Cannot create %s objects with %d args.",
ClassificationLevel.class.getSimpleName(), idsAndLabels.length));
}
final List<ClassificationLevel> levels = new ArrayList<>(idsAndLabels.length / 2);
for (int i = 0; i < idsAndLabels.length; i += 2)
{
levels.add(new ClassificationLevel(idsAndLabels[i], idsAndLabels[i+1]));
}
return levels;
}
@InjectMocks ClassificationServiceBootstrap classificationServiceBootstrap;
@Mock ClassificationServiceDAO mockClassificationServiceDAO;
@Mock AttributeService mockAttributeService;
@Mock AuthenticationUtil mockAuthenticationUtil;
/** Using a mock appender in the class logger so that we can verify some of the logging requirements. */
@Mock Appender mockAppender;
@Captor ArgumentCaptor<LoggingEvent> loggingEventCaptor;
@Before public void setUp()
{
MockitoAnnotations.initMocks(this);
MockAuthenticationUtilHelper.setup(mockAuthenticationUtil);
}
@Test public void defaultLevelsConfigurationVanillaSystem()
{
when(mockClassificationServiceDAO.getConfiguredLevels()).thenReturn(DEFAULT_CLASSIFICATION_LEVELS);
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString())).thenReturn(null);
classificationServiceBootstrap.initConfiguredClassificationLevels();
verify(mockAttributeService).setAttribute(eq((Serializable) DEFAULT_CLASSIFICATION_LEVELS),
anyString(), anyString(), anyString());
}
@Test public void alternativeLevelsConfigurationPreviouslyStartedSystem()
{
when(mockClassificationServiceDAO.getConfiguredLevels()).thenReturn(ALT_CLASSIFICATION_LEVELS);
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString()))
.thenReturn((Serializable) DEFAULT_CLASSIFICATION_LEVELS);
classificationServiceBootstrap.initConfiguredClassificationLevels();
verify(mockAttributeService).setAttribute(eq((Serializable) ALT_CLASSIFICATION_LEVELS),
anyString(), anyString(), anyString());
}
@Test (expected=MissingConfiguration.class)
public void missingLevelsConfigurationVanillaSystemShouldFail() throws Exception
{
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString())).thenReturn(null);
classificationServiceBootstrap.initConfiguredClassificationLevels();
}
@Test public void pristineSystemShouldBootstrapReasonsConfiguration()
{
// There are no classification reasons stored in the AttributeService.
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString())).thenReturn(null);
// We'll use a small set of placeholder classification reasons.
when(mockClassificationServiceDAO.getConfiguredReasons()).thenReturn(PLACEHOLDER_CLASSIFICATION_REASONS);
classificationServiceBootstrap.initConfiguredClassificationReasons();
verify(mockAttributeService).setAttribute(eq((Serializable)PLACEHOLDER_CLASSIFICATION_REASONS),
anyString(), anyString(), anyString());
}
@Test public void checkAttributesNotTouchedIfConfiguredReasonsHaveNotChanged()
{
// The classification reasons stored are the same values that are found on the classpath.
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString())).thenReturn((Serializable)PLACEHOLDER_CLASSIFICATION_REASONS);
when(mockClassificationServiceDAO.getConfiguredReasons()).thenReturn(PLACEHOLDER_CLASSIFICATION_REASONS);
classificationServiceBootstrap.initConfiguredClassificationReasons();
verify(mockAttributeService, never()).setAttribute(any(Serializable.class),
anyString(), anyString(), anyString());
}
/**
* Check that if the reasons supplied on the classpath differ from those already persisted then a warning is logged
* and no change is made to the persisted reasons.
* <p>
* This test uses the underlying log4j implementation to insert a mock Appender, and tests this for the warning
* message. If the underlying logging framework is changed then this unit test will fail, and it may not be
* possible to/worth fixing.
*/
@Test public void previouslyStartedSystemShouldWarnIfConfiguredReasonsHaveChanged()
{
// The classification reasons stored are different from those found on the classpath.
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString())).thenReturn(
(Serializable) PLACEHOLDER_CLASSIFICATION_REASONS);
when(mockClassificationServiceDAO.getConfiguredReasons()).thenReturn(ALTERNATIVE_CLASSIFICATION_REASONS);
// Put the mock Appender into the log4j logger and allow warning messages to be received.
org.apache.log4j.Logger log4jLogger = org.apache.log4j.Logger.getLogger(ClassificationServiceBootstrap.class);
log4jLogger.addAppender(mockAppender);
Level normalLevel = log4jLogger.getLevel();
log4jLogger.setLevel(Level.WARN);
// Call the method under test.
classificationServiceBootstrap.initConfiguredClassificationReasons();
// Reset the logging level for other tests.
log4jLogger.setLevel(normalLevel);
// Check the persisted values weren't changed.
verify(mockAttributeService, never()).setAttribute(any(Serializable.class),
anyString(), anyString(), anyString());
// Check that the warning message was logged.
verify(mockAppender).doAppend(loggingEventCaptor.capture());
List<LoggingEvent> loggingEvents = loggingEventCaptor.getAllValues();
Stream<String> messages = loggingEvents.stream().map(event -> event.getRenderedMessage());
String expectedMessage = "Classification reasons configured in classpath do not match those stored in Alfresco. Alfresco will use the unchanged values stored in the database.";
assertTrue("Warning message not found in log.", messages.anyMatch(message -> message == expectedMessage));
}
@Test(expected = MissingConfiguration.class)
public void noReasonsFoundCausesException()
{
when(mockAttributeService.getAttribute(anyString(), anyString(), anyString()))
.thenReturn((Serializable) null);
when(mockClassificationServiceDAO.getConfiguredReasons()).thenReturn(null);
classificationServiceBootstrap.initConfiguredClassificationReasons();
}
/**
* Check that the initialise method creates a clearance level corresponding to each classification level and that
* the display label for the lowest clearance level is "No Clearance" (rather than "Unclassified").
*/
@Test public void initConfiguredClearanceLevels()
{
ClassificationLevel topSecret = new ClassificationLevel("1", "TopSecret");
ClassificationLevel secret = new ClassificationLevel("2", "Secret");
ImmutableList<ClassificationLevel> classificationLevels = ImmutableList.of(topSecret, secret, ClassificationLevelManager.UNCLASSIFIED);
// Call the method under test.
classificationServiceBootstrap.initConfiguredClearanceLevels(classificationLevels);
List<ClearanceLevel> clearanceLevels = classificationServiceBootstrap.getClearanceLevelManager().getClearanceLevels();
assertEquals("There should be one clearance level for each classification level.", classificationLevels.size(), clearanceLevels.size());
assertEquals("TopSecret", clearanceLevels.get(0).getDisplayLabel());
assertEquals("Secret", clearanceLevels.get(1).getDisplayLabel());
assertEquals("rm.classification.noClearance", clearanceLevels.get(2).getDisplayLabel());
}
}

View File

@@ -18,45 +18,21 @@
*/
package org.alfresco.module.org_alfresco_module_rm.classification;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock.generateNodeRef;
import static org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock.generateText;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.InvalidNode;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.LevelIdNotFound;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.MissingConfiguration;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.ReasonIdNotFound;
import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel;
import org.alfresco.module.org_alfresco_module_rm.test.util.ExceptionUtils;
import org.alfresco.module.org_alfresco_module_rm.test.util.MockAuthenticationUtilHelper;
import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
import org.alfresco.service.cmr.attributes.AttributeService;
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.namespace.QName;
import org.apache.log4j.Appender;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -65,8 +41,6 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import com.google.common.collect.Sets;
/**
* Unit tests for {@link ClassificationServiceImpl}.
*
@@ -79,18 +53,7 @@ public class ClassificationServiceImplUnitTest
"Secret", "rm.classification.secret",
"Confidential", "rm.classification.confidential",
"No Clearance", "rm.classification.noClearance");
private static final List<ClassificationLevel> ALT_CLASSIFICATION_LEVELS = asLevelList("Board", "B",
"Executive Management", "EM",
"Employee", "E",
"Public", "P");
private static final List<ClassificationReason> PLACEHOLDER_CLASSIFICATION_REASONS = asList(new ClassificationReason("id1", "label1"),
new ClassificationReason("id2", "label2"));
private static final List<ClassificationReason> ALTERNATIVE_CLASSIFICATION_REASONS = asList(new ClassificationReason("id8", "label8"),
new ClassificationReason("id9", "label9"));
private static final String CLASSIFICATION_LEVEL_ID = "classificationLevelId";
private static final ClassificationLevel CLASSIFICATION_LEVEL = new ClassificationLevel(CLASSIFICATION_LEVEL_ID, generateText());
/**
* A convenience method for turning lists of level id Strings into lists
* of {@code ClassificationLevel} objects.
@@ -117,128 +80,15 @@ public class ClassificationServiceImplUnitTest
@InjectMocks private ClassificationServiceImpl classificationServiceImpl;
@Mock private AttributeService mockedAttributeService;
@Mock private AuthenticationUtil mockedAuthenticationUtil;
@Mock private ClassificationServiceDAO mockClassificationServiceDAO;
@Mock private NodeService mockNodeService;
@Mock private DictionaryService mockDictionaryService;
/** Using a mock appender in the class logger so that we can verify some of the logging requirements. */
@Mock private Appender mockAppender;
@Mock private ClassificationLevelManager mockLevelManager;
@Mock private ClassificationReasonManager mockReasonManager;
@Captor private ArgumentCaptor<LoggingEvent> loggingEventCaptor;
@Captor private ArgumentCaptor<Map<QName, Serializable>> propertiesCaptor;
@Before public void setUp()
{
MockitoAnnotations.initMocks(this);
MockAuthenticationUtilHelper.setup(mockedAuthenticationUtil);
}
@Test public void defaultLevelsConfigurationVanillaSystem()
{
when(mockClassificationServiceDAO.getConfiguredLevels()).thenReturn(DEFAULT_CLASSIFICATION_LEVELS);
when(mockedAttributeService.getAttribute(anyString(), anyString(), anyString())).thenReturn(null);
classificationServiceImpl.initConfiguredClassificationLevels();
verify(mockedAttributeService).setAttribute(eq((Serializable) DEFAULT_CLASSIFICATION_LEVELS),
anyString(), anyString(), anyString());
}
@Test public void alternativeLevelsConfigurationPreviouslyStartedSystem()
{
when(mockClassificationServiceDAO.getConfiguredLevels()).thenReturn(ALT_CLASSIFICATION_LEVELS);
when(mockedAttributeService.getAttribute(anyString(), anyString(), anyString()))
.thenReturn((Serializable) DEFAULT_CLASSIFICATION_LEVELS);
classificationServiceImpl.initConfiguredClassificationLevels();
verify(mockedAttributeService).setAttribute(eq((Serializable) ALT_CLASSIFICATION_LEVELS),
anyString(), anyString(), anyString());
}
@Test (expected=MissingConfiguration.class)
public void missingLevelsConfigurationVanillaSystemShouldFail() throws Exception
{
when(mockedAttributeService.getAttribute(anyString(), anyString(), anyString())).thenReturn(null);
classificationServiceImpl.initConfiguredClassificationLevels();
}
@Test public void pristineSystemShouldBootstrapReasonsConfiguration()
{
// There are no classification reasons stored in the AttributeService.
when(mockedAttributeService.getAttribute(anyString(), anyString(), anyString())).thenReturn(null);
// We'll use a small set of placeholder classification reasons.
when(mockClassificationServiceDAO.getConfiguredReasons()).thenReturn(PLACEHOLDER_CLASSIFICATION_REASONS);
classificationServiceImpl.initConfiguredClassificationReasons();
verify(mockedAttributeService).setAttribute(eq((Serializable)PLACEHOLDER_CLASSIFICATION_REASONS),
anyString(), anyString(), anyString());
}
@Test public void checkAttributesNotTouchedIfConfiguredReasonsHaveNotChanged()
{
// The classification reasons stored are the same values that are found on the classpath.
when(mockedAttributeService.getAttribute(anyString(), anyString(), anyString())).thenReturn((Serializable)PLACEHOLDER_CLASSIFICATION_REASONS);
when(mockClassificationServiceDAO.getConfiguredReasons()).thenReturn(PLACEHOLDER_CLASSIFICATION_REASONS);
classificationServiceImpl.initConfiguredClassificationReasons();
verify(mockedAttributeService, never()).setAttribute(any(Serializable.class),
anyString(), anyString(), anyString());
}
/**
* Check that if the reasons supplied on the classpath differ from those already persisted then a warning is logged
* and no change is made to the persisted reasons.
* <p>
* This test uses the underlying log4j implementation to insert a mock Appender, and tests this for the warning
* message. If the underlying logging framework is changed then this unit test will fail, and it may not be
* possible to/worth fixing.
*/
@Test public void previouslyStartedSystemShouldWarnIfConfiguredReasonsHaveChanged()
{
// The classification reasons stored are different from those found on the classpath.
when(mockedAttributeService.getAttribute(anyString(), anyString(), anyString())).thenReturn(
(Serializable) PLACEHOLDER_CLASSIFICATION_REASONS);
when(mockClassificationServiceDAO.getConfiguredReasons()).thenReturn(ALTERNATIVE_CLASSIFICATION_REASONS);
// Put the mock Appender into the log4j logger and allow warning messages to be received.
org.apache.log4j.Logger log4jLogger = org.apache.log4j.Logger.getLogger(ClassificationServiceImpl.class);
log4jLogger.addAppender(mockAppender);
Level normalLevel = log4jLogger.getLevel();
log4jLogger.setLevel(Level.WARN);
// Call the method under test.
classificationServiceImpl.initConfiguredClassificationReasons();
// Reset the logging level for other tests.
log4jLogger.setLevel(normalLevel);
// Check the persisted values weren't changed.
verify(mockedAttributeService, never()).setAttribute(any(Serializable.class),
anyString(), anyString(), anyString());
// Check that the warning message was logged.
verify(mockAppender).doAppend(loggingEventCaptor.capture());
List<LoggingEvent> loggingEvents = loggingEventCaptor.getAllValues();
Stream<String> messages = loggingEvents.stream().map(event -> event.getRenderedMessage());
String expectedMessage = "Classification reasons configured in classpath do not match those stored in Alfresco. Alfresco will use the unchanged values stored in the database.";
assertTrue("Warning message not found in log.", messages.anyMatch(message -> message == expectedMessage));
}
@Test(expected = MissingConfiguration.class)
public void noReasonsFoundCausesException()
{
when(mockedAttributeService.getAttribute(anyString(), anyString(), anyString()))
.thenReturn((Serializable) null);
when(mockClassificationServiceDAO.getConfiguredReasons()).thenReturn(null);
classificationServiceImpl.initConfiguredClassificationReasons();
}
/**
@@ -271,69 +121,6 @@ public class ClassificationServiceImplUnitTest
assertEquals("Expected an empty list when the target level is not found.", 0, actual.size());
}
/** Classify a piece of content with a couple of reasons and check the NodeService is called correctly. */
@Test public void classifyContent_success()
{
// Create a level and two reasons.
ClassificationLevel level = new ClassificationLevel("levelId1", "displayLabelKey");
ClassificationReason reason1 = new ClassificationReason("reasonId1", "displayLabelKey1");
ClassificationReason reason2 = new ClassificationReason("reasonId2", "displayLabelKey2");
// Set up the managers to return these objects when the ids are provided.
when(mockLevelManager.findLevelById("levelId1")).thenReturn(level);
when(mockReasonManager.findReasonById("reasonId1")).thenReturn(reason1);
when(mockReasonManager.findReasonById("reasonId2")).thenReturn(reason2);
// Create a content node.
NodeRef content = new NodeRef("fake://content/");
when(mockDictionaryService.isSubClass(mockNodeService.getType(content), ContentModel.TYPE_CONTENT)).thenReturn(true);
when(mockNodeService.hasAspect(content, ClassifiedContentModel.ASPECT_CLASSIFIED)).thenReturn(false);
// Call the method under test.
classificationServiceImpl.classifyContent("levelId1", "classificationAuthority",
Sets.newHashSet("reasonId1", "reasonId2"), content);
verify(mockNodeService).addAspect(eq(content), eq(ClassifiedContentModel.ASPECT_CLASSIFIED),
propertiesCaptor.capture());
// Check the properties that were received.
Map<QName, Serializable> properties = propertiesCaptor.getValue();
HashSet<QName> expectedPropertyKeys = Sets.newHashSet(ClassifiedContentModel.PROP_INITIAL_CLASSIFICATION,
ClassifiedContentModel.PROP_CURRENT_CLASSIFICATION,
ClassifiedContentModel.PROP_CLASSIFICATION_AUTHORITY,
ClassifiedContentModel.PROP_CLASSIFICATION_REASONS);
assertEquals("Aspect created with unexpected set of keys.", expectedPropertyKeys, properties.keySet());
assertEquals("Unexpected initial classification.", level.getId(), properties.get(ClassifiedContentModel.PROP_INITIAL_CLASSIFICATION));
assertEquals("Unexpected current classification.", level.getId(), properties.get(ClassifiedContentModel.PROP_CURRENT_CLASSIFICATION));
assertEquals("Unexpected authority.", "classificationAuthority", properties.get(ClassifiedContentModel.PROP_CLASSIFICATION_AUTHORITY));
Set<String> expectedReasonIds = Sets.newHashSet("reasonId1", "reasonId2");
assertEquals("Unexpected set of reasons.", expectedReasonIds, properties.get(ClassifiedContentModel.PROP_CLASSIFICATION_REASONS));
}
/** Classify a folder using the <code>classifyContent</code> method and check that an exception is raised. */
@Test(expected = InvalidNode.class)
public void classifyContent_notContent()
{
// Create a folder node.
NodeRef notAPieceOfContent = new NodeRef("not://a/piece/of/content/");
when(mockNodeService.getType(notAPieceOfContent)).thenReturn(ContentModel.TYPE_FOLDER);
// Call the method under test.
classificationServiceImpl.classifyContent("levelId1", "classificationAuthority",
Sets.newHashSet("reasonId1", "reasonId2"), notAPieceOfContent);
}
/** Classify a piece of content that has already been classified. */
@Test(expected = UnsupportedOperationException.class)
public void classifyContent_alreadyClassified()
{
// Create a classified piece of content.
NodeRef classifiedContent = new NodeRef("classified://content/");
when(mockDictionaryService.isSubClass(mockNodeService.getType(classifiedContent), ContentModel.TYPE_CONTENT)).thenReturn(true);
when(mockNodeService.hasAspect(classifiedContent, ClassifiedContentModel.ASPECT_CLASSIFIED)).thenReturn(true);
// Call the method under test.
classificationServiceImpl.classifyContent("levelId1", "classificationAuthority",
Sets.newHashSet("reasonId1", "reasonId2"), classifiedContent);
}
@Test
public void getClassificationLevelById()
{
@@ -369,48 +156,4 @@ public class ClassificationServiceImplUnitTest
doThrow(new ReasonIdNotFound("Id not found!")).when(mockReasonManager).findReasonById(classificationReasonId);
classificationServiceImpl.getClassificationReasonById(classificationReasonId);
}
/**
* Given that a node does not have the classify aspect applied
* When I ask for the nodes classification
* Then 'Unclassified' is returned
*/
@Test
public void getCurrentClassificationWithoutAspectApplied()
{
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockNodeService.hasAspect(nodeRef, ClassifiedContentModel.ASPECT_CLASSIFIED))
.thenReturn(false);
ClassificationLevel classificationLevel = classificationServiceImpl.getCurrentClassification(nodeRef);
assertEquals(ClassificationLevelManager.UNCLASSIFIED, classificationLevel);
verify(mockNodeService).hasAspect(nodeRef, ClassifiedContentModel.ASPECT_CLASSIFIED);
verifyNoMoreInteractions(mockNodeService);
}
/**
* Given that a node is classified
* When I ask for the node classification
* Then I get the correct classificationlevel
*/
@Test
public void getCurrentClassification()
{
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockNodeService.hasAspect(nodeRef, ClassifiedContentModel.ASPECT_CLASSIFIED))
.thenReturn(true);
when(mockNodeService.getProperty(nodeRef, ClassifiedContentModel.PROP_CURRENT_CLASSIFICATION))
.thenReturn(CLASSIFICATION_LEVEL_ID);
when(mockLevelManager.findLevelById(CLASSIFICATION_LEVEL_ID))
.thenReturn(CLASSIFICATION_LEVEL);
ClassificationLevel classificationLevel = classificationServiceImpl.getCurrentClassification(nodeRef);
assertEquals(CLASSIFICATION_LEVEL, classificationLevel);
verify(mockNodeService).hasAspect(nodeRef, ClassifiedContentModel.ASPECT_CLASSIFIED);
verify(mockNodeService).getProperty(nodeRef, ClassifiedContentModel.PROP_CURRENT_CLASSIFICATION);
verify(mockLevelManager).findLevelById(CLASSIFICATION_LEVEL_ID);
verifyNoMoreInteractions(mockNodeService, mockLevelManager);
}
}

View File

@@ -47,8 +47,11 @@ public class ClearanceLevelManagerUnitTest
@Before
public void setup()
{
List<ClearanceLevel> clearanceLevels = ImmutableList.of(TOP_SECRET_CLEARANCE, SECRET_CLEARANCE);
clearanceLevelManager = new ClearanceLevelManager(clearanceLevels);
List<ClearanceLevel> clearanceLevels = ImmutableList.of(TOP_SECRET_CLEARANCE,
SECRET_CLEARANCE,
ClearanceLevelManager.NO_CLEARANCE);
clearanceLevelManager = new ClearanceLevelManager();
clearanceLevelManager.setClearanceLevels(clearanceLevels);
}
/** Check that the secret clearance can be found from the classification level id "S". */
@@ -65,16 +68,17 @@ public class ClearanceLevelManagerUnitTest
{
clearanceLevelManager.findLevelByClassificationLevelId("UNKNOWN ID");
}
/**
* Given that I have created a clearance level manager from a list of clearance levels
* Given that I have created a clearance level manager from a list of clearance levels (including the no clearance level)
* Then the no clearance level is available
*
* ...(and not added in the same way as for {@link ClassificationLevelManager#setClassificationLevels(List)}).
*/
@Test public void noClearanceLevel()
{
assertEquals(3, clearanceLevelManager.getClearanceLevels().size());
ClearanceLevel noClearance = clearanceLevelManager.findLevelByClassificationLevelId(ClassificationLevelManager.UNCLASSIFIED_ID);
assertEquals(ClearanceLevelManager.NO_CLEARANCE, noClearance);
assertEquals(ClassificationLevelManager.UNCLASSIFIED, noClearance.getHighestClassificationLevel());
assertEquals("The three clearance levels should be available.", 3, clearanceLevelManager.getClearanceLevels().size());
ClearanceLevel noClearance = clearanceLevelManager.findLevelByClassificationLevelId(ClassificationLevelManager.UNCLASSIFIED_ID);
assertEquals("'No clearance' could not be found.", ClearanceLevelManager.NO_CLEARANCE, noClearance);
}
}

View File

@@ -0,0 +1,313 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.classification;
import static org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock.generateNodeRef;
import static org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock.generateText;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceException.InvalidNode;
import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel;
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.cmr.security.PersonService.PersonInfo;
import org.alfresco.service.namespace.QName;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
* Unit tests for {@link ContentClassificationServiceImpl}.
*
* @author tpage
*/
public class ContentClassificationServiceImplUnitTest implements ClassifiedContentModel
{
private static final String CLASSIFICATION_LEVEL_ID = "classificationLevelId";
private static final ClassificationLevel CLASSIFICATION_LEVEL = new ClassificationLevel(CLASSIFICATION_LEVEL_ID, generateText());
@InjectMocks ContentClassificationServiceImpl contentClassificationServiceImpl;
@Mock ClassificationLevelManager mockLevelManager;
@Mock ClassificationReasonManager mockReasonManager;
@Mock NodeService mockNodeService;
@Mock DictionaryService mockDictionaryService;
@Mock SecurityClearanceService mockSecurityClearanceService;
@Captor ArgumentCaptor<Map<QName, Serializable>> propertiesCaptor;
@Before public void setUp()
{
MockitoAnnotations.initMocks(this);
}
/** Classify a piece of content with a couple of reasons and check the NodeService is called correctly. */
@Test public void classifyContent_success()
{
// Create a level and two reasons.
ClassificationLevel level = new ClassificationLevel("levelId1", "displayLabelKey");
ClassificationReason reason1 = new ClassificationReason("reasonId1", "displayLabelKey1");
ClassificationReason reason2 = new ClassificationReason("reasonId2", "displayLabelKey2");
// Set up the managers to return these objects when the ids are provided.
when(mockLevelManager.findLevelById("levelId1")).thenReturn(level);
when(mockReasonManager.findReasonById("reasonId1")).thenReturn(reason1);
when(mockReasonManager.findReasonById("reasonId2")).thenReturn(reason2);
// Create a content node.
NodeRef content = new NodeRef("fake://content/");
when(mockDictionaryService.isSubClass(mockNodeService.getType(content), ContentModel.TYPE_CONTENT)).thenReturn(true);
when(mockNodeService.hasAspect(content, ClassifiedContentModel.ASPECT_CLASSIFIED)).thenReturn(false);
// Call the method under test.
contentClassificationServiceImpl.classifyContent("levelId1", "classificationAuthority",
Sets.newHashSet("reasonId1", "reasonId2"), content);
verify(mockNodeService).addAspect(eq(content), eq(ClassifiedContentModel.ASPECT_CLASSIFIED),
propertiesCaptor.capture());
// Check the properties that were received.
Map<QName, Serializable> properties = propertiesCaptor.getValue();
HashSet<QName> expectedPropertyKeys = Sets.newHashSet(ClassifiedContentModel.PROP_INITIAL_CLASSIFICATION,
ClassifiedContentModel.PROP_CURRENT_CLASSIFICATION,
ClassifiedContentModel.PROP_CLASSIFICATION_AUTHORITY,
ClassifiedContentModel.PROP_CLASSIFICATION_REASONS);
assertEquals("Aspect created with unexpected set of keys.", expectedPropertyKeys, properties.keySet());
assertEquals("Unexpected initial classification.", level.getId(), properties.get(ClassifiedContentModel.PROP_INITIAL_CLASSIFICATION));
assertEquals("Unexpected current classification.", level.getId(), properties.get(ClassifiedContentModel.PROP_CURRENT_CLASSIFICATION));
assertEquals("Unexpected authority.", "classificationAuthority", properties.get(ClassifiedContentModel.PROP_CLASSIFICATION_AUTHORITY));
Set<String> expectedReasonIds = Sets.newHashSet("reasonId1", "reasonId2");
assertEquals("Unexpected set of reasons.", expectedReasonIds, properties.get(ClassifiedContentModel.PROP_CLASSIFICATION_REASONS));
}
/** Classify a folder using the <code>classifyContent</code> method and check that an exception is raised. */
@Test(expected = InvalidNode.class)
public void classifyContent_notContent()
{
// Create a folder node.
NodeRef notAPieceOfContent = new NodeRef("not://a/piece/of/content/");
when(mockNodeService.getType(notAPieceOfContent)).thenReturn(ContentModel.TYPE_FOLDER);
// Call the method under test.
contentClassificationServiceImpl.classifyContent("levelId1", "classificationAuthority",
Sets.newHashSet("reasonId1", "reasonId2"), notAPieceOfContent);
}
/** Classify a piece of content that has already been classified. */
@Test(expected = UnsupportedOperationException.class)
public void classifyContent_alreadyClassified()
{
// Create a classified piece of content.
NodeRef classifiedContent = new NodeRef("classified://content/");
when(mockDictionaryService.isSubClass(mockNodeService.getType(classifiedContent), ContentModel.TYPE_CONTENT)).thenReturn(true);
when(mockNodeService.hasAspect(classifiedContent, ClassifiedContentModel.ASPECT_CLASSIFIED)).thenReturn(true);
// Call the method under test.
contentClassificationServiceImpl.classifyContent("levelId1", "classificationAuthority",
Sets.newHashSet("reasonId1", "reasonId2"), classifiedContent);
}
/**
* Given that a node does not have the classify aspect applied
* When I ask for the nodes classification
* Then 'Unclassified' is returned
*/
@Test
public void getCurrentClassificationWithoutAspectApplied()
{
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockNodeService.hasAspect(nodeRef, ClassifiedContentModel.ASPECT_CLASSIFIED))
.thenReturn(false);
ClassificationLevel classificationLevel = contentClassificationServiceImpl.getCurrentClassification(nodeRef);
assertEquals(ClassificationLevelManager.UNCLASSIFIED, classificationLevel);
verify(mockNodeService).hasAspect(nodeRef, ClassifiedContentModel.ASPECT_CLASSIFIED);
verifyNoMoreInteractions(mockNodeService);
}
/**
* Given that a node is classified
* When I ask for the node classification
* Then I get the correct classificationlevel
*/
@Test
public void getCurrentClassification()
{
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockNodeService.hasAspect(nodeRef, ClassifiedContentModel.ASPECT_CLASSIFIED))
.thenReturn(true);
when(mockNodeService.getProperty(nodeRef, ClassifiedContentModel.PROP_CURRENT_CLASSIFICATION))
.thenReturn(CLASSIFICATION_LEVEL_ID);
when(mockLevelManager.findLevelById(CLASSIFICATION_LEVEL_ID))
.thenReturn(CLASSIFICATION_LEVEL);
ClassificationLevel classificationLevel = contentClassificationServiceImpl.getCurrentClassification(nodeRef);
assertEquals(CLASSIFICATION_LEVEL, classificationLevel);
verify(mockNodeService).hasAspect(nodeRef, ClassifiedContentModel.ASPECT_CLASSIFIED);
verify(mockNodeService).getProperty(nodeRef, ClassifiedContentModel.PROP_CURRENT_CLASSIFICATION);
verify(mockLevelManager).findLevelById(CLASSIFICATION_LEVEL_ID);
verifyNoMoreInteractions(mockNodeService, mockLevelManager);
}
/**
* Given that the node is unclassified
* When I ask if the current user has clearance
* Then true
*/
@Test public void clearedForUnclassifiedNode()
{
// Content is unclassified by default.
NodeRef nodeRef = generateNodeRef(mockNodeService);
assertTrue(contentClassificationServiceImpl.hasClearance(nodeRef));
}
/**
* Given that the node is classified
* And the user has no security clearance
* When I ask if the current user has clearance
* Then false
*/
@Test public void userWithNoClearanceIsntClearedOnClassifiedNode()
{
// assign test classification to node
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockNodeService.hasAspect(nodeRef, ASPECT_CLASSIFIED)).thenReturn(true);
String classificationLevelId = generateText();
when(mockNodeService.getProperty(nodeRef, PROP_CURRENT_CLASSIFICATION)).thenReturn(classificationLevelId);
ClassificationLevel classificationLevel = new ClassificationLevel(classificationLevelId, generateText());
when(mockLevelManager.findLevelById(classificationLevelId)).thenReturn(classificationLevel);
// create user with no clearance
SecurityClearance clearance = new SecurityClearance(mock(PersonInfo.class), ClearanceLevelManager.NO_CLEARANCE);
when(mockSecurityClearanceService.getUserSecurityClearance()).thenReturn(clearance);
assertFalse(contentClassificationServiceImpl.hasClearance(nodeRef));
}
/**
* Given that the node is classified
* And the user has clearance grater than the classification
* When I ask if the user has clearance
* Then true
*/
@Test public void classifiedNodeUserClearanceGreater()
{
// init classification levels
ClassificationLevel topSecret = new ClassificationLevel("TopSecret", generateText());
String secretId = "Secret";
ClassificationLevel secret = new ClassificationLevel(secretId, generateText());
ClassificationLevel confidential = new ClassificationLevel("Confidential", generateText());
List<ClassificationLevel> classificationLevels = Arrays.asList(topSecret, secret, confidential, ClassificationLevelManager.UNCLASSIFIED);
when(mockLevelManager.getClassificationLevels()).thenReturn(ImmutableList.copyOf(classificationLevels));
// set nodes classification
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockNodeService.hasAspect(nodeRef, ASPECT_CLASSIFIED)).thenReturn(true);
when(mockNodeService.getProperty(nodeRef, PROP_CURRENT_CLASSIFICATION)).thenReturn(secretId);
when(mockLevelManager.findLevelById(secretId)).thenReturn(secret);
// set users security clearance
ClearanceLevel topSecretClearance = new ClearanceLevel(topSecret, "Top Secret");
SecurityClearance clearance = new SecurityClearance(mock(PersonInfo.class), topSecretClearance);
when(mockSecurityClearanceService.getUserSecurityClearance()).thenReturn(clearance);
assertTrue(contentClassificationServiceImpl.hasClearance(nodeRef));
}
/**
* Given that the node is classified
* And the user has clearance equal to the the classification
* When I ask if the user has clearance
* Then true
*/
@Test public void classifiedNodeUserClearanceEqual()
{
// init classification levels
ClassificationLevel topSecret = new ClassificationLevel("TopSecret", generateText());
String secretId = "Secret";
ClassificationLevel secret = new ClassificationLevel(secretId, generateText());
ClassificationLevel confidential = new ClassificationLevel("Confidential", generateText());
List<ClassificationLevel> classificationLevels = Arrays.asList(topSecret, secret, confidential, ClassificationLevelManager.UNCLASSIFIED);
when(mockLevelManager.getClassificationLevels()).thenReturn(ImmutableList.copyOf(classificationLevels));
// set nodes classification
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockNodeService.hasAspect(nodeRef, ASPECT_CLASSIFIED)).thenReturn(true);
when(mockNodeService.getProperty(nodeRef, PROP_CURRENT_CLASSIFICATION)).thenReturn(secretId);
when(mockLevelManager.findLevelById(secretId)).thenReturn(secret);
// set users security clearance
ClearanceLevel secretClearance = new ClearanceLevel(secret, "Secret");
SecurityClearance clearance = new SecurityClearance(mock(PersonInfo.class), secretClearance);
when(mockSecurityClearanceService.getUserSecurityClearance()).thenReturn(clearance);
assertTrue(contentClassificationServiceImpl.hasClearance(nodeRef));
}
/**
* Given that the node is classified
* And the user has clearance less than the classification
* When I ask if the user has clearance
* Then true
*/
@Test public void classifiedNodeUserClearanceLess()
{
// init classification levels
ClassificationLevel topSecret = new ClassificationLevel("TopSecret", generateText());
String secretId = "Secret";
ClassificationLevel secret = new ClassificationLevel(secretId, generateText());
ClassificationLevel confidential = new ClassificationLevel("Confidential", generateText());
List<ClassificationLevel> classificationLevels = Arrays.asList(topSecret, secret, confidential, ClassificationLevelManager.UNCLASSIFIED);
when(mockLevelManager.getClassificationLevels()).thenReturn(ImmutableList.copyOf(classificationLevels));
// set nodes classification
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockNodeService.hasAspect(nodeRef, ASPECT_CLASSIFIED)).thenReturn(true);
when(mockNodeService.getProperty(nodeRef, PROP_CURRENT_CLASSIFICATION)).thenReturn(secretId);
when(mockLevelManager.findLevelById(secretId)).thenReturn(secret);
// set users security clearance
ClearanceLevel confidentialClearance = new ClearanceLevel(confidential, "Confidential");
SecurityClearance clearance = new SecurityClearance(mock(PersonInfo.class), confidentialClearance);
when(mockSecurityClearanceService.getUserSecurityClearance()).thenReturn(clearance);
assertFalse(contentClassificationServiceImpl.hasClearance(nodeRef));
}
}

View File

@@ -20,14 +20,15 @@ package org.alfresco.module.org_alfresco_module_rm.classification;
import static org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel.ASPECT_SECURITY_CLEARANCE;
import static org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel.PROP_CLEARANCE_LEVEL;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.alfresco.module.org_alfresco_module_rm.test.util.AlfMock.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -58,12 +59,13 @@ public class SecurityClearanceServiceImplUnitTest
{
@InjectMocks private SecurityClearanceServiceImpl securityClearanceServiceImpl;
@Mock private AuthenticationUtil mockedAuthenticationUtil;
@Mock private ClassificationService mockClassificationService;
@Mock private DictionaryService mockDictionaryService;
@Mock private NodeService mockNodeService;
@Mock private PersonService mockPersonService;
@Mock private ClearanceLevelManager mockClearanceLevelManager;
@Mock private AuthenticationUtil mockAuthenticationUtil;
@Mock private ClassificationLevelManager mockClassificationLevelManager;
@Mock private DictionaryService mockDictionaryService;
@Mock private NodeService mockNodeService;
@Mock private PersonService mockPersonService;
@Mock private ClassificationService mockClassificationService;
@Mock private ClearanceLevelManager mockClearanceLevelManager;
@Before public void setUp()
{
@@ -76,15 +78,15 @@ public class SecurityClearanceServiceImplUnitTest
final PersonInfo info = new PersonInfo(userNode, userName, firstName, lastName);
when(mockPersonService.getPerson(eq(userName), anyBoolean())).thenReturn(userNode);
when(mockPersonService.getPerson(eq(userNode))).thenReturn(info);
when(mockPersonService.getPerson(userNode)).thenReturn(info);
when(mockNodeService.hasAspect(eq(userNode), eq(ASPECT_SECURITY_CLEARANCE))).thenReturn(clearanceLevel != null);
when(mockNodeService.getProperty(eq(userNode), eq(PROP_CLEARANCE_LEVEL))).thenReturn(clearanceLevel);
when(mockNodeService.hasAspect(userNode, ASPECT_SECURITY_CLEARANCE)).thenReturn(clearanceLevel != null);
when(mockNodeService.getProperty(userNode, PROP_CLEARANCE_LEVEL)).thenReturn(clearanceLevel);
if (clearanceLevel != null)
{
final ClassificationLevel dummyValue = new ClassificationLevel(clearanceLevel, clearanceLevel);
when(mockClassificationService.getClassificationLevelById(eq(clearanceLevel))).thenReturn(dummyValue);
when(mockClassificationLevelManager.findLevelById(clearanceLevel)).thenReturn(dummyValue);
}
return info;
@@ -93,246 +95,115 @@ public class SecurityClearanceServiceImplUnitTest
@Test public void userWithNoClearanceGetsDefaultClearance()
{
final PersonInfo user1 = createMockPerson("user1", "User", "One", null);
MockAuthenticationUtilHelper.setup(mockedAuthenticationUtil, user1.getUserName());
MockAuthenticationUtilHelper.setup(mockAuthenticationUtil, user1.getUserName());
when(mockClassificationService.getUnclassifiedClassificationLevel())
.thenReturn(ClassificationLevelManager.UNCLASSIFIED);
.thenReturn(ClassificationLevelManager.UNCLASSIFIED);
when(mockClearanceLevelManager.findLevelByClassificationLevelId(ClassificationLevelManager.UNCLASSIFIED_ID))
.thenReturn(ClearanceLevelManager.NO_CLEARANCE);
.thenReturn(ClearanceLevelManager.NO_CLEARANCE);
final SecurityClearance clearance = securityClearanceServiceImpl.getUserSecurityClearance();
assertEquals(ClassificationLevelManager.UNCLASSIFIED, clearance.getClearanceLevel().getHighestClassificationLevel());
}
/** Check that a user can have their clearance set. */
/** Check that a user can have their clearance set by an authorised user. */
@Test public void setUserSecurityClearance_setClearance()
{
// Create the user.
// Create the clearance.
String topSecretId = "ClearanceId";
ClassificationLevel level = new ClassificationLevel(topSecretId, "TopSecretKey");
ClearanceLevel clearanceLevel = new ClearanceLevel(level, "TopSecretKey");
when(mockClearanceLevelManager.findLevelByClassificationLevelId(topSecretId)).thenReturn(clearanceLevel);
when(mockClassificationLevelManager.getClassificationLevels()).thenReturn(ImmutableList.of(level));
// Create the authorised user.
String authorisedUserName = "authorisedUser";
when(mockAuthenticationUtil.getFullyAuthenticatedUser()).thenReturn(authorisedUserName);
NodeRef authorisedPersonNode = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, authorisedUserName);
PersonInfo authorisedPersonInfo = new PersonInfo(authorisedPersonNode, authorisedUserName, "first", "last");
when(mockPersonService.getPerson(authorisedUserName, false)).thenReturn(authorisedPersonNode);
when(mockPersonService.getPerson(authorisedPersonNode)).thenReturn(authorisedPersonInfo);
// The authorised user is cleared to use this clearance.
when(mockNodeService.hasAspect(authorisedPersonNode, ASPECT_SECURITY_CLEARANCE)).thenReturn(true);
when(mockNodeService.getProperty(authorisedPersonNode, PROP_CLEARANCE_LEVEL)).thenReturn(topSecretId);
// Create the user who will have their clearance set.
String userName = "User 1";
NodeRef personNode = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, userName);
PersonInfo personInfo = new PersonInfo(personNode, userName, "user", "two");
PersonInfo personInfo = new PersonInfo(personNode, userName, "first", "last");
when(mockPersonService.getPerson(userName, false)).thenReturn(personNode);
when(mockPersonService.getPerson(personNode)).thenReturn(personInfo);
// Create the clearance.
String clearanceId = "ClearanceId";
ClassificationLevel level = new ClassificationLevel(clearanceId, "TopSecretKey");
when(mockClassificationService.getClassificationLevelById(clearanceId)).thenReturn(level);
ClearanceLevel clearanceLevel = new ClearanceLevel(level, "TopSecretKey");
when(mockClearanceLevelManager.findLevelByClassificationLevelId(clearanceId)).thenReturn(clearanceLevel);
// Once the user's clearance has been set then the node service is queried about it.
when(mockNodeService.hasAspect(personNode, ASPECT_SECURITY_CLEARANCE)).thenReturn(true);
when(mockNodeService.getProperty(personNode, PROP_CLEARANCE_LEVEL)).thenReturn(clearanceId);
when(mockNodeService.getProperty(personNode, PROP_CLEARANCE_LEVEL)).thenReturn(topSecretId);
// Call the method under test.
SecurityClearance securityClearance = securityClearanceServiceImpl.setUserSecurityClearance(userName, clearanceId);
SecurityClearance securityClearance = securityClearanceServiceImpl.setUserSecurityClearance(userName, topSecretId);
// Check the returned value.
assertEquals(personInfo, securityClearance.getPersonInfo());
assertEquals(clearanceLevel, securityClearance.getClearanceLevel());
verify(mockNodeService).setProperty(personNode, PROP_CLEARANCE_LEVEL, clearanceId);
// Check the value stored in the node service.
verify(mockNodeService).setProperty(personNode, PROP_CLEARANCE_LEVEL, topSecretId);
}
/**
* Check that a user cannot raise someone's clearance above their own. Here we check that an exception thrown by the
* classification service is passed through.
*/
/** Check that a user cannot raise someone else's clearance above their own. */
@Test(expected = LevelIdNotFound.class)
public void setUserSecurityClearance_insufficientClearance()
{
String userName = "User 1";
NodeRef personNode = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, userName);
when(mockPersonService.getPerson(userName, false)).thenReturn(personNode);
String clearanceId = "ClearanceId";
// If the user has insufficient clearance then they cannot access the level.
when(mockClassificationService.getClassificationLevelById(clearanceId)).thenThrow(new LevelIdNotFound(clearanceId));
// Create the "Top Secret" and "Confidential" clearances.
String topSecretId = "TopSecretClearanceId";
ClassificationLevel topSecret = new ClassificationLevel(topSecretId, "TopSecretKey");
ClearanceLevel topSecretClearance = new ClearanceLevel(topSecret, "TopSecretKey");
when(mockClearanceLevelManager.findLevelByClassificationLevelId(topSecretId)).thenReturn(topSecretClearance);
String confidentialId = "ConfidentialClearanceId";
ClassificationLevel confidential = new ClassificationLevel(confidentialId, "ConfidentialKey");
ClearanceLevel confidentialClearance = new ClearanceLevel(confidential, "ConfidentialKey");
when(mockClearanceLevelManager.findLevelByClassificationLevelId(confidentialId)).thenReturn(confidentialClearance);
when(mockClassificationLevelManager.getClassificationLevels()).thenReturn(ImmutableList.of(topSecret, confidential));
securityClearanceServiceImpl.setUserSecurityClearance(userName, clearanceId);
// Create the user attempting to use the API with "Confidential" clearance.
String userName = "unauthorisedUser";
when(mockAuthenticationUtil.getFullyAuthenticatedUser()).thenReturn(userName);
NodeRef personNode = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, userName);
PersonInfo personInfo = new PersonInfo(personNode, userName, "first", "last");
when(mockPersonService.getPerson(userName, false)).thenReturn(personNode);
when(mockPersonService.getPerson(personNode)).thenReturn(personInfo);
// The authorised user is cleared to use this clearance.
when(mockNodeService.hasAspect(personNode, ASPECT_SECURITY_CLEARANCE)).thenReturn(true);
when(mockNodeService.getProperty(personNode, PROP_CLEARANCE_LEVEL)).thenReturn(confidentialId);
// Create the user who will have their clearance set.
String targetUserName = "Target User";
NodeRef targetPersonNode = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, targetUserName);
PersonInfo targetPersonInfo = new PersonInfo(targetPersonNode, targetUserName, "first", "last");
when(mockPersonService.getPerson(targetUserName, false)).thenReturn(targetPersonNode);
when(mockPersonService.getPerson(targetPersonNode)).thenReturn(targetPersonInfo);
// Call the method under test and expect an exception.
securityClearanceServiceImpl.setUserSecurityClearance(targetUserName, topSecretId);
}
/**
* Check that the initialise method creates a clearance level corresponding to each classification level and that
* the display label for the lowest clearance level is "No Clearance" (rather than "Unclassified").
* Check that a user with no clearance is not cleared to use the "Secret" classification.
*/
@Test public void initialise()
@Test public void isClearedForClassification()
{
ClassificationLevel topSecret = new ClassificationLevel("1", "TopSecret");
ClassificationLevel secret = new ClassificationLevel("2", "Secret");
List<ClassificationLevel> classificationLevels = Arrays.asList(topSecret, secret, ClassificationLevelManager.UNCLASSIFIED);
when(mockClassificationService.getClassificationLevels()).thenReturn(classificationLevels );
ImmutableList<ClassificationLevel> classificationLevels = ImmutableList.of(topSecret, secret);
when(mockClassificationLevelManager.getClassificationLevels()).thenReturn(classificationLevels);
SecurityClearance clearance = new SecurityClearance(mock(PersonInfo.class), ClearanceLevelManager.NO_CLEARANCE);
// Call the method under test.
securityClearanceServiceImpl.initialise();
boolean result = securityClearanceServiceImpl.isClearedForClassification(clearance, "2");
List<ClearanceLevel> clearanceLevels = securityClearanceServiceImpl.getClearanceManager().getClearanceLevels();
assertEquals("There should be one clearance level for each classification level.", classificationLevels.size(), clearanceLevels.size());
assertEquals("TopSecret", clearanceLevels.get(0).getDisplayLabel());
assertEquals("Secret", clearanceLevels.get(1).getDisplayLabel());
assertEquals("rm.classification.noClearance", clearanceLevels.get(2).getDisplayLabel());
}
/**
* Given that the node is unclassified
* When I ask if the current user has clearance
* Then true
*/
@Test public void clearedForUnclassifiedNode()
{
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockClassificationService.getCurrentClassification(nodeRef))
.thenReturn(ClassificationLevelManager.UNCLASSIFIED);
assertTrue(securityClearanceServiceImpl.hasClearance(nodeRef));
}
/**
* Given that the node is classified
* And the user has no security clearance
* When I ask if the current user has clearance
* Then false
*/
@Test public void userWithNoClearanceIsntClearedOnClassifiedNode()
{
// assign test classification to node
String classificationLevelId = generateText();
ClassificationLevel classificationLevel = new ClassificationLevel(classificationLevelId, generateText());
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockClassificationService.getCurrentClassification(nodeRef))
.thenReturn(classificationLevel);
when(mockClearanceLevelManager.findLevelByClassificationLevelId(classificationLevelId))
.thenReturn(new ClearanceLevel(classificationLevel, generateText()));
// create user with no clearance
final PersonInfo user1 = createMockPerson(generateText(), generateText(), generateText(), null);
MockAuthenticationUtilHelper.setup(mockedAuthenticationUtil, user1.getUserName());
when(mockClassificationService.getUnclassifiedClassificationLevel())
.thenReturn(ClassificationLevelManager.UNCLASSIFIED);
when(mockClearanceLevelManager.findLevelByClassificationLevelId(ClassificationLevelManager.UNCLASSIFIED_ID))
.thenReturn(ClearanceLevelManager.NO_CLEARANCE);
assertFalse(securityClearanceServiceImpl.hasClearance(nodeRef));
}
/**
* Given that the node is classified
* And the user has clearance grater than the classification
* When I ask if the user has clearance
* Then true
*/
@Test public void classifiedNodeUserClearanceGreater()
{
// init classification levels
ClassificationLevel topSecret = new ClassificationLevel("TopSecret", generateText());
ClassificationLevel secret = new ClassificationLevel("Secret", generateText());
ClassificationLevel confidential = new ClassificationLevel("Confidential", generateText());
List<ClassificationLevel> classificationLevels = Arrays.asList(topSecret, secret, confidential, ClassificationLevelManager.UNCLASSIFIED);
when(mockClassificationService.getClassificationLevels()).thenReturn(classificationLevels);
// init classification levels
when(mockClearanceLevelManager.findLevelByClassificationLevelId("TopSecret"))
.thenReturn(new ClearanceLevel(topSecret, generateText()));
when(mockClearanceLevelManager.findLevelByClassificationLevelId("Secret"))
.thenReturn(new ClearanceLevel(secret, generateText()));
when(mockClearanceLevelManager.findLevelByClassificationLevelId("Confidential"))
.thenReturn(new ClearanceLevel(confidential, generateText()));
when(mockClearanceLevelManager.findLevelByClassificationLevelId(ClassificationLevelManager.UNCLASSIFIED_ID))
.thenReturn(ClearanceLevelManager.NO_CLEARANCE);
when(mockClassificationService.getUnclassifiedClassificationLevel())
.thenReturn(ClassificationLevelManager.UNCLASSIFIED);
// set nodes classification
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockClassificationService.getCurrentClassification(nodeRef))
.thenReturn(secret);
// set users security clearance
final PersonInfo user1 = createMockPerson(generateText(), generateText(), generateText(), "TopSecret");
MockAuthenticationUtilHelper.setup(mockedAuthenticationUtil, user1.getUserName());
assertTrue(securityClearanceServiceImpl.hasClearance(nodeRef));
}
/**
* Given that the node is classified
* And the user has clearance equal to the the classification
* When I ask if the user has clearance
* Then true
*/
@Test public void classifiedNodeUserClearanceEqual()
{
// init classification levels
ClassificationLevel topSecret = new ClassificationLevel("TopSecret", generateText());
ClassificationLevel secret = new ClassificationLevel("Secret", generateText());
ClassificationLevel confidential = new ClassificationLevel("Confidential", generateText());
List<ClassificationLevel> classificationLevels = Arrays.asList(topSecret, secret, confidential, ClassificationLevelManager.UNCLASSIFIED);
when(mockClassificationService.getClassificationLevels()).thenReturn(classificationLevels);
// init classification levels
when(mockClearanceLevelManager.findLevelByClassificationLevelId("TopSecret"))
.thenReturn(new ClearanceLevel(topSecret, generateText()));
when(mockClearanceLevelManager.findLevelByClassificationLevelId("Secret"))
.thenReturn(new ClearanceLevel(secret, generateText()));
when(mockClearanceLevelManager.findLevelByClassificationLevelId("Confidential"))
.thenReturn(new ClearanceLevel(confidential, generateText()));
when(mockClearanceLevelManager.findLevelByClassificationLevelId(ClassificationLevelManager.UNCLASSIFIED_ID))
.thenReturn(ClearanceLevelManager.NO_CLEARANCE);
when(mockClassificationService.getUnclassifiedClassificationLevel())
.thenReturn(ClassificationLevelManager.UNCLASSIFIED);
// set nodes classification
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockClassificationService.getCurrentClassification(nodeRef))
.thenReturn(secret);
// set users security clearance
final PersonInfo user1 = createMockPerson(generateText(), generateText(), generateText(), "Secret");
MockAuthenticationUtilHelper.setup(mockedAuthenticationUtil, user1.getUserName());
assertTrue(securityClearanceServiceImpl.hasClearance(nodeRef));
}
/**
* Given that the node is classified
* And the user has clearance less than the classification
* When I ask if the user has clearance
* Then true
*/
@Test public void classifiedNodeUserClearanceLess()
{
// init classification levels
ClassificationLevel topSecret = new ClassificationLevel("TopSecret", generateText());
ClassificationLevel secret = new ClassificationLevel("Secret", generateText());
ClassificationLevel confidential = new ClassificationLevel("Confidential", generateText());
List<ClassificationLevel> classificationLevels = Arrays.asList(topSecret, secret, confidential, ClassificationLevelManager.UNCLASSIFIED);
when(mockClassificationService.getClassificationLevels()).thenReturn(classificationLevels);
// init classification levels
when(mockClearanceLevelManager.findLevelByClassificationLevelId("TopSecret"))
.thenReturn(new ClearanceLevel(topSecret, generateText()));
when(mockClearanceLevelManager.findLevelByClassificationLevelId("Secret"))
.thenReturn(new ClearanceLevel(secret, generateText()));
when(mockClearanceLevelManager.findLevelByClassificationLevelId("Confidential"))
.thenReturn(new ClearanceLevel(confidential, generateText()));
when(mockClearanceLevelManager.findLevelByClassificationLevelId(ClassificationLevelManager.UNCLASSIFIED_ID))
.thenReturn(ClearanceLevelManager.NO_CLEARANCE);
when(mockClassificationService.getUnclassifiedClassificationLevel())
.thenReturn(ClassificationLevelManager.UNCLASSIFIED);
// set nodes classification
NodeRef nodeRef = generateNodeRef(mockNodeService);
when(mockClassificationService.getCurrentClassification(nodeRef))
.thenReturn(secret);
// set users security clearance
final PersonInfo user1 = createMockPerson(generateText(), generateText(), generateText(), "Confidential");
MockAuthenticationUtilHelper.setup(mockedAuthenticationUtil, user1.getUserName());
assertFalse(securityClearanceServiceImpl.hasClearance(nodeRef));
assertFalse("A user with no clearance should not be able to access the 'Secret' classification.", result);
}
/**

View File

@@ -34,7 +34,7 @@ import java.util.Map;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationLevelManager;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationReasonManager;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationService;
import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseWebScriptUnitTest;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -68,8 +68,8 @@ public class ClassifyContentPostUnitTest extends BaseWebScriptUnitTest
/** ClassifyContentPost webscript instance */
private @Spy @InjectMocks ClassifyContentPost webScript;
/** Mocked classification service */
private @Mock ClassificationService mockedClassificationService;
/** Mocked content classification service */
private @Mock ContentClassificationService mockedContentClassificationService;
/** Mocked classification level manager */
private @Mock ClassificationLevelManager mockedClassificationLevelManager;
@@ -116,7 +116,7 @@ public class ClassifyContentPostUnitTest extends BaseWebScriptUnitTest
assertEquals(getStringValueFromJSONObject(json, SUCCESS), Boolean.TRUE.toString());
// Verify that the classify content method was called
verify(mockedClassificationService, times(1)).classifyContent(LEVEL_ID, AUTHORITY, newHashSet(REASON1_ID, REASON2_ID), record);
verify(mockedContentClassificationService, times(1)).classifyContent(LEVEL_ID, AUTHORITY, newHashSet(REASON1_ID, REASON2_ID), record);
}
/**