diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/AssetFolderController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/AssetFolderController.java index e80af045b..843191aa3 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/AssetFolderController.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/AssetFolderController.java @@ -222,7 +222,8 @@ public class AssetFolderController { } final ContentSection section = sectionResult.get(); - if (!assetPermissionsChecker.canEditAssets(section)) { + if (!assetPermissionsChecker.canEditAssets(section) + && !assetPermissionsChecker.canUseAssets(section)) { sectionsUi.showAccessDenied("sectionIdentifier", sectionIdentifier); } @@ -342,7 +343,8 @@ public class AssetFolderController { return sectionsUi.showContentSectionNotFound(sectionIdentifier); } - if (!assetPermissionsChecker.canEditAssets(section)) { + if (!assetPermissionsChecker.canEditAssets(section) + && !assetPermissionsChecker.canUseAssets(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifier ); @@ -528,11 +530,6 @@ public class AssetFolderController { } else { return sectionsUi.showContentSectionNotFound(sectionIdentifier); } - if (!assetPermissionsChecker.canEditAssets(section)) { - return sectionsUi.showAccessDenied( - "sectionidentifier", sectionIdentifier - ); - } final Folder folder; final Optional folderResult = folderRepo diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/CategoriesController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/CategoriesController.java index 2015ffc89..3c2d61d3a 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/CategoriesController.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/CategoriesController.java @@ -18,6 +18,8 @@ */ package org.librecms.ui.contentsections; +import com.arsdigita.cms.ui.authoring.multipartarticle.SectionPreviewPanel; + import org.libreccm.api.Identifier; import org.libreccm.api.IdentifierParser; import org.libreccm.categorization.Categorization; @@ -98,6 +100,12 @@ public class CategoriesController { @Inject private ContentSectionRepository sectionRepo; + /** + * Provides common functions for controllers working with content sections. + */ + @Inject + private ContentSectionsUi sectionsUi; + /** * The {@link GlobalizationHelper} to use. */ @@ -146,6 +154,14 @@ public class CategoriesController { final ContentSection section = sectionResult.get(); sectionModel.setSection(section); + if (!permissionChecker.isPermitted( + AdminPrivileges.ADMINISTER_CATEGORIES, section + )) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifier + ); + } + final List domains = section .getDomains() .stream() @@ -229,6 +245,14 @@ public class CategoriesController { final ContentSection section = sectionResult.get(); sectionModel.setSection(section); + if (!permissionChecker.isPermitted( + AdminPrivileges.ADMINISTER_CATEGORIES, section + )) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifier + ); + } + final Optional domainResult = section .getDomains() .stream() diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationWorkflowController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationWorkflowController.java index 431526376..216072293 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationWorkflowController.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ConfigurationWorkflowController.java @@ -309,7 +309,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -353,7 +353,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -404,7 +404,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -455,7 +455,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -505,7 +505,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -556,7 +556,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -607,7 +607,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -656,7 +656,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -706,7 +706,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -864,7 +864,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -918,7 +918,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -979,7 +979,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -1042,7 +1042,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -1104,7 +1104,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -1167,7 +1167,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -1231,7 +1231,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -1293,7 +1293,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -1356,7 +1356,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); @@ -1437,7 +1437,7 @@ public class ConfigurationWorkflowController { } final ContentSection section = sectionResult.get(); sectionModel.setSection(section); - if (!adminPermissionsChecker.canAdministerLifecycles(section)) { + if (!adminPermissionsChecker.canAdministerWorkflows(section)) { return sectionsUi.showAccessDenied( "sectionIdentifier", sectionIdentifierParam ); diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ItemPermissionChecker.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ItemPermissionChecker.java index 0995804b7..bfd68b0f6 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/ItemPermissionChecker.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/ItemPermissionChecker.java @@ -112,7 +112,7 @@ public class ItemPermissionChecker { * @return {@code true} if the current user can apply alternate workflows to * the item, {@code false} otherwise. */ - public boolean canApplyAlternateWorkflowItems( + public boolean canApplyAlternateWorkflow( final ContentItem item ) { return permissionChecker.isPermitted( @@ -303,7 +303,7 @@ public class ItemPermissionChecker { * @return {@code true} if the current user can edit the item, {@code false} * otherwise. */ - public boolean canEditItems(final ContentItem item) { + public boolean canEditItem(final ContentItem item) { return permissionChecker.isPermitted( ItemPrivileges.EDIT, item ); diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CategorizationStep.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CategorizationStep.java index 136e6aff1..83c0ac46f 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CategorizationStep.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CategorizationStep.java @@ -27,9 +27,11 @@ import org.libreccm.categorization.DomainOwnership; import org.libreccm.categorization.ObjectNotAssignedToCategoryException; import org.libreccm.core.UnexpectedErrorException; import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.security.PermissionChecker; import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentItemManager; import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.privileges.ItemPrivileges; import java.util.ArrayList; import java.util.List; @@ -66,6 +68,9 @@ public class CategorizationStep implements MvcAuthoringStep { @Inject private CategoryManager categoryManager; + @Inject + private DocumentUi documentUi; + @Inject private IdentifierParser identifierParser; @@ -78,6 +83,9 @@ public class CategorizationStep implements MvcAuthoringStep { @Inject private Models models; + @Inject + private PermissionChecker permissionChecker; + /** * The current content section. */ @@ -195,7 +203,15 @@ public class CategorizationStep implements MvcAuthoringStep { */ @Override public String showStep() { - return "org/librecms/ui/documents/categorization.xhtml"; + if (permissionChecker.isPermitted(ItemPrivileges.CATEGORIZE, document)) { + return "org/librecms/ui/documents/categorization.xhtml"; + } else { + return documentUi.showAccessDenied( + section, + document, + getLabel() + ); + } } /** diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CreateDenied.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CreateDenied.java new file mode 100644 index 000000000..a3b795f8e --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/CreateDenied.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2021 LibreCCM Foundation. + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui.contentsections.documents; + +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.Folder; + +import java.util.Map; + +/** + * A pseudo implemention of the {@link MvcDocumentCreateStep} interface used by + * the {@link DocumentController} to show an error message when the current + * user is not permitted to create new items. + * + * Most of methods in this implementation are throwing an + * {@link UnsupportedOperationException}. + * + * @author Jens Pelzetter + */public class CreateDenied + implements MvcDocumentCreateStep{ + + @Override + public Class getDocumentType() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getDescription() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getBundle() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public ContentSection getContentSection() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setContentSection(ContentSection section) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getContentSectionLabel() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getContentSectionTitle() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Folder getFolder() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setFolder(Folder folder) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getFolderPath() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Map getMessages() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String showCreateForm() { + return "org/librecms/ui/contentsection/documents/access-denied.xhtml"; + } + + @Override + public String createContentItem() { + return "org/librecms/ui/contentsection/documents/access-denied.xhtml"; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java index bb70fdf60..9ab86454c 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java @@ -34,6 +34,7 @@ import org.librecms.lifecycle.LifecycleDefinition; import org.librecms.lifecycle.Phase; import org.librecms.ui.contentsections.ContentSectionsUi; import org.librecms.ui.contentsections.DocumentFolderController; +import org.librecms.ui.contentsections.ItemPermissionChecker; import java.time.ZoneId; import java.time.format.DateTimeFormatter; @@ -111,12 +112,21 @@ public class DocumentController { @Inject private Instance> createSteps; + /** + * Messages for default steps + */ + @Inject + private DefaultStepsMessageBundle defaultStepsMessageBundle; + /** * {@link GlobalizationHelper} for working with localized texts etc. */ @Inject private GlobalizationHelper globalizationHelper; + @Inject + private ItemPermissionChecker itemPermissionChecker; + /** * Used to make avaiable in the views without a named bean. */ @@ -230,6 +240,15 @@ public class DocumentController { folder = folderResult.get(); } + if (!itemPermissionChecker.canCreateNewItems(folder)) { + models.put("section", section.getLabel()); + models.put("folderPath", folderPath); + models.put( + "step", defaultStepsMessageBundle.getMessage("create_step") + ); + return new CreateDenied(); + } + final Class documentClass; try { documentClass = (Class) Class.forName( @@ -301,6 +320,14 @@ public class DocumentController { documentUi.showDocumentNotFound(section, documentPath); } final ContentItem item = itemResult.get(); + if (!itemPermissionChecker.canEditItem(item)) { + return documentUi.showAccessDenied( + section, + item, + defaultStepsMessageBundle.getMessage("edit_denied") + ); + } + return String.format( "redirect:/%s/documents/%s/@authoringsteps/%s", sectionIdentifier, @@ -345,6 +372,14 @@ public class DocumentController { return new DocumentNotFound(); } final ContentItem item = itemResult.get(); + if (!itemPermissionChecker.canEditItem(item)) { + models.put("section", section.getLabel()); + models.put("documentPath", itemManager.getItemFolder(item)); + models.put( + "step", defaultStepsMessageBundle.getMessage("edit_step") + ); + return new EditDenied(); + } final Instance instance = authoringSteps .select( @@ -416,6 +451,19 @@ public class DocumentController { } selectedDocumentModel.setContentItem(item); + if (!itemPermissionChecker.canEditItem(item)) { + models.put("section", section.getLabel()); + models.put("documentPath", itemManager.getItemFolder(item)); + models.put( + "step", defaultStepsMessageBundle.getMessage("edit_step") + ); + return documentUi.showAccessDenied( + section, + documentPath, + defaultStepsMessageBundle.getMessage("history") + ); + } + models.put( "revisions", itemRepo.retrieveRevisions(item, item.getObjectId()) diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentUi.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentUi.java index 341dede86..09daac853 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentUi.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentUi.java @@ -18,6 +18,8 @@ */ package org.librecms.ui.contentsections.documents; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemManager; import org.librecms.contentsection.ContentSection; import javax.enterprise.context.RequestScoped; @@ -30,14 +32,36 @@ import javax.mvc.Models; * @author Jens Pelzetter */ @RequestScoped -class DocumentUi { +public class DocumentUi { + @Inject + private ContentItemManager itemManager; + /** * Used to provide data for the views without a named bean. */ @Inject private Models models; + public String showAccessDenied( + final ContentSection section, + final ContentItem item, + final String step + ) { + return showAccessDenied(section, itemManager.getItemPath(item), step); + } + + public String showAccessDenied( + final ContentSection section, + final String documentPath, + final String step + ) { + models.put("section", section.getLabel()); + models.put("documentPath", documentPath); + models.put("step", step); + return "org/librecms/ui/contentsection/documents/access-denied.xhtml"; + } + public String showDocumentNotFound( final ContentSection section, final String documentPath ) { diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentWorkflowController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentWorkflowController.java index bd29c3d66..2e6f70cea 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentWorkflowController.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentWorkflowController.java @@ -31,6 +31,7 @@ import org.librecms.contentsection.ContentItemRepository; import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.privileges.ItemPrivileges; import org.librecms.ui.contentsections.ContentSectionsUi; +import org.librecms.ui.contentsections.ItemPermissionChecker; import java.util.Optional; @@ -74,6 +75,9 @@ public class DocumentWorkflowController { @Inject private ContentSectionsUi sectionsUi; + @Inject + private DefaultStepsMessageBundle defaultStepsMessageBundle; + /** * Common functions for controllers working with {@link ContentItem}s. */ @@ -86,6 +90,9 @@ public class DocumentWorkflowController { @Inject private IdentifierParser identifierParser; + @Inject + private ItemPermissionChecker itemPermissionChecker; + /** * Used to check permissions for the current content item. */ @@ -144,6 +151,15 @@ public class DocumentWorkflowController { } final ContentItem item = itemResult.get(); selectedDocumentModel.setContentItem(item); + if (!itemPermissionChecker.canEditItem(item)) { + return documentUi.showAccessDenied( + section, + documentPath, + defaultStepsMessageBundle.getMessage( + "workflows.task.lock.access_denied" + ) + ); + } final Optional taskResult = findTask( item, taskIdentifier @@ -192,6 +208,15 @@ public class DocumentWorkflowController { } final ContentItem item = itemResult.get(); selectedDocumentModel.setContentItem(item); + if (!itemPermissionChecker.canEditItem(item)) { + return documentUi.showAccessDenied( + section, + documentPath, + defaultStepsMessageBundle.getMessage( + "workflows.task.lock.access_denied" + ) + ); + } final Optional taskResult = findTask( item, taskIdentifier @@ -242,6 +267,15 @@ public class DocumentWorkflowController { } final ContentItem item = itemResult.get(); selectedDocumentModel.setContentItem(item); + if (!itemPermissionChecker.canEditItem(item)) { + return documentUi.showAccessDenied( + section, + documentPath, + defaultStepsMessageBundle.getMessage( + "workflows.task.lock.access_denied" + ) + ); + } final Optional taskResult = findTask( item, taskIdentifier @@ -295,6 +329,15 @@ public class DocumentWorkflowController { } final ContentItem item = itemResult.get(); selectedDocumentModel.setContentItem(item); + if (!itemPermissionChecker.canApplyAlternateWorkflow(item)) { + return documentUi.showAccessDenied( + section, + documentPath, + defaultStepsMessageBundle.getMessage( + "workflows.task.lock.access_denied" + ) + ); + } if (!permissionChecker.isPermitted( ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item)) { @@ -351,6 +394,15 @@ public class DocumentWorkflowController { } final ContentItem item = itemResult.get(); selectedDocumentModel.setContentItem(item); + if (!itemPermissionChecker.canEditItem(item)) { + return documentUi.showAccessDenied( + section, + documentPath, + defaultStepsMessageBundle.getMessage( + "workflows.task.lock.access_denied" + ) + ); + } if (!permissionChecker.isPermitted( ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item)) { diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/EditDenied.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/EditDenied.java new file mode 100644 index 000000000..1b7120228 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/EditDenied.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2021 LibreCCM Foundation. + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.ui.contentsections.documents; + +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentSection; + +/** + * A pseudo implemention of the {@link MvcAuthoringStep} interface used by the + * {@link DocumentController} to show an error message when the current user is + * not permitted to edit an item. + * + * Most of methods in this implementation are throwing an + * {@link UnsupportedOperationException}. + * + * @author Jens Pelzetter + */ +public class EditDenied implements MvcAuthoringStep { + + @Override + public String getDescription() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getBundle() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public ContentSection getContentSection() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setContentSection(ContentSection section) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getContentSectionLabel() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getContentSectionTitle() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Class supportedDocumentType() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getLabel() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public ContentItem getContentItem() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setContentItem(ContentItem document) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getContentItemPath() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getContentItemTitle() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String showStep() { + return "org/librecms/ui/contentsection/documents/access-denied.xhtml"; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStep.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStep.java index 18518c529..9d26c0f43 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStep.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStep.java @@ -25,6 +25,7 @@ import org.librecms.contentsection.ContentSection; import org.librecms.lifecycle.Lifecycle; import org.librecms.lifecycle.LifecycleDefinition; import org.librecms.lifecycle.LifecycleDefinitionRepository; +import org.librecms.ui.contentsections.ItemPermissionChecker; import java.time.LocalDate; import java.time.LocalDateTime; @@ -68,9 +69,18 @@ public class PublishStep implements MvcAuthoringStep { @Inject private ContentItemManager itemManager; + @Inject + private DefaultStepsMessageBundle defaultStepsMessageBundle; + + @Inject + private DocumentUi documentUi; + @Inject private GlobalizationHelper globalizationHelper; + @Inject + private ItemPermissionChecker itemPermissionChecker; + @Inject private LifecycleDefinitionRepository lifecycleDefRepo; @@ -149,20 +159,30 @@ public class PublishStep implements MvcAuthoringStep { @Override public String showStep() { - final String lifecycleDefUuid; - if (itemManager.isLive(document)) { - lifecycleDefUuid = document - .getLifecycle() - .getDefinition() - .getUuid(); + if (itemPermissionChecker.canPublishItems(document)) { + final String lifecycleDefUuid; + if (itemManager.isLive(document)) { + lifecycleDefUuid = document + .getLifecycle() + .getDefinition() + .getUuid(); + } else { + lifecycleDefUuid = document + .getContentType() + .getDefaultLifecycle() + .getUuid(); + } + models.put("lifecycleDefinitionUuid", lifecycleDefUuid); + return "org/librecms/ui/documents/publish.xhtml"; } else { - lifecycleDefUuid = document - .getContentType() - .getDefaultLifecycle() - .getUuid(); + return documentUi.showAccessDenied( + section, + document, + defaultStepsMessageBundle.getMessage( + "access_to_authoringstep_denied", new String[]{getLabel()} + ) + ); } - models.put("lifecycleDefinitionUuid", lifecycleDefUuid); - return "org/librecms/ui/documents/publish.xhtml"; } /** @@ -336,6 +356,14 @@ public class PublishStep implements MvcAuthoringStep { ) ); + if (!itemPermissionChecker.canPublishItems(document)) { + return documentUi.showAccessDenied( + section, + document, + "item.publish" + ); + } + if (selectedLifecycleDefUuid.isEmpty()) { if (itemManager.isLive(document)) { final LifecycleDefinition definition; @@ -377,6 +405,14 @@ public class PublishStep implements MvcAuthoringStep { @Path("/@unpublish") @Transactional(Transactional.TxType.REQUIRED) public String unpublish() { + if (!itemPermissionChecker.canPublishItems(document)) { + return documentUi.showAccessDenied( + section, + document, + "item.unpublish" + ); + } + itemManager.unpublish(document); return String.format( diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticleCreateStep.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticleCreateStep.java index 394c61e44..d43720c24 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticleCreateStep.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticleCreateStep.java @@ -27,6 +27,9 @@ import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.Folder; import org.librecms.contentsection.FolderManager; import org.librecms.contenttypes.Article; +import org.librecms.ui.contentsections.ItemPermissionChecker; +import org.librecms.ui.contentsections.documents.DefaultStepsMessageBundle; +import org.librecms.ui.contentsections.documents.DocumentUi; import javax.enterprise.context.RequestScoped; import javax.inject.Named; @@ -54,6 +57,9 @@ import javax.ws.rs.FormParam; @Named("CmsArticleCreateStep") public class MvcArticleCreateStep implements MvcDocumentCreateStep
{ + @Inject + private ArticleMessageBundle articleMessageBundle; + /** * Provides functions for working with content items. */ @@ -66,6 +72,11 @@ public class MvcArticleCreateStep implements MvcDocumentCreateStep
{ @Inject private ContentItemRepository itemRepo; + + + @Inject + private DocumentUi documentUi; + /** * Provides operations for folders. */ @@ -78,6 +89,9 @@ public class MvcArticleCreateStep implements MvcDocumentCreateStep
{ @Inject private GlobalizationHelper globalizationHelper; + @Inject + private ItemPermissionChecker itemPermissionChecker; + /** * Used to provided data for the views without a named bean. */ @@ -203,7 +217,15 @@ public class MvcArticleCreateStep implements MvcDocumentCreateStep
{ // @Path("/") @Override public String showCreateForm() { + if (itemPermissionChecker.canCreateNewItems(folder)) { return "org/librecms/ui/contenttypes/article/create-article.xhtml"; + } else { + return documentUi.showAccessDenied( + section, + getFolderPath(), + articleMessageBundle.getMessage("create_new_article.denied") + ); + } } // @POST diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticlePropertiesStep.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticlePropertiesStep.java index 5d7cec87a..1d21e9292 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticlePropertiesStep.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticlePropertiesStep.java @@ -27,7 +27,10 @@ import org.librecms.contentsection.ContentItemRepository; import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.FolderManager; import org.librecms.contenttypes.Article; +import org.librecms.ui.contentsections.ItemPermissionChecker; import org.librecms.ui.contentsections.documents.AuthoringStepPathFragment; +import org.librecms.ui.contentsections.documents.DefaultStepsMessageBundle; +import org.librecms.ui.contentsections.documents.DocumentUi; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; @@ -60,6 +63,9 @@ import javax.ws.rs.PathParam; @Named("CmsArticlePropertiesStep") public class MvcArticlePropertiesStep implements MvcAuthoringStep { + @Inject + private ArticleMessageBundle articleMessageBundle; + /** * The path fragment of the step. */ @@ -77,6 +83,9 @@ public class MvcArticlePropertiesStep implements MvcAuthoringStep { @Inject private ContentItemManager itemManager; + @Inject + private DocumentUi documentUi; + /** * Provides functions for working with folders. */ @@ -89,6 +98,9 @@ public class MvcArticlePropertiesStep implements MvcAuthoringStep { @Inject private GlobalizationHelper globalizationHelper; + @Inject + private ItemPermissionChecker itemPermissionChecker; + /** * The current content section. */ @@ -170,7 +182,15 @@ public class MvcArticlePropertiesStep implements MvcAuthoringStep { @Override public String showStep() { - return "org/librecms/ui/contenttypes/article/article-basic-properties.xhtml"; + if (itemPermissionChecker.canEditItem(document)) { + return "org/librecms/ui/contenttypes/article/article-basic-properties.xhtml"; + } else { + return documentUi.showAccessDenied( + section, + document, + articleMessageBundle.getMessage("article.edit.denied") + ); + } } diff --git a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticleTextBodyStep.java b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticleTextBodyStep.java index 21e44ba7c..398817343 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticleTextBodyStep.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contenttypes/MvcArticleTextBodyStep.java @@ -20,13 +20,15 @@ package org.librecms.ui.contenttypes; import org.libreccm.core.UnexpectedErrorException; import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.l10n.LocalizedString; import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentItemManager; import org.librecms.contentsection.ContentItemRepository; import org.librecms.contentsection.ContentSection; -import org.librecms.contentsection.FolderManager; import org.librecms.contenttypes.Article; +import org.librecms.ui.contentsections.ItemPermissionChecker; import org.librecms.ui.contentsections.documents.AuthoringStepPathFragment; +import org.librecms.ui.contentsections.documents.DocumentUi; import javax.enterprise.context.RequestScoped; import javax.mvc.Controller; @@ -58,6 +60,9 @@ import javax.ws.rs.PathParam; @Named("CmsArticleTextBodyStep") public class MvcArticleTextBodyStep implements MvcAuthoringStep { + @Inject + private ArticleMessageBundle articleMessageBundle; + /** * The path fragment of the step. */ @@ -75,12 +80,18 @@ public class MvcArticleTextBodyStep implements MvcAuthoringStep { @Inject private ContentItemManager itemManager; + @Inject + private DocumentUi documentUi; + /** * Provides functions for working with {@link LocalizedString}s. */ @Inject private GlobalizationHelper globalizationHelper; + @Inject + private ItemPermissionChecker itemPermissionChecker; + /** * The current content section. */ @@ -162,7 +173,15 @@ public class MvcArticleTextBodyStep implements MvcAuthoringStep { @Override public String showStep() { - return "org/librecms/ui/contenttypes/article/article-text.xhtml"; + if (itemPermissionChecker.canEditItem(document)) { + return "org/librecms/ui/contenttypes/article/article-text.xhtml"; + } else { + return documentUi.showAccessDenied( + section, + document, + articleMessageBundle.getMessage("article.edit.denied") + ); + } } /** diff --git a/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/documents/access-denied.xhtml b/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/documents/access-denied.xhtml new file mode 100644 index 000000000..eff1d3ea3 --- /dev/null +++ b/ccm-cms/src/main/resources/WEB-INF/views/org/librecms/ui/contentsection/documents/access-denied.xhtml @@ -0,0 +1,33 @@ +]> + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + +