From b39aa8152f6e894ba3b12604743f3431c49dda4c Mon Sep 17 00:00:00 2001 From: jensp Date: Thu, 24 Nov 2016 17:59:40 +0000 Subject: [PATCH] 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 --- .../cms/ui/type/ContentTypeAdminPane.java | 5 - .../cms/ui/type/TypePermissionsTable.java | 254 ++++++++---------- .../type/TypePermissionsTableController.java | 103 +++++++ .../ui/workflow/TaskFinishFormController.java | 58 ++++ .../contentsection/ContentTypeManager.java | 40 ++- .../privileges/TypePrivileges.java | 33 +++ .../libreccm/security/PermissionChecker.java | 116 +++++++- 7 files changed, 452 insertions(+), 157 deletions(-) create mode 100644 ccm-cms/src/main/java/com/arsdigita/cms/ui/type/TypePermissionsTableController.java create mode 100644 ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskFinishFormController.java create mode 100644 ccm-cms/src/main/java/org/librecms/contentsection/privileges/TypePrivileges.java diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/ContentTypeAdminPane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/ContentTypeAdminPane.java index 029f34598..13a6a7a27 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/ContentTypeAdminPane.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/ContentTypeAdminPane.java @@ -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 diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/TypePermissionsTable.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/TypePermissionsTable.java index 24d726a2f..94984c170 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/TypePermissionsTable.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/TypePermissionsTable.java @@ -5,34 +5,47 @@ 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... - * + * * @author Jens Pelzetter */ public class TypePermissionsTable extends Table implements TableActionListener { @@ -49,28 +62,28 @@ public class TypePermissionsTable extends Table implements TableActionListener { this.type = type; setEmptyView(new Label(new GlobalizedMessage( - "cms.ui.type.permissions.none", - CmsConstants.CMS_BUNDLE))); + "cms.ui.type.permissions.none", + CmsConstants.CMS_BUNDLE))); TableColumnModel columnModel = getColumnModel(); columnModel.add(new TableColumn( - 0, - new GlobalizedMessage("cms.ui.type.permissions.role", - CmsConstants.CMS_BUNDLE).localize(), - TABLE_COL_ROLE)); + 0, + new GlobalizedMessage("cms.ui.type.permissions.role", + CmsConstants.CMS_BUNDLE).localize(), + TABLE_COL_ROLE)); columnModel.add(new TableColumn( - 1, - new GlobalizedMessage("cms.ui.type.permissions_can_use", - CmsConstants.CMS_BUNDLE).localize(), - TABLE_COL_CAN_USE)); + 1, + new GlobalizedMessage("cms.ui.type.permissions_can_use", + CmsConstants.CMS_BUNDLE).localize(), + TABLE_COL_CAN_USE)); columnModel.add(new TableColumn( - 2, - new GlobalizedMessage("cms.ui.type.permission.action", - CmsConstants.CMS_BUNDLE).localize(), - TABLE_COL_ACTION)); + 2, + new GlobalizedMessage("cms.ui.type.permission.action", + CmsConstants.CMS_BUNDLE).localize(), + TABLE_COL_ACTION)); setModelBuilder(new TypePermissionsTableModelBuilder()); @@ -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())); + 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); } } @@ -122,8 +120,8 @@ public class TypePermissionsTable extends Table implements TableActionListener { } private class TypePermissionsTableModelBuilder - extends LockableImpl - implements TableModelBuilder { + extends LockableImpl + implements TableModelBuilder { public TypePermissionsTableModelBuilder() { } @@ -133,95 +131,73 @@ 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 roles; - private ContentType contentType; - private List permissions; + private final Iterator> iterator; + private RowData 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> 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() { - return false; -// if (roles == null) { -// return false; -// } else { -// return roles.next(); -// } + if (iterator.hasNext()) { + currentRow = iterator.next(); + return true; + } else { + return false; + } } @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 - extends LockableImpl - implements TableCellRenderer { + extends LockableImpl + implements TableCellRenderer { @Override public Component getComponent(Table table, @@ -231,58 +207,62 @@ 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 - extends LockableImpl - implements TableCellRenderer { + extends LockableImpl + 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 { + 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; } + } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/TypePermissionsTableController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/TypePermissionsTableController.java new file mode 100644 index 000000000..3ce9c3a63 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/TypePermissionsTableController.java @@ -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 Jens Pelzetter + */ +@RequestScoped +public class TypePermissionsTableController { + + @Inject + private PermissionChecker permissionChecker; + + @Inject + private PermissionManager permissionManager; + + @Inject + private ContentTypeRepository typeRepo; + + @Transactional(Transactional.TxType.REQUIRED) + public List> 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> retrieveTypePermissions( + final long typeId, final ContentSection section) { + final ContentType type = typeRepo.findById(typeId); + + final List roles = section.getRoles(); + + return roles.stream() + .map(role -> retrievePermissionsForRole(type, role)) + .collect(Collectors.toList()); + } + + private RowData retrievePermissionsForRole(final ContentType type, + final Role role) { + final RowData 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); + } + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskFinishFormController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskFinishFormController.java new file mode 100644 index 000000000..5f459f6da --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskFinishFormController.java @@ -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 Jens Pelzetter + */ +@RequestScoped +public class TaskFinishFormController { + + @Inject + private AssignableTaskManager taskManager; + + @Inject + private Shiro shiro; + + @Transactional(Transactional.TxType.REQUIRED) + public List findEnabledTasks(final Workflow workflow) { + final User user = shiro.getUser(); + final List roles = user.getRoleMemberships().stream() + .map(membership -> membership.getRole()) + .collect(Collectors.toList()); + + return taskManager.findAssignedTasks(workflow, roles); + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentTypeManager.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentTypeManager.java index a58010cf5..bb7333643 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentTypeManager.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentTypeManager.java @@ -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; @@ -41,6 +42,9 @@ public class ContentTypeManager { @Inject private ContentTypeRepository typeRepo; + + @Inject + private PermissionManager permissionManager; @SuppressWarnings("unchecked") public Class classNameToClass(final String className) { @@ -49,10 +53,10 @@ public class ContentTypeManager { clazz = Class.forName(className); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException(String.format( - "No class with the name \"%s\" exists.", className), - ex); + "No class with the name \"%s\" exists.", className), + ex); } - + if (clazz.isAssignableFrom(ContentItem.class)) { return (Class) clazz; } else { @@ -60,7 +64,7 @@ public class ContentTypeManager { "Class \"%s\" is not a content type.", className)); } } - + @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired public void setDefaultLifecycle( @@ -81,8 +85,28 @@ public class ContentTypeManager { final WorkflowTemplate template) { type.setDefaultWorkflow(template); - + 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); + } + } diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/privileges/TypePrivileges.java b/ccm-cms/src/main/java/org/librecms/contentsection/privileges/TypePrivileges.java new file mode 100644 index 000000000..5b40d0eef --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/contentsection/privileges/TypePrivileges.java @@ -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 Jens Pelzetter + */ +public final class TypePrivileges { + + public static final String USE_TYPE = "use_type"; + + private TypePrivileges() { + //Nothing + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/security/PermissionChecker.java b/ccm-core/src/main/java/org/libreccm/security/PermissionChecker.java index 5a8a178e3..8de073796 100644 --- a/ccm-core/src/main/java/org/libreccm/security/PermissionChecker.java +++ b/ccm-core/src/main/java/org/libreccm/security/PermissionChecker.java @@ -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 Jens Pelzetter */ @@ -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 = 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 = 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