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 d83ff155e3..1dcf24b9eb 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 @@ -96,4 +96,51 @@ + + + + + + + + + + + org.alfresco.module.org_alfresco_module_rm.classification.SecurityClearanceService + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + + org.alfresco.module.org_alfresco_module_rm.classification.SecurityClearanceService.getUserSecurityClearance=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.classification.SecurityClearanceService.getUsersSecurityClearance=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.classification.SecurityClearanceService.*=ACL_DENY + + + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/classifiedContentModel.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/classifiedContentModel.xml index b771569c64..372fb3e659 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/model/classifiedContentModel.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/model/classifiedContentModel.xml @@ -26,7 +26,8 @@ - + @@ -66,11 +67,31 @@ Classification Reasons - Holds the id's of classification reasons + Holds the ids of classification reasons d:text true + + + + + + Security Clearance + The security clearance for this user + d:text + true + true + false + NoClearance + + + + + + + \ No newline at end of file diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java index 553b165906..b2beb8b45f 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java @@ -67,6 +67,11 @@ public interface ClassificationService Set classificationReasonIds, NodeRef content) throws LevelIdNotFound, ReasonIdNotFound, InvalidNodeRefException, InvalidNode; + /** + * Gets the default {@link ClassificationLevel}, which will usually be the level with the lowest security clearance. + */ + ClassificationLevel getDefaultClassificationLevel(); + /** * Gets the classification level for the given classification level id * diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java index 075b298142..8deca04cb5 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java @@ -267,6 +267,12 @@ public class ClassificationServiceImpl extends ServiceBaseImpl nodeService.addAspect(content, ASPECT_CLASSIFIED, properties); } + @Override public ClassificationLevel getDefaultClassificationLevel() + { + List classificationLevels = getClassificationLevels(); + return classificationLevels.isEmpty() ? null : classificationLevels.get(classificationLevels.size() - 1); + } + /** * @see org.alfresco.module.org_alfresco_module_rm.classification.ClassificationService#getClassificationLevelById(java.lang.String) */ diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceService.java new file mode 100644 index 0000000000..0eb97b581d --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceService.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.module.org_alfresco_module_rm.classification; + +import org.alfresco.query.PagingRequest; +import org.alfresco.query.PagingResults; +import org.alfresco.service.cmr.security.NoSuchPersonException; +import org.alfresco.service.cmr.security.PersonService.PersonInfo; +import org.alfresco.util.Pair; + +/** + * This service offers access to users' security clearance levels. + * + * @author Neil Mc Erlean + * @since 3.0 + */ +public interface SecurityClearanceService +{ + /** + * Get the currently authenticated user's security clearance. + * + * @return a {@link PersonInfo}, {@link ClassificationLevel} pair for the currently authenticated user. + * @throws NoSuchPersonException if the current user's person node cannot be found. + */ + Pair getUserSecurityClearance(); + + /** + * Get users' security clearances. + * + * @param userNameFragment A username fragment which will be used to apply a 'starts with' query. + * @param sortAscending if @code true} returns data sorted in ascending order by username. + * @param req paging request definition. + * @return {@link PersonInfo}, {@link ClassificationLevel} pairs for the specified page of users. + */ + PagingResults> getUsersSecurityClearance(String userNameFragment, + boolean sortAscending, + PagingRequest req); +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java new file mode 100644 index 0000000000..9a240dfbbe --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/SecurityClearanceServiceImpl.java @@ -0,0 +1,108 @@ +/* + * 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; + +import static java.util.Arrays.asList; +import static org.alfresco.model.ContentModel.PROP_FIRSTNAME; +import static org.alfresco.model.ContentModel.PROP_LASTNAME; +import static org.alfresco.model.ContentModel.PROP_USERNAME; +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 org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; +import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl; +import org.alfresco.query.PagingRequest; +import org.alfresco.query.PagingResults; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.security.PersonService.PersonInfo; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * @author Neil Mc Erlean + * @since 3.0 + */ +public class SecurityClearanceServiceImpl extends ServiceBaseImpl implements SecurityClearanceService +{ + private ClassificationService classificationService; + private PersonService personService; + + public void setClassificationService(ClassificationService service) { this.classificationService = service; } + public void setPersonService (PersonService service) { this.personService = service; } + + public Pair getUserSecurityClearance() + { + final String currentUser = authenticationUtil.getFullyAuthenticatedUser(); + Objects.requireNonNull(currentUser, "Fully authenticated user is null, which is not allowed."); + + return getUserSecurityClearance(currentUser); + } + + private Pair getUserSecurityClearance(final String userName) + { + final NodeRef personNode = personService.getPerson(userName, false); + final PersonInfo personInfo = personService.getPerson(personNode); + + final ClassificationLevel classificationLevel; + + if (nodeService.hasAspect(personNode, ASPECT_SECURITY_CLEARANCE)) + { + final String clearanceLevel = (String)nodeService.getProperty(personNode, PROP_CLEARANCE_LEVEL); + // TODO Should we fall back to a default here or give an error? + classificationLevel = clearanceLevel == null ? classificationService.getDefaultClassificationLevel() : + classificationService.getClassificationLevelById(clearanceLevel); + } + else { classificationLevel = classificationService.getDefaultClassificationLevel(); } + + return new Pair<>(personInfo, classificationLevel); + } + + public PagingResults> getUsersSecurityClearance(String userNameFragment, + boolean sortAscending, + PagingRequest req) + { + final List filterProps = asList(PROP_USERNAME, PROP_FIRSTNAME, PROP_LASTNAME); + final List> sortProps = asList(new Pair<>(PROP_USERNAME, sortAscending)); + + final PagingResults p = personService.getPeople(userNameFragment, filterProps, sortProps, req); + + return new PagingResults>() + { + @Override public List> getPage() + { + List> pcPage= new ArrayList<>(p.getPage().size()); + for (PersonInfo pi : p.getPage()) + { + pcPage.add(getUserSecurityClearance(pi.getUserName())); + } + return pcPage; + } + + @Override public boolean hasMoreItems() { return p.hasMoreItems(); } + @Override public Pair getTotalResultCount() { return p.getTotalResultCount(); } + @Override public String getQueryExecutionId() { return p.getQueryExecutionId(); } + }; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/model/ClassifiedContentModel.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/model/ClassifiedContentModel.java index a334fbea33..d463657c96 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/model/ClassifiedContentModel.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/model/ClassifiedContentModel.java @@ -40,4 +40,8 @@ public interface ClassifiedContentModel QName PROP_CURRENT_CLASSIFICATION = QName.createQName(CLF_URI, "currentClassification"); QName PROP_CLASSIFICATION_AUTHORITY = QName.createQName(CLF_URI, "classificationAuthority"); QName PROP_CLASSIFICATION_REASONS = QName.createQName(CLF_URI, "classificationReasons"); + + /** Security Clearance aspect. */ + QName ASPECT_SECURITY_CLEARANCE = QName.createQName(CLF_URI, "securityClearance"); + QName PROP_CLEARANCE_LEVEL = QName.createQName(CLF_URI, "clearanceLevel"); } \ No newline at end of file diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/package-info.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/package-info.java index 9bc85dffe2..1def2a1185 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/package-info.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/package-info.java @@ -19,7 +19,14 @@ /** * This package contains the various types required for the 'Classified Records' feature. + * Nodes within Alfresco can be given a {@link org.alfresco.module.org_alfresco_module_rm.classification.ClassificationLevel} + * which then restricts access to them to users having the appropriate clearance. + *

+ * The {@link org.alfresco.module.org_alfresco_module_rm.classification.ClassificationService} is responsible + * for the management of those levels and it is the + * {@link org.alfresco.module.org_alfresco_module_rm.classification.SecurityClearanceService} which deals + * wth users and their clearances. * * @since 3.0 */ -package org.alfresco.module.org_alfresco_module_rm.classification; \ No newline at end of file +package org.alfresco.module.org_alfresco_module_rm.classification;