CCM NG/ccm-cms: Support for the TYPE_USE privilege.

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4455 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2016-11-24 17:59:40 +00:00
parent 582bcab967
commit b39aa8152f
7 changed files with 452 additions and 157 deletions

View File

@ -23,11 +23,9 @@ import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.GridPanel;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSubmissionListener;
import com.arsdigita.cms.CMS;
@ -40,11 +38,9 @@ import com.arsdigita.cms.ui.BaseDeleteForm;
import com.arsdigita.globalization.GlobalizedMessage;
//ToDo insert later import com.arsdigita.cms.ui.ContentSectionPage;
import org.libreccm.core.CcmObject;
import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
import com.arsdigita.toolbox.ui.ActionGroup;
import com.arsdigita.toolbox.ui.Section;
import com.arsdigita.toolbox.ui.Cancellable;
import org.apache.log4j.Logger;
@ -53,7 +49,6 @@ import org.librecms.CmsConstants;
import org.librecms.contentsection.ContentSectionManager;
import org.librecms.contentsection.ContentTypeManager;
import java.math.BigDecimal;
/**
* This class contains the split pane for the ContentType administration

View File

@ -5,30 +5,43 @@ import com.arsdigita.bebop.ControlLink;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.Text;
import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.table.RowData;
import com.arsdigita.bebop.table.TableCellRenderer;
import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.table.TableColumnModel;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.table.TableModelBuilder;
import com.arsdigita.cms.CMS;
import org.librecms.contentsection.ContentType;
import com.arsdigita.cms.dispatcher.Utilities;
import com.arsdigita.cms.ui.ContentSectionRequestLocal;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.ui.admin.GlobalizationUtil;
import org.libreccm.security.Party;
import org.libreccm.security.Role;
import com.arsdigita.util.LockableImpl;
import java.awt.image.Kernel;
import java.util.List;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.security.Permission;
import org.libreccm.security.PermissionChecker;
import org.libreccm.security.RoleRepository;
import org.librecms.CmsConstants;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.privileges.AdminPrivileges;
import sun.security.util.SecurityConstants;
import java.util.Iterator;
/**
*
* ToDo, maybe not needed anymore...
@ -83,36 +96,21 @@ public class TypePermissionsTable extends Table implements TableActionListener {
@Override
public void cellSelected(final TableActionEvent event) {
PageState state = event.getPageState();
final PageState state = event.getPageState();
final TableColumn column = getColumnModel().get(event.getColumn());
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final RoleRepository roleRepo = cdiUtil.findBean(RoleRepository.class);
final TypePermissionsTableController controller = cdiUtil.findBean(
TypePermissionsTableController.class);
if (TABLE_COL_ACTION.equals(column.getHeaderKey().toString())) {
final Role role = roleRepo.findById(Long.parseLong(
event.getRowKey().toString()));
ContentType contentType = getType().getContentType(state);
// ToDo
// ObjectPermissionCollection permissions
// = PermissionService.
// getDirectGrantedPermissions(contentType.getOID());
//
// if ((permissions.size() == 0)) {
// role.grantPermission(contentType,
// PrivilegeDescriptor.get(
// com.arsdigita.cms.SecurityManager.CMS_NEW_ITEM));
// } else if (!role.checkPermission(contentType, PrivilegeDescriptor.
// get(com.arsdigita.cms.SecurityManager.CMS_NEW_ITEM))) {
// role.grantPermission(contentType,
// PrivilegeDescriptor.get(
// com.arsdigita.cms.SecurityManager.CMS_NEW_ITEM));
// } else {
// role.revokePermission(contentType,
// PrivilegeDescriptor.get(
// com.arsdigita.cms.SecurityManager.CMS_NEW_ITEM));
// }
controller.toggleTypeUsePermission(contentType, role);
}
}
@ -133,90 +131,68 @@ public class TypePermissionsTable extends Table implements TableActionListener {
table.getRowSelectionModel().clearSelection(state);
return new TypePermissionsTableModel(table, state);
}
}
private class TypePermissionsTableModel implements TableModel {
private Table table;
private List<Role> roles;
private ContentType contentType;
private List<Permission> permissions;
private final Iterator<RowData<Long>> iterator;
private RowData<Long> currentRow;
public TypePermissionsTableModel(final Table table,
final PageState state) {
this.table = table;
contentType
= ((TypePermissionsTable) table).getType().getContentType(
state);
final ContentType contentType = ((TypePermissionsTable) table)
.getType()
.getContentType(state);
roles = CMS.getContext().getContentSection().getRoles();
// permissions
// = PermissionService.
// getDirectGrantedPermissions(contentType.getOID());
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final TypePermissionsTableController controller = cdiUtil.findBean(
TypePermissionsTableController.class);
final ContentSection section = CMS.getContext().getContentSection();
final List<RowData<Long>> rows = controller.retrieveTypePermissions(
contentType, section);
iterator = rows.iterator();
}
@Override
public int getColumnCount() {
if (roles == null) {
return 0;
} else {
return (int) roles.size();
}
return 3;
}
@Override
public boolean nextRow() {
if (iterator.hasNext()) {
currentRow = iterator.next();
return true;
} else {
return false;
// if (roles == null) {
// return false;
// } else {
// return roles.next();
// }
}
}
@Override
public Object getElementAt(int columnIndex) {
// switch (columnIndex) {
// case 0:
// return roles.getRole().getName();
// case 1:
// if (permissions.isEmpty()) {
// return "cms.ui.type.permissions.can_use.yes";
// } else {
// if (roles.getRole().checkPermission(contentType,
// PrivilegeDescriptor.
// get(
// com.arsdigita.cms.SecurityManager.CMS_NEW_ITEM))) {
// return "cms.ui.type.permissions.can_use.yes";
// } else {
// return "cms.ui.type.permissions.can_use.no";
// }
// }
// case 2:
// if (permissions.size() == 0) {
// return "cms.ui.type.permissions.actions.restrict_to_this_role";
// } else {
// if (roles.getRole().checkPermission(contentType,
// PrivilegeDescriptor.
// get(
// com.arsdigita.cms.SecurityManager.CMS_NEW_ITEM))) {
// return "cms.ui.type.permissions.actions.revoke";
// } else {
// return "cms.ui.type.permissions.can_use.grant";
// }
// }
// default:
// return null;
// }
return null;
public Object getElementAt(final int columnIndex) {
switch (columnIndex) {
case 0:
return currentRow.getColData(0);
case 1:
return currentRow.getColData(1);
case 2:
if ("cms.ui.type.permissions.can_use.yes".equals(currentRow
.getColData(1))) {
return "cms.ui.type.permissions.actions.revoke";
} else {
return "cms.ui.type.permissions.can_use.grant";
}
default:
throw new IllegalArgumentException("Invalid column index.");
}
}
@Override
public Object getKeyAt(int columnIndex) {
// return roles.getRole().getID();
return null;
public Object getKeyAt(final int columnIndex) {
return currentRow.getRowKey();
}
}
private class RoleCellRenderer
@ -231,8 +207,9 @@ public class TypePermissionsTable extends Table implements TableActionListener {
Object key,
int row,
int column) {
return new Label(value.toString());
return new Text(value.toString());
}
}
private class CanUseCellRenderer
@ -240,49 +217,52 @@ public class TypePermissionsTable extends Table implements TableActionListener {
implements TableCellRenderer {
@Override
public Component getComponent(Table table,
PageState state,
Object value,
boolean isSelected,
Object key,
int row,
int column) {
return new Label(GlobalizationUtil.globalize(value.toString()));
public Component getComponent(final Table table,
final PageState state,
final Object value,
final boolean isSelected,
final Object key,
final int row,
final int column) {
return new Label(new GlobalizedMessage(value.toString(),
CmsConstants.CMS_BUNDLE));
}
}
private class ActionCellRenderer
extends LockableImpl
implements TableCellRenderer {
public Component getComponent(Table table,
PageState state,
Object value,
@Override
public Component getComponent(final Table table,
final PageState state,
final Object value,
boolean isSelected,
Object key,
int row,
int column) {
// com.arsdigita.cms.SecurityManager securityManager = Utilities.
// getSecurityManager(state);
// Party party = Kernel.getContext().getParty();
// if (party == null) {
// party = Kernel.getPublicUser();
// }
// if (securityManager.canAccess(party,
// SecurityConstants.CONTENT_TYPE_ADMIN)) {
// ControlLink link = new ControlLink((String) GlobalizationUtil.
// globalize(
// value.toString()).localize());
//
// return link;
// } else {
return new Label(value.toString());
// }
final Object key,
final int row,
final int column) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final PermissionChecker permissionChecker = cdiUtil.findBean(
PermissionChecker.class);
final ContentSection section = CMS.getContext().getContentSection();
if (permissionChecker.isPermitted(
AdminPrivileges.ADMINISTER_CONTENT_TYPES, section)) {
return new ControlLink(new Label(new GlobalizedMessage(
(String) value), CmsConstants.CMS_BUNDLE));
} else {
return new Text("");
}
}
}
private ContentTypeRequestLocal getType() {
return type;
}
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2016 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 com.arsdigita.cms.ui.type;
import org.librecms.contentsection.privileges.TypePrivileges;
import com.arsdigita.bebop.table.RowData;
import org.libreccm.security.PermissionChecker;
import org.libreccm.security.PermissionManager;
import org.libreccm.security.Role;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentType;
import org.librecms.contentsection.ContentTypeRepository;
import java.util.List;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class TypePermissionsTableController {
@Inject
private PermissionChecker permissionChecker;
@Inject
private PermissionManager permissionManager;
@Inject
private ContentTypeRepository typeRepo;
@Transactional(Transactional.TxType.REQUIRED)
public List<RowData<Long>> retrieveTypePermissions(
final ContentType type, final ContentSection section) {
//Ensure that we use a sane object for the type
return retrieveTypePermissions(type.getObjectId(), section);
}
@Transactional(Transactional.TxType.REQUIRED)
public List<RowData<Long>> retrieveTypePermissions(
final long typeId, final ContentSection section) {
final ContentType type = typeRepo.findById(typeId);
final List<Role> roles = section.getRoles();
return roles.stream()
.map(role -> retrievePermissionsForRole(type, role))
.collect(Collectors.toList());
}
private RowData<Long> retrievePermissionsForRole(final ContentType type,
final Role role) {
final RowData<Long> rowData = new RowData<>(2);
rowData.setRowKey(role.getRoleId());
rowData.setColData(0, role.getName());
if (permissionChecker.isPermitted(TypePrivileges.USE_TYPE, type)) {
rowData.setColData(1, "cms.ui.type.permissions.can_use.yes");
} else {
rowData.setColData(1, "cms.ui.type.permissions.can_use.no");
}
return rowData;
}
public void toggleTypeUsePermission(final ContentType type,
final Role role) {
if (permissionChecker.isPermitted(TypePrivileges.USE_TYPE, type, role)) {
permissionManager.revokePrivilege(TypePrivileges.USE_TYPE,
role,
type);
} else {
permissionManager.grantPrivilege(TypePrivileges.USE_TYPE,
role,
type);
}
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2016 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 com.arsdigita.cms.ui.workflow;
import org.libreccm.security.Role;
import org.libreccm.security.Shiro;
import org.libreccm.security.User;
import org.libreccm.workflow.AssignableTask;
import org.libreccm.workflow.AssignableTaskManager;
import org.libreccm.workflow.Workflow;
import java.util.List;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class TaskFinishFormController {
@Inject
private AssignableTaskManager taskManager;
@Inject
private Shiro shiro;
@Transactional(Transactional.TxType.REQUIRED)
public List<AssignableTask> findEnabledTasks(final Workflow workflow) {
final User user = shiro.getUser();
final List<Role> roles = user.getRoleMemberships().stream()
.map(membership -> membership.getRole())
.collect(Collectors.toList());
return taskManager.findAssignedTasks(workflow, roles);
}
}

View File

@ -18,15 +18,16 @@
*/
package org.librecms.contentsection;
import org.librecms.contentsection.privileges.TypePrivileges;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.PermissionManager;
import org.libreccm.security.RequiresPrivilege;
import org.libreccm.security.Role;
import org.libreccm.workflow.WorkflowTemplate;
import org.librecms.contentsection.privileges.AdminPrivileges;
import org.librecms.lifecycle.LifecycleDefinition;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
@ -42,6 +43,9 @@ public class ContentTypeManager {
@Inject
private ContentTypeRepository typeRepo;
@Inject
private PermissionManager permissionManager;
@SuppressWarnings("unchecked")
public Class<? extends ContentItem> classNameToClass(final String className) {
final Class<?> clazz;
@ -85,4 +89,24 @@ public class ContentTypeManager {
typeRepo.save(type);
}
@Transactional(Transactional.TxType.REQUIRED)
@AuthorizationRequired
public void grantUsageOfType(
@RequiresPrivilege(AdminPrivileges.ADMINISTER_CONTENT_TYPES)
final ContentType type,
final Role role) {
permissionManager.grantPrivilege(TypePrivileges.USE_TYPE, role, type);
}
@Transactional(Transactional.TxType.REQUIRED)
@AuthorizationRequired
public void denyUsageOnType(
@RequiresPrivilege(AdminPrivileges.ADMINISTER_CONTENT_TYPES)
final ContentType type,
final Role role) {
permissionManager.revokePrivilege(TypePrivileges.USE_TYPE, role, type);
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2016 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.contentsection.privileges;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public final class TypePrivileges {
public static final String USE_TYPE = "use_type";
private TypePrivileges() {
//Nothing
}
}

View File

@ -24,12 +24,15 @@ import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.subject.Subject;
import org.libreccm.core.CcmObject;
import java.util.Optional;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
* An utility class for checking permissions. Uses the current {@link Subject}
* as provided by the {@link Shiro} bean.
* as provided by the {@link Shiro} bean useless otherwise indicated.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@ -45,14 +48,17 @@ public class PermissionChecker {
@Inject
private Shiro shiro;
@Inject
private RoleRepository roleRepo;
/**
* Checks if the current subject has a permission granting the provided
* privilege.
* {@code privilege}.
*
* @param privilege The privilege granted by the permission.
*
* @return {@code true} if the current subject has as permission granting
* the provided {@code privilege}, {@code false} otherwise.
* @return {@code true} if the current subject has a permission granting the
* provided {@code privilege}, {@code false} otherwise.
*/
public boolean isPermitted(final String privilege) {
if (subject.isAuthenticated()) {
@ -63,16 +69,51 @@ public class PermissionChecker {
}
}
/**
* Check if the provided {@code role} has a permissions granting the
* provided {@code privilege}.
*
* @param privilege The privilege granted by the permission.
* @param role The role to check for a permission granting the
* {@code privilege}.
*
* @return {@code true} if the role has a permission granting the provided
* {@code privilege}, {@code false} otherwise.
*/
@Transactional(Transactional.TxType.REQUIRED)
public boolean isPermitted(final String privilege, final Role role) {
if (privilege == null || privilege.trim().isEmpty()) {
throw new IllegalArgumentException(
"Can't check permission null (or empty)");
}
if (role == null) {
throw new IllegalArgumentException(
"Can't check permission for role null.");
}
//Ensure that we have a none detached entity
final Role theRole = roleRepo.findById(role.getRoleId());
final Optional<Permission> permission = theRole.getPermissions()
.stream()
.filter(granted -> privilege.equals(granted.getGrantedPrivilege()))
.findFirst();
return permission.isPresent();
}
/**
* Checks if the current subject has a permission granting the provided
* privilege on the provided object or its parent object(s) if the object
* implements the {@link InheritsPermissions} interface.
* {@code privilege} on the provided {@code object} or its parent object(s)
* if the object implements the {@link InheritsPermissions} interface.
*
* @param privilege The granted privilege.
* @param object The object on which the privilege is granted.
*
* @return {@code true} if the there is a permission granting the provided
* {@code privilege} on the provided {@code subject}.
* {@code privilege} on the provided {@code object} to the current
* subject.
*/
public boolean isPermitted(final String privilege, final CcmObject object) {
final boolean result;
@ -98,6 +139,67 @@ public class PermissionChecker {
}
}
/**
* Checks if the provided {@code role} has a permission granting the
* provided {@code privilege} on the provided object or its parent object(s)
* if the object implements the {@link InheritsPermissions} interface.
*
* @param privilege The granted privilege.
* @param object The object on which the {@code privilege} is granted.
* @param role The role to check for a permission granting the
* {@code privilege}.
*
* @return {@code true} if the there is a permission granting the provided
* {@code privilege} on the provided {@code object} to the provided
* {@code role}.
*/
public boolean isPermitted(final String privilege,
final CcmObject object,
final Role role) {
if (privilege == null || privilege.trim().isEmpty()) {
throw new IllegalArgumentException(
"Can't check permission null (or empty)");
}
if (role == null) {
throw new IllegalArgumentException(
"Can't check permission for role null.");
}
if (object == null) {
throw new IllegalArgumentException(
"Can verify permissions for object null.");
}
final boolean result;
//Ensure that we have a none detached entity
final Role theRole = roleRepo.findById(role.getRoleId());
final Optional<Permission> permission = theRole.getPermissions()
.stream()
.filter(granted -> granted.getObject() != null)
.filter(granted -> object.equals(granted.getObject()))
.findFirst();
result = permission.isPresent();
if (result) {
return result;
} else if (object instanceof InheritsPermissions) {
if (((InheritsPermissions) object).getParent().isPresent()) {
return isPermitted(
privilege,
((InheritsPermissions) object).getParent().get(),
role);
} else {
return result;
}
} else {
return result;
}
}
/**
* Checks if the current subject has a permission granting the provided
* privilege. If the current subject does not have a permission granting the