/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Cyclos 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.services.customization; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import nl.strohalm.cyclos.access.AdminMemberPermission; import nl.strohalm.cyclos.access.BrokerPermission; import nl.strohalm.cyclos.access.MemberPermission; import nl.strohalm.cyclos.entities.Relationship; import nl.strohalm.cyclos.entities.customization.documents.Document; import nl.strohalm.cyclos.entities.customization.documents.DocumentQuery; import nl.strohalm.cyclos.entities.customization.documents.DynamicDocument; import nl.strohalm.cyclos.entities.customization.documents.MemberDocument; import nl.strohalm.cyclos.entities.customization.documents.StaticDocument; import nl.strohalm.cyclos.entities.groups.Group; import nl.strohalm.cyclos.entities.groups.Group.Nature; import nl.strohalm.cyclos.entities.members.Member; import nl.strohalm.cyclos.exceptions.PermissionDeniedException; import nl.strohalm.cyclos.services.BaseServiceSecurity; import nl.strohalm.cyclos.utils.access.LoggedUser; import nl.strohalm.cyclos.utils.access.PermissionHelper; /** * Security implementation for {@link DocumentService} * * @author jcomas */ public class DocumentServiceSecurity extends BaseServiceSecurity implements DocumentService { private DocumentServiceLocal documentService; @Override public Document load(final Long id, final Relationship... fetch) { Document doc = documentService.load(id, fetch); checkView(doc); return doc; } @Override public int remove(final Long... ids) { for (Long id : ids) { Document md = documentService.load(id); checkManage(md); } return documentService.remove(ids); } @Override public Document saveDynamic(final DynamicDocument document) { checkManage(document); return documentService.saveDynamic(document); } @Override public Document saveStatic(final StaticDocument document, final InputStream stream, final int size, final String fileName, final String contentType) { checkManage(document); return documentService.saveStatic(document, stream, size, fileName, contentType); } @Override public List<Document> search(final DocumentQuery documentQuery) { if (!applyQueryRestrictions(documentQuery)) { return Collections.emptyList(); } return documentService.search(documentQuery); } public void setDocumentServiceLocal(final DocumentServiceLocal documentService) { this.documentService = documentService; } @Override public void validate(final Document document, final boolean validateBinaryFile) { // Nothing to check documentService.validate(document, validateBinaryFile); } /** * Filters the natures query parameter */ private boolean applyAllowedDocumentNatures(final DocumentQuery documentQuery) { List<Document.Nature> allowedNatures = new ArrayList<Document.Nature>(); if (LoggedUser.isAdministrator()) { // Administrator through a member's profile, only member and dynamic documents if (documentQuery.getMember() != null) { allowedNatures.add(Document.Nature.DYNAMIC); allowedNatures.add(Document.Nature.MEMBER); } else { // Administrator viewing global documents, only dynamic and static allowedNatures.add(Document.Nature.DYNAMIC); allowedNatures.add(Document.Nature.STATIC); } } else if (LoggedUser.isMember()) { Member member = fetchService.fetch(documentQuery.getMember(), Member.Relationships.BROKER); if (LoggedUser.isBroker() && !LoggedUser.member().equals(member)) { // Brokers can only view member and dynamic documents of his brokered members. if ((member.getBroker() != null) && member.getBroker().equals(LoggedUser.member())) { allowedNatures.add(Document.Nature.DYNAMIC); allowedNatures.add(Document.Nature.MEMBER); } else { // It's the broker documents. allowedNatures.add(Document.Nature.DYNAMIC); allowedNatures.add(Document.Nature.MEMBER); allowedNatures.add(Document.Nature.STATIC); } } else { // Members are allowed to view all types of documents. allowedNatures.add(Document.Nature.DYNAMIC); allowedNatures.add(Document.Nature.MEMBER); allowedNatures.add(Document.Nature.STATIC); } } Collection<Document.Nature> natures = PermissionHelper.checkSelection(allowedNatures, documentQuery.getNatures()); documentQuery.setNatures(natures); return natures != null; } private boolean applyQueryRestrictions(final DocumentQuery query) { Collection<Group> visibleGroups = PermissionHelper.checkSelection(permissionService.getAllVisibleGroups(), query.getVisibleGroups()); if (visibleGroups == null) { return false; } query.setViewer(LoggedUser.element()); query.setVisibleGroups(visibleGroups); if (LoggedUser.isBroker()) { // If there is no member assigned and a broker is searching, then it's assumed he is searching his own documents. if (query.getMember() == null) { query.setMember(LoggedUser.member()); } query.setBrokerCanViewMemberDocuments(permissionService.hasPermission(BrokerPermission.DOCUMENTS_VIEW_MEMBER)); } else if (LoggedUser.isMember()) { // Members can only search for his own member documents. query.setMember(LoggedUser.member()); } if (query.getMember() != null && !permissionService.manages(query.getMember())) { return false; } if (!applyAllowedDocumentNatures(query)) { return false; } return true; } private boolean canManage(final Document document) { if (document instanceof MemberDocument) { if (!permissionService.permission().admin(AdminMemberPermission.DOCUMENTS_MANAGE_MEMBER) .broker(BrokerPermission.DOCUMENTS_MANAGE_MEMBER).hasPermission()) { return false; } else { return permissionService.manages(((MemberDocument) document).getMember()); } } else if (document instanceof StaticDocument) { return permissionService.permission().admin(AdminMemberPermission.DOCUMENTS_MANAGE_STATIC).hasPermission(); } else { // DynamicDocument return permissionService.permission().admin(AdminMemberPermission.DOCUMENTS_MANAGE_DYNAMIC).hasPermission(); } } private void checkManage(final Document document) { if (!canManage(document)) { throw new PermissionDeniedException(); } } private void checkView(final Document doc) { if (doc instanceof MemberDocument) { MemberDocument mDoc = (MemberDocument) doc; mDoc = fetchService.fetch(mDoc, MemberDocument.Relationships.MEMBER); final MemberDocument.Visibility visibility = mDoc.getVisibility(); // Check the visibility of the document if (((LoggedUser.group().getNature() == Nature.MEMBER) && visibility != MemberDocument.Visibility.MEMBER) || (LoggedUser.isBroker() && visibility == MemberDocument.Visibility.ADMIN)) { throw new PermissionDeniedException(); } // Check the permission permissionService.permission(mDoc.getMember()) .admin(AdminMemberPermission.DOCUMENTS_MANAGE_MEMBER) .broker(BrokerPermission.DOCUMENTS_VIEW_MEMBER) .member() .check(); } else { // Check whether the document can be viewed by the logged user permissionService.permission() .adminFor(AdminMemberPermission.DOCUMENTS_DETAILS, doc) .brokerFor(BrokerPermission.DOCUMENTS_VIEW, doc) .memberFor(MemberPermission.DOCUMENTS_VIEW, doc).check(); } } }