Some code formattig, added function for fixing item and asset permissions (sometimes they are not correctly inherited from the folder.

master
Jens Pelzetter 2023-07-12 21:08:18 +02:00
parent 4251fd1df9
commit 7cea45560a
21 changed files with 1272 additions and 166 deletions

View File

@ -580,16 +580,28 @@ public class PagesController {
final Page page = pageManager.findPageForCategory(category); final Page page = pageManager.findPageForCategory(category);
pagePropertiesModel.setProperties(page.getProperties()); pagePropertiesModel.setProperties(page.getProperties());
try {
final String result;
if (itemName.equals("index") || itemName.isBlank()) { if (itemName.equals("index") || itemName.isBlank()) {
return themesMvc.getMvcTemplate( result = themesMvc.getMvcTemplate(
uriInfo, "pages", page.getDisplayName() uriInfo, "pages", page.getDisplayName()
); );
} else { } else {
return themesMvc.getMvcTemplate( result = themesMvc.getMvcTemplate(
uriInfo, "pages", "item-page" uriInfo, "pages", "item-page"
); );
} }
return result;
} catch (Exception ex) {
throw new WebApplicationException(
"An error occured while rendering the page.",
ex,
Response.serverError().entity(
"An error occured while rendering the page."
).build()
);
}
} }
private void initSiteInfoModel( private void initSiteInfoModel(

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2023 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.pages.models;
import org.librecms.contentsection.ContentItem;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ContentItemListItemModel extends AbstractContentItemListItemModel {
@Override
public String getType() {
return ContentItem.class.getName();
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2023 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.pages.models;
import org.librecms.contentsection.ContentItem;
import javax.enterprise.context.RequestScoped;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class ContentItemListModelBuilder
extends AbstractContentItemListItemModelBuilder<ContentItem, ContentItemListItemModel> {
@Override
public Class<ContentItem> buildsListItemModelFor() {
return ContentItem.class;
}
@Override
protected ContentItemListItemModel buildModel() {
return new ContentItemListItemModel();
}
}

View File

@ -251,10 +251,11 @@ public class ItemListModel {
criteriaBuilder.isNull(catJoin.get("type")), criteriaBuilder.isNull(catJoin.get("type")),
criteriaBuilder.equal( criteriaBuilder.equal(
from.get("version"), ContentItemVersion.LIVE from.get("version"), ContentItemVersion.LIVE
),
buildPermissionsCheck(
criteriaBuilder, from, permissionsJoin
) )
// ,
// buildPermissionsCheck(
// criteriaBuilder, from, permissionsJoin
// )
) )
); );
@ -265,7 +266,7 @@ public class ItemListModel {
.collect(Collectors.toList()) .collect(Collectors.toList())
); );
return entityManager final List<? extends AbstractContentItemListItemModel> result = entityManager
.createQuery(criteriaQuery) .createQuery(criteriaQuery)
.getResultList() .getResultList()
.stream() .stream()
@ -278,6 +279,8 @@ public class ItemListModel {
.limit(pageSize) .limit(pageSize)
.map(this::buildListItemModel) .map(this::buildListItemModel)
.collect(Collectors.toList()); .collect(Collectors.toList());
return result;
} }
private List<Category> collectCategories(final Category category) { private List<Category> collectCategories(final Category category) {

View File

@ -93,6 +93,8 @@ public class ConfigurationController {
return "org/librecms/ui/contentsection/configuration/index.xhtml"; return "org/librecms/ui/contentsection/configuration/index.xhtml";
} }
/** /**
* Checks if the current user is permitted to access the configurations page * Checks if the current user is permitted to access the configurations page
* of the content section. * of the content section.

View File

@ -0,0 +1,141 @@
/*
* Copyright (C) 2023 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;
import org.libreccm.categorization.Categorization;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.PermissionManager;
import org.librecms.contentsection.Asset;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionManager;
import org.librecms.contentsection.Folder;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.mvc.Controller;
import javax.transaction.Transactional;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
/**
* Controller for the fix item and asset permissions function.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Controller
@Path("/{sectionIdentifier}/configuration/fix-item-and-asset-permissions")
public class ConfigurationFixItemPermissionsController {
/**
* Used to check the admin permissions of a content section.
*/
@Inject
private AdminPermissionsChecker adminPermissionsChecker;
// @Inject
// private ContentSectionManager sectionManager;
@Inject
private ContentSectionModel sectionModel;
/**
* Common functions for views working with {@link ContentSection}s.
*/
@Inject
private ContentSectionsUi sectionsUi;
// @Inject
// private PermissionManager permissionManager;
//
@Inject
private FixItemPermissionsTaskManager taskManager;
@POST
@Path("/")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String fixItemAndAssetPermissions(
@PathParam("sectionIdentifier") final String sectionIdentifierParam
) {
final Optional<ContentSection> sectionResult = sectionsUi
.findContentSection(sectionIdentifierParam);
if (!sectionResult.isPresent()) {
return sectionsUi.showContentSectionNotFound(sectionIdentifierParam);
}
final ContentSection section = sectionResult.get();
sectionModel.setSection(section);
if (!adminPermissionsChecker.canAdministerContentTypes(section)) {
return sectionsUi.showAccessDenied(
"sectionIdentifier", sectionIdentifierParam
);
}
// fixContentItemPermissions(section.getRootDocumentsFolder());
// fixAssetPermissions(section.getRootAssetsFolder());
taskManager.fixItemPermissions(section);
return String.format(
"redirect:%s/configuration", sectionIdentifierParam
);
}
// private void fixContentItemPermissions(final Folder folder) {
// final List<ContentItem> items = folder
// .getObjects()
// .stream()
// .map(Categorization::getCategorizedObject)
// .filter(obj -> obj instanceof ContentItem)
// .map(obj -> (ContentItem) obj)
// .collect(Collectors.toList());
//
// for(final ContentItem item : items) {
// permissionManager.copyPermissions(folder, item, true);
// }
//
// for(final Folder subFolder : folder.getSubFolders()) {
// fixContentItemPermissions(subFolder);
// }
// }
//
// private void fixAssetPermissions(final Folder folder) {
// final List<Asset> assets = folder
// .getObjects()
// .stream()
// .map(Categorization::getCategorizedObject)
// .filter(obj -> obj instanceof Asset)
// .map(obj -> (Asset) obj)
// .collect(Collectors.toList());
//
// for(final Asset asset : assets) {
// permissionManager.copyPermissions(folder, asset, true);
// }
//
// for(final Folder subFolder : folder.getSubFolders()) {
// fixAssetPermissions(subFolder);
// }
// }
}

View File

@ -76,6 +76,7 @@ public class ContentSectionApplication extends Application {
classes.add(ConfigurationController.class); classes.add(ConfigurationController.class);
classes.add(ConfigurationContactEntryKeysController.class); classes.add(ConfigurationContactEntryKeysController.class);
classes.add(ConfigurationDocumentTypesController.class); classes.add(ConfigurationDocumentTypesController.class);
classes.add(ConfigurationFixItemPermissionsController.class);
classes.add(ConfigurationLifecyclesController.class); classes.add(ConfigurationLifecyclesController.class);
classes.add(ConfigurationRolesController.class); classes.add(ConfigurationRolesController.class);
classes.add(ConfigurationWorkflowController.class); classes.add(ConfigurationWorkflowController.class);

View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2023 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;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.categorization.Categorization;
import org.libreccm.core.CcmObject;
import org.libreccm.security.PermissionManager;
import org.librecms.contentsection.Asset;
import org.librecms.contentsection.AssetManager;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemManager;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionRepository;
import org.librecms.contentsection.Folder;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@ApplicationScoped
public class FixItemPermissions {
private static final Logger LOGGER = LogManager.getLogger(
FixItemPermissions.class
);
@Inject
private AssetManager assetManager;
@Inject
private ContentItemManager itemManager;
@Inject
private ContentSectionRepository sectionRepo;
@Inject
private PermissionManager permissionManager;
@Transactional(Transactional.TxType.REQUIRED)
public void fixItemPermissions(final ContentSection contentSection) {
final String sectionUuid = Optional
.ofNullable(contentSection)
.map(ContentSection::getUuid)
.orElseThrow(
() -> new IllegalArgumentException(
"Can't fix ItemPermissions for content section null"
)
);
final ContentSection section = sectionRepo
.findByUuid(sectionUuid)
.orElseThrow(
() -> new IllegalArgumentException(
String.format(
"No ContentSection with UUID %s in the database.",
sectionUuid
)
)
);
fixContentItemPermissions(section.getRootDocumentsFolder());
fixAssetPermissions(section.getRootAssetsFolder());
}
private void fixContentItemPermissions(final Folder folder) {
final List<ContentItem> items = new ArrayList<>();
for (final Categorization categorization : folder.getObjects()) {
final CcmObject categorized = categorization.getCategorizedObject();
if (categorized instanceof ContentItem) {
items.add((ContentItem) categorized);
}
}
// final List<ContentItem> items = folder
// .getObjects()
// .stream()
// .map(Categorization::getCategorizedObject)
// .filter(obj -> obj instanceof ContentItem)
// .map(obj -> (ContentItem) obj)
// .collect(Collectors.toList());
for (final ContentItem item : items) {
LOGGER.info(
"Fixing permissions for item {} {}",
item.getUuid(),
itemManager.getItemPath(item)
);
permissionManager.copyPermissions(folder, item, true);
if (itemManager.isLive(item)) {
permissionManager.copyPermissions(
folder,
itemManager.getLiveVersion(item, ContentItem.class).get(),
true
);
}
}
for (final Folder subFolder : folder.getSubFolders()) {
fixContentItemPermissions(subFolder);
}
}
private void fixAssetPermissions(final Folder folder) {
final List<Asset> assets = folder
.getObjects()
.stream()
.map(Categorization::getCategorizedObject)
.filter(obj -> obj instanceof Asset)
.map(obj -> (Asset) obj)
.collect(Collectors.toList());
for (final Asset asset : assets) {
LOGGER.info(
"Fixing permissions for asset {} {}...",
asset.getUuid(),
assetManager.getAssetPath(asset)
);
permissionManager.copyPermissions(folder, asset, true);
}
for (final Folder subFolder : folder.getSubFolders()) {
fixAssetPermissions(subFolder);
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2023 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;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public enum FixItemPermissionsStatus {
/**
* An error occured during the process.
*/
ERROR,
/**
* The import or export task is finished.
*/
FINISHED,
/**
* The task is still running.
*/
RUNNING,
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2023 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;
import org.apache.shiro.mgt.SecurityManager;
import org.librecms.contentsection.ContentSection;
import java.time.LocalDate;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class FixItemPermissionsTask {
private final ContentSection contentSection;
private final LocalDate started;
private final FixItemPermissionsTaskStatus status;
private final org.apache.shiro.mgt.SecurityManager securityManager;
public FixItemPermissionsTask(
final ContentSection contentSection,
final LocalDate started,
final FixItemPermissionsTaskStatus status,
final org.apache.shiro.mgt.SecurityManager securityManager
) {
this.contentSection = contentSection;
this.started = started;
this.status = status;
this.securityManager = securityManager;
}
public ContentSection getContentSection() {
return contentSection;
}
public LocalDate getStarted() {
return started;
}
public FixItemPermissionsTaskStatus getStatus() {
return status;
}
public SecurityManager getSecurityManager() {
return securityManager;
}
}

View File

@ -0,0 +1,159 @@
/*
* Copyright (C) 2023 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;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.librecms.contentsection.ContentSection;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Comparator;
import java.util.Optional;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@ApplicationScoped
public class FixItemPermissionsTaskManager {
private static final Logger LOGGER = LogManager.getLogger(
FixItemPermissionsTaskManager.class
);
@Inject
private Event<FixItemPermissionsTask> taskSender;
private final SortedSet<FixItemPermissionsTaskStatus> tasks;
public SortedSet<FixItemPermissionsTaskStatus> getTasks() {
return Collections.unmodifiableSortedSet(tasks);
}
public boolean isTaskActiveForContentSection(final ContentSection section) {
return isTaskActiveForContentSection(
Optional
.ofNullable(section)
.map(ContentSection::getLabel)
.orElseThrow(
() -> new IllegalArgumentException(
"Can't check task status for ContentSection null."
)
)
);
}
public boolean isTaskActiveForContentSection(final String name) {
return tasks
.stream()
.anyMatch(
task -> task.getContentSection().equals(name)
&& task.getStatus()
== FixItemPermissionsStatus.RUNNING
);
}
public boolean isTaskFailedForContentSection(final String name) {
return tasks
.stream()
.anyMatch(
task -> task.getContentSection().equals(name)
&& task.getStatus()
== FixItemPermissionsStatus.ERROR
);
}
public FixItemPermissionsTaskManager() {
tasks = new TreeSet<>(
Comparator
.comparing(FixItemPermissionsTaskStatus::getStarted)
.thenComparing(FixItemPermissionsTaskStatus::getContentSection)
);
}
@Transactional(Transactional.TxType.REQUIRED)
public void fixItemPermissions(final ContentSection section) {
if (isTaskActiveForContentSection(section)) {
throw new IllegalArgumentException(
String.format(
"A FixItemPermissionsTask is already active for content "
+ "section %s.",
section.getLabel()
)
);
}
tasks.removeAll(
tasks
.stream()
.filter(task -> task.getStatus()
== FixItemPermissionsStatus.ERROR
|| task.getStatus()
== FixItemPermissionsStatus.FINISHED)
.collect(Collectors.toSet())
);
final FixItemPermissionsTaskStatus taskStatus
= new FixItemPermissionsTaskStatus();
taskStatus.setContentSection(section.getLabel());
taskStatus.setStarted(LocalDateTime.now());
taskSender.fireAsync(
new FixItemPermissionsTask(
section,
LocalDate.now(),
taskStatus,
SecurityUtils.getSecurityManager()
)
).handle((task, ex) -> handleTaskResult(task, ex, taskStatus));
taskStatus.setStatus(FixItemPermissionsStatus.RUNNING);
}
private Object handleTaskResult(
final FixItemPermissionsTask task,
final Throwable ex,
final FixItemPermissionsTaskStatus status
) {
if (ex == null) {
status.setStatus(FixItemPermissionsStatus.FINISHED);
} else {
status.setStatus(FixItemPermissionsStatus.ERROR);
status.setException(ex);
LOGGER.error(
"Fix Item Permissions for Content Section {} failed ",
status.getContentSection()
);
LOGGER.error("with exception:", ex);
}
return task;
}
}

View File

@ -0,0 +1,152 @@
/*
* Copyright (C) 2023 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;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Objects;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class FixItemPermissionsTaskStatus
implements Comparable<FixItemPermissionsTaskStatus> {
/**
* The content section for which the task was started.
*/
private String contentSection;
/**
* When was the task started?
*/
private LocalDateTime started;
/**
* The status of the task.
*/
private FixItemPermissionsStatus status;
/**
* If the proces throw an exception, it is stored here.
*/
private Throwable exception;
public String getContentSection() {
return contentSection;
}
protected void setContentSection(final String contentSection) {
this.contentSection = contentSection;
}
public LocalDateTime getStarted() {
return started;
}
protected void setStarted(final LocalDateTime started) {
this.started = started;
}
public FixItemPermissionsStatus getStatus() {
return status;
}
protected void setStatus(final FixItemPermissionsStatus status) {
this.status = status;
}
public Throwable getException() {
return exception;
}
protected void setException(final Throwable exception) {
this.exception = exception;
}
@Override
public int hashCode() {
int hash = 5;
hash = 17 * hash + Objects.hashCode(contentSection);
hash = 17 * hash + Objects.hashCode(started);
hash = 17 * hash + Objects.hashCode(status);
return hash;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (obj instanceof FixItemPermissionsTaskStatus) {
return false;
}
final FixItemPermissionsTaskStatus other
= (FixItemPermissionsTaskStatus) obj;
if (!other.canEqual(this)) {
return false;
}
if (!Objects.equals(contentSection, other.getContentSection())) {
return false;
}
if (!Objects.equals(started, other.getStarted())) {
return false;
}
return status == other.getStatus();
}
public boolean canEqual(final Object obj) {
return obj instanceof FixItemPermissionsTaskStatus;
}
@Override
public int compareTo(final FixItemPermissionsTaskStatus other) {
return Comparator
.nullsFirst(
Comparator
.comparing(FixItemPermissionsTaskStatus::getContentSection)
.thenComparing(FixItemPermissionsTaskStatus::getStarted)
)
.compare(this, other);
}
@Override
public String toString() {
return String.format(
"%s{"
+ "contentSection = %s, "
+ "started = %s, "
+ "status = %s"
+ "}",
super.toString(),
contentSection,
DateTimeFormatter.ISO_DATE_TIME
.withZone(ZoneId.systemDefault())
.format(started),
Objects.toString(status)
);
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 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;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("FixItemPermissionsTaskStatusModel")
public class FixItemPermissionsTaskStatusModel {
@Inject
private ContentSectionModel sectionModel;
@Inject
private FixItemPermissionsTaskManager taskManager;
public boolean isTaskRunningForContentSection() {
return taskManager.isTaskActiveForContentSection(
sectionModel.getSectionName()
);
}
public boolean isTaskFailedForContentSection() {
return taskManager.isTaskFailedForContentSection(
sectionModel.getSectionName()
);
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2023 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;
import org.apache.shiro.util.ThreadContext;
import org.libreccm.security.Shiro;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.ObservesAsync;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@ApplicationScoped
public class FixItemPermissionsTasks {
@Inject
private FixItemPermissions fixItemPermissions;
@Inject
private Shiro shiro;
@Transactional(Transactional.TxType.REQUIRED)
public void fixItemPermissions(
@ObservesAsync final FixItemPermissionsTask task
) {
ThreadContext.bind(task.getSecurityManager());
shiro.getSystemUser().execute(() -> executeFixItemPermissions(task));
}
private void executeFixItemPermissions(final FixItemPermissionsTask task) {
fixItemPermissions.fixItemPermissions(task.getContentSection());
}
}

View File

@ -136,6 +136,51 @@
</p> </p>
</div> </div>
</div> </div>
<div class="col mb-4">
<div aria-describedby="configuration-fixitemandassetspermissions-body"
class="card pt-2"
id="configuration-fixitemandassetspermissions">
<svg aria-hidden="true"
class="card-img-top"
fill="currentColor">
<use xlink:href="#{request.contextPath}/assets/bootstrap/bootstrap-icons.svg#screwdriver" />
</svg>
</div>
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/configuration/fix-item-and-asset-permissions"
class="card-body"
id="configuration-fixitemandassetspermissions-body"
method="post">
<h2 class="card-title">
<c:choose>
<c:when test="#{FixItemPermissionsTaskStatusModel.taskRunningForContentSection}">
#{CmsAdminMessages['contentsection.configuration.fixitemandassetspermissions.title']}
</c:when>
<c:otherwise>
<button class="btn btn-link stretched-link"
type="submit">
#{CmsAdminMessages['contentsection.configuration.fixitemandassetspermissions.title']}
</button>
</c:otherwise>
</c:choose>
</h2>
<p class="card-text">
<c:if test="#{FixItemPermissionsTaskStatusModel.taskFailedForContentSection}">
<div class="alert alert-danger" role="alert">
#{CmsAdminMessages['contentsection.configuration.fixitemandassetspermissions.failed']}
</div>
</c:if>
<c:choose>
<c:when test="#{FixItemPermissionsTaskStatusModel.taskRunningForContentSection}">
#{CmsAdminMessages['contentsection.configuration.fixitemandassetspermissions.running']}
</c:when>
<c:otherwise>
#{CmsAdminMessages['contentsection.configuration.fixitemandassetspermissions.description']}
</c:otherwise>
</c:choose>
</p>
</form>
</div>
</div> </div>
</div> </div>
</ui:define> </ui:define>

View File

@ -1030,3 +1030,7 @@ pages.page.details.displayname.dialog.displayname.help=The display name of the p
pages.page.details.displayname.dialog.submit=Save pages.page.details.displayname.dialog.submit=Save
pages.page.details.displayname.edit=Edit display name pages.page.details.displayname.edit=Edit display name
pages.page.details.dialog.displayname.label=Display name pages.page.details.dialog.displayname.label=Display name
contentsection.configuration.fixitemandassetspermissions.title=Fix permissions
contentsection.configuration.fixitemandassetspermissions.description=Repairs the permissions for items and assets
contentsection.configuration.fixitemandassetspermissions.running=Fixing permissions for item and assets...
contentsection.configuration.fixitemandassetspermissions.failed=Failed to repair permissions for items and assets. Check the log for details.

View File

@ -1031,3 +1031,7 @@ pages.page.details.displayname.dialog.displayname.help=The display name of the p
pages.page.details.displayname.dialog.submit=Speichern pages.page.details.displayname.dialog.submit=Speichern
pages.page.details.displayname.edit=Display Name bearbeiten pages.page.details.displayname.edit=Display Name bearbeiten
pages.page.details.dialog.displayname.label=Display Name pages.page.details.dialog.displayname.label=Display Name
contentsection.configuration.fixitemandassetspermissions.title=Berechtigungen reparieren
contentsection.configuration.fixitemandassetspermissions.description=Repariert die Berechtigungen f\u00fcr Dokumente und Assets
contentsection.configuration.fixitemandassetspermissions.running=Repariere Berechtigungen f\u00fcr Dokumente und Assets
contentsection.configuration.fixitemandassetspermissions.failed=Reparieren der Berechtigungen f\u00fcr Dokumente und Assets fehlgeschlagen. Weitere Informationen im Log.

View File

@ -18,6 +18,8 @@
*/ */
package org.libreccm.mvc.freemarker; package org.libreccm.mvc.freemarker;
import com.arsdigita.kernel.KernelConfig;
import freemarker.cache.ClassTemplateLoader; import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.MultiTemplateLoader; import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader; import freemarker.cache.TemplateLoader;
@ -26,6 +28,7 @@ import freemarker.template.Configuration;
import freemarker.template.TemplateExceptionHandler; import freemarker.template.TemplateExceptionHandler;
import org.eclipse.krazo.engine.ViewEngineConfig; import org.eclipse.krazo.engine.ViewEngineConfig;
import org.eclipse.krazo.ext.freemarker.DefaultConfigurationProducer; import org.eclipse.krazo.ext.freemarker.DefaultConfigurationProducer;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.theming.Themes; import org.libreccm.theming.Themes;
import javax.enterprise.inject.Produces; import javax.enterprise.inject.Produces;
@ -43,6 +46,9 @@ import javax.servlet.ServletContext;
public class MvcFreemarkerConfigurationProducer public class MvcFreemarkerConfigurationProducer
extends DefaultConfigurationProducer { extends DefaultConfigurationProducer {
@Inject
private ConfigurationManager confManager;
@Inject @Inject
private Models models; private Models models;
@ -60,15 +66,27 @@ public class MvcFreemarkerConfigurationProducer
@Specializes @Specializes
@Override @Override
public Configuration getConfiguration() { public Configuration getConfiguration() {
final KernelConfig kernelConfig = confManager.findConfiguration(
KernelConfig.class
);
final Configuration configuration = new Configuration( final Configuration configuration = new Configuration(
Configuration.VERSION_2_3_30 Configuration.VERSION_2_3_30
); );
configuration.setDefaultEncoding("UTF-8"); configuration.setDefaultEncoding("UTF-8");
if (kernelConfig.isDebugEnabled()) {
configuration.setTemplateExceptionHandler(
TemplateExceptionHandler.DEBUG_HANDLER
);
configuration.setLogTemplateExceptions(true);
} else {
configuration.setTemplateExceptionHandler( configuration.setTemplateExceptionHandler(
TemplateExceptionHandler.RETHROW_HANDLER TemplateExceptionHandler.RETHROW_HANDLER
); );
configuration.setLogTemplateExceptions(false); configuration.setLogTemplateExceptions(false);
}
configuration.setWrapUncheckedExceptions(false); configuration.setWrapUncheckedExceptions(false);
configuration.setLocalizedLookup(false); configuration.setLocalizedLookup(false);
configuration.setTemplateLoader( configuration.setTemplateLoader(

View File

@ -57,8 +57,10 @@ public class PermissionManager implements Serializable {
@SuppressWarnings("PMD.LongVariable") @SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_OBJECT = "object"; private static final String QUERY_PARAM_OBJECT = "object";
@SuppressWarnings("PMD.LongVariable") @SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_GRANTEE = "grantee"; private static final String QUERY_PARAM_GRANTEE = "grantee";
@SuppressWarnings("PMD.LongVariable") @SuppressWarnings("PMD.LongVariable")
private static final String QUERY_PARAM_PRIVILEGE = "privilege"; private static final String QUERY_PARAM_PRIVILEGE = "privilege";
@ -79,8 +81,12 @@ public class PermissionManager implements Serializable {
* @return The permission identified by the provided {@code permissionId). * @return The permission identified by the provided {@code permissionId).
*/ */
public Optional<Permission> findById(final long permissionId) { public Optional<Permission> findById(final long permissionId) {
return Optional.ofNullable(entityManager.find(Permission.class, return Optional.ofNullable(
permissionId)); entityManager.find(
Permission.class,
permissionId
)
);
} }
/** /**
@ -93,7 +99,9 @@ public class PermissionManager implements Serializable {
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public List<Permission> findPermissionsForRole(final Role role) { public List<Permission> findPermissionsForRole(final Role role) {
final TypedQuery<Permission> query = entityManager.createNamedQuery( final TypedQuery<Permission> query = entityManager.createNamedQuery(
"Permission.findPermissionsForRole", Permission.class); "Permission.findPermissionsForRole",
Permission.class
);
query.setParameter("grantee", role); query.setParameter("grantee", role);
return query.getResultList(); return query.getResultList();
@ -110,17 +118,22 @@ public class PermissionManager implements Serializable {
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public List<Permission> findPermissionsForObject(final CcmObject object) { public List<Permission> findPermissionsForObject(final CcmObject object) {
final TypedQuery<Permission> query = entityManager.createNamedQuery( final TypedQuery<Permission> query = entityManager.createNamedQuery(
"Permission.findPermissionsForCcmObject", Permission.class); "Permission.findPermissionsForCcmObject",
Permission.class
);
query.setParameter("object", object); query.setParameter("object", object);
return query.getResultList(); return query.getResultList();
} }
public List<Permission> findPermissionsForRoleAndObject( public List<Permission> findPermissionsForRoleAndObject(
final Role role, final CcmObject object) { final Role role,
final CcmObject object
) {
final TypedQuery<Permission> query = entityManager.createNamedQuery( final TypedQuery<Permission> query = entityManager.createNamedQuery(
"Permission.findPermissionsForRoleAndObject", Permission.class); "Permission.findPermissionsForRoleAndObject",
Permission.class
);
query.setParameter("object", object); query.setParameter("object", object);
query.setParameter("grantee", role); query.setParameter("grantee", role);
@ -148,9 +161,11 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public Permission grantPrivilege(final String privilege, public Permission grantPrivilege(
final String privilege,
final Role grantee, final Role grantee,
final CcmObject object) { final CcmObject object
) {
if (privilege == null || privilege.isEmpty()) { if (privilege == null || privilege.isEmpty()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't grant a permission without a privilege."); "Can't grant a permission without a privilege.");
@ -182,7 +197,13 @@ public class PermissionManager implements Serializable {
entityManager.persist(permission); entityManager.persist(permission);
grantRecursive(privilege, grantee, object, object.getClass(), object); grantRecursive(
privilege,
grantee,
object,
object.getClass(),
object
);
return permission; return permission;
} }
@ -202,32 +223,44 @@ public class PermissionManager implements Serializable {
* {@link #grantPrivilege(java.lang.String, org.libreccm.security.Role, org.libreccm.core.CcmObject)} * {@link #grantPrivilege(java.lang.String, org.libreccm.security.Role, org.libreccm.core.CcmObject)}
* was invoked. * was invoked.
*/ */
private void grantRecursive(final String privilege, private void grantRecursive(
final String privilege,
final Role grantee, final Role grantee,
final CcmObject object, final CcmObject object,
final Class<?> clazz, final Class<?> clazz,
final CcmObject inheritedFrom) { final CcmObject inheritedFrom
) {
final Field[] fields = clazz.getDeclaredFields(); final Field[] fields = clazz.getDeclaredFields();
Arrays.stream(fields) Arrays.stream(fields)
.filter(field -> field.isAnnotationPresent( .filter(field -> field.isAnnotationPresent(
RecursivePermissions.class)) RecursivePermissions.class))
.filter(field -> { .filter(
return checkIfPrivilegeIsRecursive( field -> checkIfPrivilegeIsRecursive(
field.getAnnotation(RecursivePermissions.class), field.getAnnotation(RecursivePermissions.class),
privilege); privilege
}) )
.forEach(field -> { )
.forEach(
field -> {
field.setAccessible(true); field.setAccessible(true);
grantRecursive(privilege, grantee, field, object, inheritedFrom); grantRecursive(
privilege,
grantee,
field,
object,
inheritedFrom
);
}); });
// Repeat for superclass of the current class. // Repeat for superclass of the current class.
if (clazz.getSuperclass() != null) { if (clazz.getSuperclass() != null) {
grantRecursive(privilege, grantRecursive(
privilege,
grantee, grantee,
object, object,
clazz.getSuperclass(), clazz.getSuperclass(),
inheritedFrom); inheritedFrom
);
} }
} }
@ -246,13 +279,14 @@ public class PermissionManager implements Serializable {
*/ */
private boolean checkIfPrivilegeIsRecursive( private boolean checkIfPrivilegeIsRecursive(
final RecursivePermissions annotation, final RecursivePermissions annotation,
final String privilege) { final String privilege
) {
if (annotation.privileges() == null if (annotation.privileges() == null
|| annotation.privileges().length == 0) { || annotation.privileges().length == 0) {
return true; return true;
} else { } else {
return Arrays.stream(annotation.privileges()) return Arrays
.stream(annotation.privileges())
.anyMatch(privilege::equals); .anyMatch(privilege::equals);
} }
} }
@ -266,24 +300,35 @@ public class PermissionManager implements Serializable {
* @param owner The object which own the provided {@code field}. * @param owner The object which own the provided {@code field}.
* @param inheritedFrom The object from which the permission is inherited. * @param inheritedFrom The object from which the permission is inherited.
*/ */
private void grantRecursive(final String privilege, private void grantRecursive(
final String privilege,
final Role grantee, final Role grantee,
final Field field, final Field field,
final CcmObject owner, final CcmObject owner,
final CcmObject inheritedFrom) { final CcmObject inheritedFrom
) {
final CcmObject ownerObject = ccmObjectRepo final CcmObject ownerObject = ccmObjectRepo
.findObjectById(owner.getObjectId()) .findObjectById(owner.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(
() -> new IllegalArgumentException(
String.format(
"No CcmObject with ID %d in the database. " "No CcmObject with ID %d in the database. "
+ "Where did that ID come from?", + "Where did that ID come from?",
owner.getObjectId()))); owner.getObjectId()
)
)
);
final CcmObject inheritedFromObject = ccmObjectRepo final CcmObject inheritedFromObject = ccmObjectRepo
.findObjectById(inheritedFrom.getObjectId()) .findObjectById(inheritedFrom.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(
() -> new IllegalArgumentException(
String.format(
"No CcmObject with ID %d in the database. " "No CcmObject with ID %d in the database. "
+ "Where did that ID come from?", + "Where did that ID come from?",
inheritedFrom.getObjectId()))); inheritedFrom.getObjectId()
)
)
);
final Object value; final Object value;
try { try {
@ -303,10 +348,14 @@ public class PermissionManager implements Serializable {
collection.stream() collection.stream()
.filter(obj -> obj instanceof CcmObject) .filter(obj -> obj instanceof CcmObject)
.map(obj -> (CcmObject) obj) .map(obj -> (CcmObject) obj)
.forEach(obj -> grantInherited(privilege, .forEach(
obj -> grantInherited(
privilege,
grantee, grantee,
obj, obj,
inheritedFromObject)); inheritedFromObject
)
);
// Relations between two CcmObjects with attributes or n:m relations // Relations between two CcmObjects with attributes or n:m relations
// use an object to represent the relation. The object must implement // use an object to represent the relation. The object must implement
// the Relation interface. For each Relation object in the collection // the Relation interface. For each Relation object in the collection
@ -316,33 +365,44 @@ public class PermissionManager implements Serializable {
.map(obj -> (Relation) obj) .map(obj -> (Relation) obj)
.filter(relation -> relation.getRelatedObject() != null) .filter(relation -> relation.getRelatedObject() != null)
.map(relation -> relation.getRelatedObject()) .map(relation -> relation.getRelatedObject())
.forEach(obj -> grantInherited(privilege, .forEach(
obj -> grantInherited(
privilege,
grantee, grantee,
obj, obj,
inheritedFromObject)); inheritedFromObject
)
);
} else if (CcmObject.class.isAssignableFrom(field.getType())) { } else if (CcmObject.class.isAssignableFrom(field.getType())) {
// If the provided object is a CcmObject create an inherited // If the provided object is a CcmObject create an inherited
// permission for this object. // permission for this object.
grantInherited(privilege, grantInherited(
privilege,
grantee, grantee,
(CcmObject) value, (CcmObject) value,
inheritedFromObject); inheritedFromObject
);
} else if (Relation.class.isAssignableFrom(field.getType())) { } else if (Relation.class.isAssignableFrom(field.getType())) {
// If the provided field is a Relation object created an inherited // If the provided field is a Relation object created an inherited
// permission on the related object. // permission on the related object.
final Relation relation = (Relation) value; final Relation relation = (Relation) value;
if (relation.getRelatedObject() != null) { if (relation.getRelatedObject() != null) {
grantInherited(privilege, grantInherited(
privilege,
grantee, grantee,
relation.getRelatedObject(), relation.getRelatedObject(),
inheritedFromObject); inheritedFromObject
);
} }
} else { } else {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(
String.format(
"Found a field annotated with \"%s\" but the field is not a " "Found a field annotated with \"%s\" but the field is not a "
+ "collection nor a CcmObject nore a Relation object. This " + "collection nor a CcmObject nore a Relation object. This "
+ "is not supported.", + "is not supported.",
RecursivePermissions.class)); RecursivePermissions.class
)
);
} }
} }
@ -355,11 +415,12 @@ public class PermissionManager implements Serializable {
* granted. * granted.
* @param inheritedFrom The object from which the permission is inherited. * @param inheritedFrom The object from which the permission is inherited.
*/ */
private void grantInherited(final String privilege, private void grantInherited(
final String privilege,
final Role grantee, final Role grantee,
final CcmObject object, final CcmObject object,
final CcmObject inheritedFrom) { final CcmObject inheritedFrom
) {
if (!existsPermission(privilege, grantee, object)) { if (!existsPermission(privilege, grantee, object)) {
final Permission permission = new Permission(); final Permission permission = new Permission();
permission.setGrantee(grantee); permission.setGrantee(grantee);
@ -371,11 +432,13 @@ public class PermissionManager implements Serializable {
entityManager.persist(permission); entityManager.persist(permission);
grantRecursive(privilege, grantRecursive(
privilege,
grantee, grantee,
object, object,
object.getClass(), object.getClass(),
inheritedFrom); inheritedFrom
);
} }
} }
@ -389,16 +452,20 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void grantPrivilege(final String privilege, public void grantPrivilege(
final Role grantee) { final String privilege,
final Role grantee
) {
if (privilege == null || privilege.isEmpty()) { if (privilege == null || privilege.isEmpty()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't grant a permission without a privilege."); "Can't grant a permission without a privilege."
);
} }
if (grantee == null) { if (grantee == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't grant a permission to grantee null."); "Can't grant a permission to grantee null."
);
} }
if (!existsPermission(privilege, grantee)) { if (!existsPermission(privilege, grantee)) {
@ -423,42 +490,52 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void revokePrivilege(final String privilege, public void revokePrivilege(
final String privilege,
final Role grantee, final Role grantee,
final CcmObject object) { final CcmObject object
) {
if (privilege == null || privilege.isEmpty()) { if (privilege == null || privilege.isEmpty()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't revoke a permission without a privilege."); "Can't revoke a permission without a privilege."
);
} }
if (grantee == null) { if (grantee == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't revoke a permission from grantee null."); "Can't revoke a permission from grantee null."
);
} }
if (object == null) { if (object == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't revoke a permission from object NULL."); "Can't revoke a permission from object NULL."
);
} }
LOGGER.debug("Revoking permission granting privilege \"{}\" " LOGGER.debug(
"Revoking permission granting privilege \"{}\" "
+ "on object \"{}\" to role \"{}\"...", + "on object \"{}\" to role \"{}\"...",
privilege, privilege,
grantee.getName(), grantee.getName(),
object.getUuid()); object.getUuid()
);
if (existsPermission(privilege, grantee, object) if (existsPermission(privilege, grantee, object)
|| existsInheritedPermission(privilege, grantee, object)) { || existsInheritedPermission(privilege, grantee, object)) {
LOGGER.debug("There is a permission for the provided parameters, " LOGGER.debug(
+ "revoking it..."); "There is a permission for the provided parameters, "
+ "revoking it..."
);
final Query deleteQuery = entityManager.createQuery( final Query deleteQuery = entityManager.createQuery(
"DELETE FROM Permission p " "DELETE FROM Permission p "
+ "WHERE p.grantedPrivilege = :privilege " + "WHERE p.grantedPrivilege = :privilege "
+ "AND p.grantee = :grantee " + "AND p.grantee = :grantee "
+ "AND p.object = :object"); + "AND p.object = :object"
);
deleteQuery.setParameter(QUERY_PARAM_PRIVILEGE, privilege); deleteQuery.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
deleteQuery.setParameter(QUERY_PARAM_GRANTEE, grantee); deleteQuery.setParameter(QUERY_PARAM_GRANTEE, grantee);
deleteQuery.setParameter(QUERY_PARAM_OBJECT, object); deleteQuery.setParameter(QUERY_PARAM_OBJECT, object);
@ -470,18 +547,21 @@ public class PermissionManager implements Serializable {
+ "WHERE p.grantedPrivilege = :privilege " + "WHERE p.grantedPrivilege = :privilege "
+ "AND p.grantee = :grantee " + "AND p.grantee = :grantee "
+ "AND p.inheritedFrom = :object " + "AND p.inheritedFrom = :object "
+ "AND p.inherited = true"); + "AND p.inherited = true"
);
deleteInheritedQuery.setParameter(QUERY_PARAM_PRIVILEGE, privilege); deleteInheritedQuery.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
deleteInheritedQuery.setParameter(QUERY_PARAM_GRANTEE, grantee); deleteInheritedQuery.setParameter(QUERY_PARAM_GRANTEE, grantee);
deleteInheritedQuery.setParameter("object", object); deleteInheritedQuery.setParameter("object", object);
final int deletedInherited = deleteInheritedQuery.executeUpdate(); final int deletedInherited = deleteInheritedQuery.executeUpdate();
LOGGER.debug("{} inherited permissions deleted.", deletedInherited); LOGGER.debug("{} inherited permissions deleted.", deletedInherited);
} else { } else {
LOGGER.warn("No permission granting privilege \"{}\" " LOGGER.warn(
"No permission granting privilege \"{}\" "
+ "on object \"{}\" to role \"{}\". Ignoring.", + "on object \"{}\" to role \"{}\". Ignoring.",
privilege, privilege,
grantee.getName(), grantee.getName(),
object.getUuid()); object.getUuid()
);
} }
} }
@ -495,16 +575,20 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void revokePrivilege(final String privilege, public void revokePrivilege(
final Role grantee) { final String privilege,
final Role grantee
) {
if (privilege == null || privilege.isEmpty()) { if (privilege == null || privilege.isEmpty()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't revoke a permission without a privilege."); "Can't revoke a permission without a privilege."
);
} }
if (grantee == null) { if (grantee == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't revoke a permission from grantee null."); "Can't revoke a permission from grantee null."
);
} }
if (existsPermission(privilege, grantee)) { if (existsPermission(privilege, grantee)) {
@ -512,7 +596,8 @@ public class PermissionManager implements Serializable {
"DELETE FROM Permission p " "DELETE FROM Permission p "
+ "WHERE p.grantedPrivilege = :privilege " + "WHERE p.grantedPrivilege = :privilege "
+ "AND p.grantee = :grantee " + "AND p.grantee = :grantee "
+ "AND p.object IS NULL"); + "AND p.object IS NULL"
);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege); query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee); query.setParameter(QUERY_PARAM_GRANTEE, grantee);
query.executeUpdate(); query.executeUpdate();
@ -532,8 +617,10 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void copyPermissions(final CcmObject source, public void copyPermissions(
final CcmObject target) { final CcmObject source,
final CcmObject target
) {
copyPermissions(source, target, false); copyPermissions(source, target, false);
} }
@ -552,21 +639,27 @@ public class PermissionManager implements Serializable {
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void copyPermissions(final CcmObject source, public void copyPermissions(
final CcmObject source,
final CcmObject target, final CcmObject target,
final boolean inherited) { final boolean inherited
) {
if (source == null) { if (source == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't copy permissions from source NULL."); "Can't copy permissions from source NULL."
);
} }
if (target == null) { if (target == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't copy permissions to target NULL."); "Can't copy permissions to target NULL."
);
} }
final TypedQuery<Permission> query = entityManager.createNamedQuery( final TypedQuery<Permission> query = entityManager.createNamedQuery(
"Permission.findPermissionsForCcmObject", Permission.class); "Permission.findPermissionsForCcmObject",
Permission.class
);
query.setParameter(QUERY_PARAM_OBJECT, source); query.setParameter(QUERY_PARAM_OBJECT, source);
final List<Permission> result = query.getResultList(); final List<Permission> result = query.getResultList();
@ -574,7 +667,11 @@ public class PermissionManager implements Serializable {
final Permission granted = grantPrivilege( final Permission granted = grantPrivilege(
permission.getGrantedPrivilege(), permission.getGrantedPrivilege(),
permission.getGrantee(), permission.getGrantee(),
target); target
);
if (granted == null) {
continue;
}
granted.setInherited(inherited); granted.setInherited(inherited);
if (inherited) { if (inherited) {
granted.setInheritedFrom(source); granted.setInheritedFrom(source);
@ -598,12 +695,17 @@ public class PermissionManager implements Serializable {
* @return A list with all privileges defined by the provided class. * @return A list with all privileges defined by the provided class.
*/ */
public List<String> listDefiniedPrivileges(final Class<?> clazz) { public List<String> listDefiniedPrivileges(final Class<?> clazz) {
return Arrays.stream(clazz.getDeclaredFields()) return Arrays
.stream(clazz.getDeclaredFields())
.filter(field -> field.getType().isAssignableFrom(String.class)) .filter(field -> field.getType().isAssignableFrom(String.class))
.filter(field -> Modifier.isStatic(field.getModifiers()) .filter(
&& Modifier.isFinal(field.getModifiers())) field -> Modifier.isStatic(field.getModifiers())
.filter(field -> field.getName().startsWith("PRIVILEGE_") && Modifier.isFinal(field.getModifiers())
|| clazz.getSimpleName().endsWith("Privileges")) )
.filter(
field -> field.getName().startsWith("PRIVILEGE_")
|| clazz.getSimpleName().endsWith("Privileges")
)
.map(field -> getPrivilegeString(field)) .map(field -> getPrivilegeString(field))
.sorted() .sorted()
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -629,11 +731,15 @@ public class PermissionManager implements Serializable {
* @return {@code true} if there is a matching permission, {@code false} if * @return {@code true} if there is a matching permission, {@code false} if
* not. * not.
*/ */
private boolean existsPermission(final String privilege, private boolean existsPermission(
final String privilege,
final Role grantee, final Role grantee,
final CcmObject object) { final CcmObject object
) {
final TypedQuery<Long> query = entityManager.createNamedQuery( final TypedQuery<Long> query = entityManager.createNamedQuery(
"Permission.existsDirectForPrivilegeRoleObject", Long.class); "Permission.existsDirectForPrivilegeRoleObject",
Long.class
);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege); query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee); query.setParameter(QUERY_PARAM_GRANTEE, grantee);
query.setParameter(QUERY_PARAM_OBJECT, object); query.setParameter(QUERY_PARAM_OBJECT, object);
@ -641,11 +747,15 @@ public class PermissionManager implements Serializable {
return query.getSingleResult() > 0; return query.getSingleResult() > 0;
} }
private boolean existsInheritedPermission(final String privilege, private boolean existsInheritedPermission(
final String privilege,
final Role grantee, final Role grantee,
final CcmObject object) { final CcmObject object
) {
final TypedQuery<Long> query = entityManager.createNamedQuery( final TypedQuery<Long> query = entityManager.createNamedQuery(
"Permission.existsInheritedForPrivilegeRoleObject", Long.class); "Permission.existsInheritedForPrivilegeRoleObject",
Long.class
);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege); query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee); query.setParameter(QUERY_PARAM_GRANTEE, grantee);
query.setParameter(QUERY_PARAM_OBJECT, object); query.setParameter(QUERY_PARAM_OBJECT, object);
@ -663,10 +773,14 @@ public class PermissionManager implements Serializable {
* @return {@code true} if there is a matching permission, {@code false} if * @return {@code true} if there is a matching permission, {@code false} if
* not. * not.
*/ */
private boolean existsPermission(final String privilege, private boolean existsPermission(
final Role grantee) { final String privilege,
final Role grantee
) {
final TypedQuery<Long> query = entityManager.createNamedQuery( final TypedQuery<Long> query = entityManager.createNamedQuery(
"Permission.existsForPrivilegeAndRole", Long.class); "Permission.existsForPrivilegeAndRole",
Long.class
);
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege); query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
query.setParameter(QUERY_PARAM_GRANTEE, grantee); query.setParameter(QUERY_PARAM_GRANTEE, grantee);

View File

@ -57,32 +57,36 @@ class FreemarkerConfigurationProvider {
private final Map<ThemeInfo, Configuration> configurations = new HashMap<>(); private final Map<ThemeInfo, Configuration> configurations = new HashMap<>();
protected Configuration getConfiguration(final ThemeInfo forTheme) { protected Configuration getConfiguration(final ThemeInfo forTheme) {
if (configurations.containsKey(forTheme)) { if (configurations.containsKey(forTheme)) {
return configurations.get(forTheme); return configurations.get(forTheme);
} else { } else {
final Configuration configuration = new Configuration( final Configuration configuration = new Configuration(
Configuration.VERSION_2_3_27); Configuration.VERSION_2_3_27
);
configuration.setDefaultEncoding("UTF-8"); configuration.setDefaultEncoding("UTF-8");
configuration configuration
.setTemplateExceptionHandler( .setTemplateExceptionHandler(
TemplateExceptionHandler.RETHROW_HANDLER); TemplateExceptionHandler.DEBUG_HANDLER
configuration.setLogTemplateExceptions(false); );
configuration.setLogTemplateExceptions(true);
configuration.setWrapUncheckedExceptions(false); configuration.setWrapUncheckedExceptions(false);
configuration.setLocalizedLookup(false); configuration.setLocalizedLookup(false);
configuration.setTemplateLoader( configuration.setTemplateLoader(
new MultiTemplateLoader(new TemplateLoader[]{ new MultiTemplateLoader(
new TemplateLoader[]{
// For for files from themes // For for files from themes
new CcmTemplateLoader(forTheme), new CcmTemplateLoader(forTheme),
// Loader for MacroLibs provided by CCM modules // Loader for MacroLibs provided by CCM modules
new WebappTemplateLoader( new WebappTemplateLoader(
servletContext, "/themes/freemarker" servletContext, "/themes/freemarker"
), ),
new ClassTemplateLoader(getClass(), "/themes/freemarker") new ClassTemplateLoader(
}) getClass(),
"/themes/freemarker"
)
}
)
); );
configurations.put(forTheme, configuration); configurations.put(forTheme, configuration);
@ -103,7 +107,8 @@ class FreemarkerConfigurationProvider {
public Object findTemplateSource(final String name) throws IOException { public Object findTemplateSource(final String name) throws IOException {
final Optional<InputStream> source = themes.getFileFromTheme( final Optional<InputStream> source = themes.getFileFromTheme(
fromTheme, name); fromTheme, name
);
if (source.isPresent()) { if (source.isPresent()) {
return source.get(); return source.get();
} else { } else {
@ -118,9 +123,10 @@ class FreemarkerConfigurationProvider {
} }
@Override @Override
public Reader getReader(final Object templateSource, public Reader getReader(
final String encoding) throws IOException { final Object templateSource,
final String encoding
) throws IOException {
final InputStream inputStream = (InputStream) templateSource; final InputStream inputStream = (InputStream) templateSource;
return new InputStreamReader(inputStream, encoding); return new InputStreamReader(inputStream, encoding);
} }
@ -128,7 +134,6 @@ class FreemarkerConfigurationProvider {
@Override @Override
public void closeTemplateSource(final Object templateSource) public void closeTemplateSource(final Object templateSource)
throws IOException { throws IOException {
final InputStream inputStream = (InputStream) templateSource; final InputStream inputStream = (InputStream) templateSource;
inputStream.close(); inputStream.close();
} }

View File

@ -217,7 +217,9 @@ public class ImportExportTaskManager {
* @see CompletionStage#handle(java.util.function.BiFunction) * @see CompletionStage#handle(java.util.function.BiFunction)
*/ */
private Object handleExportTaskResult( private Object handleExportTaskResult(
final ExportTask task, final Throwable ex, final ExportTaskStatus status final ExportTask task,
final Throwable ex,
final ExportTaskStatus status
) { ) {
if (ex == null) { if (ex == null) {
status.setStatus(ImExportTaskStatus.FINISHED); status.setStatus(ImExportTaskStatus.FINISHED);