Permission checks for authoring steps

pull/10/head
Jens Pelzetter 2021-04-03 14:40:33 +02:00
parent 2381460166
commit 5a75dc41a3
15 changed files with 541 additions and 45 deletions

View File

@ -222,7 +222,8 @@ public class AssetFolderController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
if (!assetPermissionsChecker.canEditAssets(section)) { if (!assetPermissionsChecker.canEditAssets(section)
&& !assetPermissionsChecker.canUseAssets(section)) {
sectionsUi.showAccessDenied("sectionIdentifier", sectionIdentifier); sectionsUi.showAccessDenied("sectionIdentifier", sectionIdentifier);
} }
@ -342,7 +343,8 @@ public class AssetFolderController {
return sectionsUi.showContentSectionNotFound(sectionIdentifier); return sectionsUi.showContentSectionNotFound(sectionIdentifier);
} }
if (!assetPermissionsChecker.canEditAssets(section)) { if (!assetPermissionsChecker.canEditAssets(section)
&& !assetPermissionsChecker.canUseAssets(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifier "sectionIdentifier", sectionIdentifier
); );
@ -528,11 +530,6 @@ public class AssetFolderController {
} else { } else {
return sectionsUi.showContentSectionNotFound(sectionIdentifier); return sectionsUi.showContentSectionNotFound(sectionIdentifier);
} }
if (!assetPermissionsChecker.canEditAssets(section)) {
return sectionsUi.showAccessDenied(
"sectionidentifier", sectionIdentifier
);
}
final Folder folder; final Folder folder;
final Optional<Folder> folderResult = folderRepo final Optional<Folder> folderResult = folderRepo

View File

@ -18,6 +18,8 @@
*/ */
package org.librecms.ui.contentsections; package org.librecms.ui.contentsections;
import com.arsdigita.cms.ui.authoring.multipartarticle.SectionPreviewPanel;
import org.libreccm.api.Identifier; import org.libreccm.api.Identifier;
import org.libreccm.api.IdentifierParser; import org.libreccm.api.IdentifierParser;
import org.libreccm.categorization.Categorization; import org.libreccm.categorization.Categorization;
@ -98,6 +100,12 @@ public class CategoriesController {
@Inject @Inject
private ContentSectionRepository sectionRepo; private ContentSectionRepository sectionRepo;
/**
* Provides common functions for controllers working with content sections.
*/
@Inject
private ContentSectionsUi sectionsUi;
/** /**
* The {@link GlobalizationHelper} to use. * The {@link GlobalizationHelper} to use.
*/ */
@ -146,6 +154,14 @@ public class CategoriesController {
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!permissionChecker.isPermitted(
AdminPrivileges.ADMINISTER_CATEGORIES, section
)) {
return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifier
);
}
final List<DomainListEntryModel> domains = section final List<DomainListEntryModel> domains = section
.getDomains() .getDomains()
.stream() .stream()
@ -229,6 +245,14 @@ public class CategoriesController {
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!permissionChecker.isPermitted(
AdminPrivileges.ADMINISTER_CATEGORIES, section
)) {
return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifier
);
}
final Optional<DomainOwnership> domainResult = section final Optional<DomainOwnership> domainResult = section
.getDomains() .getDomains()
.stream() .stream()

View File

@ -309,7 +309,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -353,7 +353,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -404,7 +404,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -455,7 +455,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -505,7 +505,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -556,7 +556,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -607,7 +607,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -656,7 +656,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -706,7 +706,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -864,7 +864,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -918,7 +918,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -979,7 +979,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -1042,7 +1042,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -1104,7 +1104,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -1167,7 +1167,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -1231,7 +1231,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -1293,7 +1293,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -1356,7 +1356,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );
@ -1437,7 +1437,7 @@ public class ConfigurationWorkflowController {
} }
final ContentSection section = sectionResult.get(); final ContentSection section = sectionResult.get();
sectionModel.setSection(section); sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerLifecycles(section)) { if (!adminPermissionsChecker.canAdministerWorkflows(section)) {
return sectionsUi.showAccessDenied( return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam "sectionIdentifier", sectionIdentifierParam
); );

View File

@ -112,7 +112,7 @@ public class ItemPermissionChecker {
* @return {@code true} if the current user can apply alternate workflows to * @return {@code true} if the current user can apply alternate workflows to
* the item, {@code false} otherwise. * the item, {@code false} otherwise.
*/ */
public boolean canApplyAlternateWorkflowItems( public boolean canApplyAlternateWorkflow(
final ContentItem item final ContentItem item
) { ) {
return permissionChecker.isPermitted( return permissionChecker.isPermitted(
@ -303,7 +303,7 @@ public class ItemPermissionChecker {
* @return {@code true} if the current user can edit the item, {@code false} * @return {@code true} if the current user can edit the item, {@code false}
* otherwise. * otherwise.
*/ */
public boolean canEditItems(final ContentItem item) { public boolean canEditItem(final ContentItem item) {
return permissionChecker.isPermitted( return permissionChecker.isPermitted(
ItemPrivileges.EDIT, item ItemPrivileges.EDIT, item
); );

View File

@ -27,9 +27,11 @@ import org.libreccm.categorization.DomainOwnership;
import org.libreccm.categorization.ObjectNotAssignedToCategoryException; import org.libreccm.categorization.ObjectNotAssignedToCategoryException;
import org.libreccm.core.UnexpectedErrorException; import org.libreccm.core.UnexpectedErrorException;
import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.security.PermissionChecker;
import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemManager; import org.librecms.contentsection.ContentItemManager;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.privileges.ItemPrivileges;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -66,6 +68,9 @@ public class CategorizationStep implements MvcAuthoringStep {
@Inject @Inject
private CategoryManager categoryManager; private CategoryManager categoryManager;
@Inject
private DocumentUi documentUi;
@Inject @Inject
private IdentifierParser identifierParser; private IdentifierParser identifierParser;
@ -78,6 +83,9 @@ public class CategorizationStep implements MvcAuthoringStep {
@Inject @Inject
private Models models; private Models models;
@Inject
private PermissionChecker permissionChecker;
/** /**
* The current content section. * The current content section.
*/ */
@ -195,7 +203,15 @@ public class CategorizationStep implements MvcAuthoringStep {
*/ */
@Override @Override
public String showStep() { 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()
);
}
} }
/** /**

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/public class CreateDenied
implements MvcDocumentCreateStep<ContentItem>{
@Override
public Class<ContentItem> 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<String, String> 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";
}
}

View File

@ -34,6 +34,7 @@ import org.librecms.lifecycle.LifecycleDefinition;
import org.librecms.lifecycle.Phase; import org.librecms.lifecycle.Phase;
import org.librecms.ui.contentsections.ContentSectionsUi; import org.librecms.ui.contentsections.ContentSectionsUi;
import org.librecms.ui.contentsections.DocumentFolderController; import org.librecms.ui.contentsections.DocumentFolderController;
import org.librecms.ui.contentsections.ItemPermissionChecker;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -111,12 +112,21 @@ public class DocumentController {
@Inject @Inject
private Instance<MvcDocumentCreateStep<?>> createSteps; private Instance<MvcDocumentCreateStep<?>> createSteps;
/**
* Messages for default steps
*/
@Inject
private DefaultStepsMessageBundle defaultStepsMessageBundle;
/** /**
* {@link GlobalizationHelper} for working with localized texts etc. * {@link GlobalizationHelper} for working with localized texts etc.
*/ */
@Inject @Inject
private GlobalizationHelper globalizationHelper; private GlobalizationHelper globalizationHelper;
@Inject
private ItemPermissionChecker itemPermissionChecker;
/** /**
* Used to make avaiable in the views without a named bean. * Used to make avaiable in the views without a named bean.
*/ */
@ -230,6 +240,15 @@ public class DocumentController {
folder = folderResult.get(); 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<? extends ContentItem> documentClass; final Class<? extends ContentItem> documentClass;
try { try {
documentClass = (Class<? extends ContentItem>) Class.forName( documentClass = (Class<? extends ContentItem>) Class.forName(
@ -301,6 +320,14 @@ public class DocumentController {
documentUi.showDocumentNotFound(section, documentPath); documentUi.showDocumentNotFound(section, documentPath);
} }
final ContentItem item = itemResult.get(); final ContentItem item = itemResult.get();
if (!itemPermissionChecker.canEditItem(item)) {
return documentUi.showAccessDenied(
section,
item,
defaultStepsMessageBundle.getMessage("edit_denied")
);
}
return String.format( return String.format(
"redirect:/%s/documents/%s/@authoringsteps/%s", "redirect:/%s/documents/%s/@authoringsteps/%s",
sectionIdentifier, sectionIdentifier,
@ -345,6 +372,14 @@ public class DocumentController {
return new DocumentNotFound(); return new DocumentNotFound();
} }
final ContentItem item = itemResult.get(); 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<MvcAuthoringStep> instance = authoringSteps final Instance<MvcAuthoringStep> instance = authoringSteps
.select( .select(
@ -416,6 +451,19 @@ public class DocumentController {
} }
selectedDocumentModel.setContentItem(item); 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( models.put(
"revisions", "revisions",
itemRepo.retrieveRevisions(item, item.getObjectId()) itemRepo.retrieveRevisions(item, item.getObjectId())

View File

@ -18,6 +18,8 @@
*/ */
package org.librecms.ui.contentsections.documents; package org.librecms.ui.contentsections.documents;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemManager;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
@ -30,7 +32,10 @@ import javax.mvc.Models;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@RequestScoped @RequestScoped
class DocumentUi { public class DocumentUi {
@Inject
private ContentItemManager itemManager;
/** /**
* Used to provide data for the views without a named bean. * Used to provide data for the views without a named bean.
@ -38,6 +43,25 @@ class DocumentUi {
@Inject @Inject
private Models models; 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( public String showDocumentNotFound(
final ContentSection section, final String documentPath final ContentSection section, final String documentPath
) { ) {

View File

@ -31,6 +31,7 @@ import org.librecms.contentsection.ContentItemRepository;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.privileges.ItemPrivileges; import org.librecms.contentsection.privileges.ItemPrivileges;
import org.librecms.ui.contentsections.ContentSectionsUi; import org.librecms.ui.contentsections.ContentSectionsUi;
import org.librecms.ui.contentsections.ItemPermissionChecker;
import java.util.Optional; import java.util.Optional;
@ -74,6 +75,9 @@ public class DocumentWorkflowController {
@Inject @Inject
private ContentSectionsUi sectionsUi; private ContentSectionsUi sectionsUi;
@Inject
private DefaultStepsMessageBundle defaultStepsMessageBundle;
/** /**
* Common functions for controllers working with {@link ContentItem}s. * Common functions for controllers working with {@link ContentItem}s.
*/ */
@ -86,6 +90,9 @@ public class DocumentWorkflowController {
@Inject @Inject
private IdentifierParser identifierParser; private IdentifierParser identifierParser;
@Inject
private ItemPermissionChecker itemPermissionChecker;
/** /**
* Used to check permissions for the current content item. * Used to check permissions for the current content item.
*/ */
@ -144,6 +151,15 @@ public class DocumentWorkflowController {
} }
final ContentItem item = itemResult.get(); final ContentItem item = itemResult.get();
selectedDocumentModel.setContentItem(item); selectedDocumentModel.setContentItem(item);
if (!itemPermissionChecker.canEditItem(item)) {
return documentUi.showAccessDenied(
section,
documentPath,
defaultStepsMessageBundle.getMessage(
"workflows.task.lock.access_denied"
)
);
}
final Optional<AssignableTask> taskResult = findTask( final Optional<AssignableTask> taskResult = findTask(
item, taskIdentifier item, taskIdentifier
@ -192,6 +208,15 @@ public class DocumentWorkflowController {
} }
final ContentItem item = itemResult.get(); final ContentItem item = itemResult.get();
selectedDocumentModel.setContentItem(item); selectedDocumentModel.setContentItem(item);
if (!itemPermissionChecker.canEditItem(item)) {
return documentUi.showAccessDenied(
section,
documentPath,
defaultStepsMessageBundle.getMessage(
"workflows.task.lock.access_denied"
)
);
}
final Optional<AssignableTask> taskResult = findTask( final Optional<AssignableTask> taskResult = findTask(
item, taskIdentifier item, taskIdentifier
@ -242,6 +267,15 @@ public class DocumentWorkflowController {
} }
final ContentItem item = itemResult.get(); final ContentItem item = itemResult.get();
selectedDocumentModel.setContentItem(item); selectedDocumentModel.setContentItem(item);
if (!itemPermissionChecker.canEditItem(item)) {
return documentUi.showAccessDenied(
section,
documentPath,
defaultStepsMessageBundle.getMessage(
"workflows.task.lock.access_denied"
)
);
}
final Optional<AssignableTask> taskResult = findTask( final Optional<AssignableTask> taskResult = findTask(
item, taskIdentifier item, taskIdentifier
@ -295,6 +329,15 @@ public class DocumentWorkflowController {
} }
final ContentItem item = itemResult.get(); final ContentItem item = itemResult.get();
selectedDocumentModel.setContentItem(item); selectedDocumentModel.setContentItem(item);
if (!itemPermissionChecker.canApplyAlternateWorkflow(item)) {
return documentUi.showAccessDenied(
section,
documentPath,
defaultStepsMessageBundle.getMessage(
"workflows.task.lock.access_denied"
)
);
}
if (!permissionChecker.isPermitted( if (!permissionChecker.isPermitted(
ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item)) { ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item)) {
@ -351,6 +394,15 @@ public class DocumentWorkflowController {
} }
final ContentItem item = itemResult.get(); final ContentItem item = itemResult.get();
selectedDocumentModel.setContentItem(item); selectedDocumentModel.setContentItem(item);
if (!itemPermissionChecker.canEditItem(item)) {
return documentUi.showAccessDenied(
section,
documentPath,
defaultStepsMessageBundle.getMessage(
"workflows.task.lock.access_denied"
)
);
}
if (!permissionChecker.isPermitted( if (!permissionChecker.isPermitted(
ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item)) { ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item)) {

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
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<? extends ContentItem> 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";
}
}

View File

@ -25,6 +25,7 @@ import org.librecms.contentsection.ContentSection;
import org.librecms.lifecycle.Lifecycle; import org.librecms.lifecycle.Lifecycle;
import org.librecms.lifecycle.LifecycleDefinition; import org.librecms.lifecycle.LifecycleDefinition;
import org.librecms.lifecycle.LifecycleDefinitionRepository; import org.librecms.lifecycle.LifecycleDefinitionRepository;
import org.librecms.ui.contentsections.ItemPermissionChecker;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -68,9 +69,18 @@ public class PublishStep implements MvcAuthoringStep {
@Inject @Inject
private ContentItemManager itemManager; private ContentItemManager itemManager;
@Inject
private DefaultStepsMessageBundle defaultStepsMessageBundle;
@Inject
private DocumentUi documentUi;
@Inject @Inject
private GlobalizationHelper globalizationHelper; private GlobalizationHelper globalizationHelper;
@Inject
private ItemPermissionChecker itemPermissionChecker;
@Inject @Inject
private LifecycleDefinitionRepository lifecycleDefRepo; private LifecycleDefinitionRepository lifecycleDefRepo;
@ -149,20 +159,30 @@ public class PublishStep implements MvcAuthoringStep {
@Override @Override
public String showStep() { public String showStep() {
final String lifecycleDefUuid; if (itemPermissionChecker.canPublishItems(document)) {
if (itemManager.isLive(document)) { final String lifecycleDefUuid;
lifecycleDefUuid = document if (itemManager.isLive(document)) {
.getLifecycle() lifecycleDefUuid = document
.getDefinition() .getLifecycle()
.getUuid(); .getDefinition()
.getUuid();
} else {
lifecycleDefUuid = document
.getContentType()
.getDefaultLifecycle()
.getUuid();
}
models.put("lifecycleDefinitionUuid", lifecycleDefUuid);
return "org/librecms/ui/documents/publish.xhtml";
} else { } else {
lifecycleDefUuid = document return documentUi.showAccessDenied(
.getContentType() section,
.getDefaultLifecycle() document,
.getUuid(); 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 (selectedLifecycleDefUuid.isEmpty()) {
if (itemManager.isLive(document)) { if (itemManager.isLive(document)) {
final LifecycleDefinition definition; final LifecycleDefinition definition;
@ -377,6 +405,14 @@ public class PublishStep implements MvcAuthoringStep {
@Path("/@unpublish") @Path("/@unpublish")
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public String unpublish() { public String unpublish() {
if (!itemPermissionChecker.canPublishItems(document)) {
return documentUi.showAccessDenied(
section,
document,
"item.unpublish"
);
}
itemManager.unpublish(document); itemManager.unpublish(document);
return String.format( return String.format(

View File

@ -27,6 +27,9 @@ import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.Folder; import org.librecms.contentsection.Folder;
import org.librecms.contentsection.FolderManager; import org.librecms.contentsection.FolderManager;
import org.librecms.contenttypes.Article; 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.enterprise.context.RequestScoped;
import javax.inject.Named; import javax.inject.Named;
@ -54,6 +57,9 @@ import javax.ws.rs.FormParam;
@Named("CmsArticleCreateStep") @Named("CmsArticleCreateStep")
public class MvcArticleCreateStep implements MvcDocumentCreateStep<Article> { public class MvcArticleCreateStep implements MvcDocumentCreateStep<Article> {
@Inject
private ArticleMessageBundle articleMessageBundle;
/** /**
* Provides functions for working with content items. * Provides functions for working with content items.
*/ */
@ -66,6 +72,11 @@ public class MvcArticleCreateStep implements MvcDocumentCreateStep<Article> {
@Inject @Inject
private ContentItemRepository itemRepo; private ContentItemRepository itemRepo;
@Inject
private DocumentUi documentUi;
/** /**
* Provides operations for folders. * Provides operations for folders.
*/ */
@ -78,6 +89,9 @@ public class MvcArticleCreateStep implements MvcDocumentCreateStep<Article> {
@Inject @Inject
private GlobalizationHelper globalizationHelper; private GlobalizationHelper globalizationHelper;
@Inject
private ItemPermissionChecker itemPermissionChecker;
/** /**
* Used to provided data for the views without a named bean. * Used to provided data for the views without a named bean.
*/ */
@ -203,7 +217,15 @@ public class MvcArticleCreateStep implements MvcDocumentCreateStep<Article> {
// @Path("/") // @Path("/")
@Override @Override
public String showCreateForm() { public String showCreateForm() {
if (itemPermissionChecker.canCreateNewItems(folder)) {
return "org/librecms/ui/contenttypes/article/create-article.xhtml"; return "org/librecms/ui/contenttypes/article/create-article.xhtml";
} else {
return documentUi.showAccessDenied(
section,
getFolderPath(),
articleMessageBundle.getMessage("create_new_article.denied")
);
}
} }
// @POST // @POST

View File

@ -27,7 +27,10 @@ import org.librecms.contentsection.ContentItemRepository;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.FolderManager; import org.librecms.contentsection.FolderManager;
import org.librecms.contenttypes.Article; import org.librecms.contenttypes.Article;
import org.librecms.ui.contentsections.ItemPermissionChecker;
import org.librecms.ui.contentsections.documents.AuthoringStepPathFragment; 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.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
@ -60,6 +63,9 @@ import javax.ws.rs.PathParam;
@Named("CmsArticlePropertiesStep") @Named("CmsArticlePropertiesStep")
public class MvcArticlePropertiesStep implements MvcAuthoringStep { public class MvcArticlePropertiesStep implements MvcAuthoringStep {
@Inject
private ArticleMessageBundle articleMessageBundle;
/** /**
* The path fragment of the step. * The path fragment of the step.
*/ */
@ -77,6 +83,9 @@ public class MvcArticlePropertiesStep implements MvcAuthoringStep {
@Inject @Inject
private ContentItemManager itemManager; private ContentItemManager itemManager;
@Inject
private DocumentUi documentUi;
/** /**
* Provides functions for working with folders. * Provides functions for working with folders.
*/ */
@ -89,6 +98,9 @@ public class MvcArticlePropertiesStep implements MvcAuthoringStep {
@Inject @Inject
private GlobalizationHelper globalizationHelper; private GlobalizationHelper globalizationHelper;
@Inject
private ItemPermissionChecker itemPermissionChecker;
/** /**
* The current content section. * The current content section.
*/ */
@ -170,7 +182,15 @@ public class MvcArticlePropertiesStep implements MvcAuthoringStep {
@Override @Override
public String showStep() { 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")
);
}
} }

View File

@ -20,13 +20,15 @@ package org.librecms.ui.contenttypes;
import org.libreccm.core.UnexpectedErrorException; import org.libreccm.core.UnexpectedErrorException;
import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.l10n.LocalizedString;
import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemManager; import org.librecms.contentsection.ContentItemManager;
import org.librecms.contentsection.ContentItemRepository; import org.librecms.contentsection.ContentItemRepository;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.FolderManager;
import org.librecms.contenttypes.Article; import org.librecms.contenttypes.Article;
import org.librecms.ui.contentsections.ItemPermissionChecker;
import org.librecms.ui.contentsections.documents.AuthoringStepPathFragment; import org.librecms.ui.contentsections.documents.AuthoringStepPathFragment;
import org.librecms.ui.contentsections.documents.DocumentUi;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.mvc.Controller; import javax.mvc.Controller;
@ -58,6 +60,9 @@ import javax.ws.rs.PathParam;
@Named("CmsArticleTextBodyStep") @Named("CmsArticleTextBodyStep")
public class MvcArticleTextBodyStep implements MvcAuthoringStep { public class MvcArticleTextBodyStep implements MvcAuthoringStep {
@Inject
private ArticleMessageBundle articleMessageBundle;
/** /**
* The path fragment of the step. * The path fragment of the step.
*/ */
@ -75,12 +80,18 @@ public class MvcArticleTextBodyStep implements MvcAuthoringStep {
@Inject @Inject
private ContentItemManager itemManager; private ContentItemManager itemManager;
@Inject
private DocumentUi documentUi;
/** /**
* Provides functions for working with {@link LocalizedString}s. * Provides functions for working with {@link LocalizedString}s.
*/ */
@Inject @Inject
private GlobalizationHelper globalizationHelper; private GlobalizationHelper globalizationHelper;
@Inject
private ItemPermissionChecker itemPermissionChecker;
/** /**
* The current content section. * The current content section.
*/ */
@ -162,7 +173,15 @@ public class MvcArticleTextBodyStep implements MvcAuthoringStep {
@Override @Override
public String showStep() { 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")
);
}
} }
/** /**

View File

@ -0,0 +1,33 @@
<!DOCTYPE html [<!ENTITY times '&#215;'>]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/content-section/documents/document.xhtml">
<ui:param name="activePage" value="document" />
<ui:param name="title" value="#{CmsAdminMessages['contentsection.documents.document_type.not_available.title']}" />
<ui:define name="breadcrumb">
<ui:include src="document-breadcrumbs.xhtml" />
<li aria-current="page" class="breadcrumb-item">
#{CmsAdminMessages['contentsection.document_access_denied.breadcrumb']}
</li>
</ui:define>
<ui:define name="main">
<div class="container">
<div class="alert alert-danger" role="alert">
#{CmsAdminMessages.getMessage('contentsection.document.access_denied.message', [section, documentPath, step])}
</div>
</div>
</ui:define>
</ui:composition>
</html>