modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/AuthorizedTableAction.java | 95 +++++++++ modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/RecordExtractor.java | 38 +++ modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/ResourceAuthorizedTableAction.java | 101 ++++++++++ modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/AuthorizationGWTService.java | 14 + modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupListView.java | 8 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java | 21 +- modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/AuthorizationGWTServiceImpl.java | 11 - modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties | 2 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java | 3 9 files changed, 287 insertions(+), 6 deletions(-)
New commits: commit 5422bf4365ea656d41399ec67a4c91cf573b9f0e Author: Jay Shaughnessy jshaughn@redhat.com Date: Thu Mar 31 16:50:13 2011 -0400
Button Enablement Work - Disable group Delete and New buttons for non inv-managers - Disable uninventory button for non-resource-delete users - updated text for delete perm on role detail page - Added some support for authorized button enablement (see AuthorizedTableAction) - Added an interface for record extraction (see RecordExtractor)
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/AuthorizedTableAction.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/AuthorizedTableAction.java new file mode 100644 index 0000000..710aa53 --- /dev/null +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/AuthorizedTableAction.java @@ -0,0 +1,95 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2009 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.enterprise.gui.coregui.client.components.table; + +import java.util.HashSet; +import java.util.Set; + +import com.smartgwt.client.widgets.grid.ListGridRecord; + +import org.rhq.core.domain.authz.Permission; +import org.rhq.enterprise.gui.coregui.client.PermissionsLoadedListener; +import org.rhq.enterprise.gui.coregui.client.PermissionsLoader; + +/** + * This class allows for TableAction (ie. Button) enablement based on row selection and global perm authorization. + * + * For Resource Perm authorization see {@link ResourceAuthorizedTableAction}. + * + * @author Jay Shaughnessy + */ +public abstract class AuthorizedTableAction extends AbstractTableAction { + + Table<?> table; + + HashSet<Permission> globalPermissions = new HashSet<Permission>(); + + Boolean isGlobalAuthorized; + + protected AuthorizedTableAction(Table<?> table, Permission... permissions) { + this(table, TableActionEnablement.ALWAYS, permissions); + } + + protected AuthorizedTableAction(Table<?> table, TableActionEnablement enablement, Permission... permissions) { + super(enablement); + + this.table = table; + + for (Permission p : permissions) { + switch (p.getTarget()) { + case GLOBAL: + globalPermissions.add(p); + break; + case RESOURCE: + throw new IllegalArgumentException("Does not support Resource permissions"); + } + } + + if (globalPermissions.isEmpty()) { + isGlobalAuthorized = Boolean.TRUE; + } + } + + @Override + public boolean isEnabled(ListGridRecord[] selection) { + if (!super.isEnabled(selection)) { + return false; + } + + if (null == isGlobalAuthorized) { + new PermissionsLoader().loadExplicitGlobalPermissions(new PermissionsLoadedListener() { + + public void onPermissionsLoaded(Set<Permission> grantedPermissions) { + for (Permission requiredPermission : globalPermissions) { + if (!grantedPermissions.contains(requiredPermission)) { + return; + } + } + isGlobalAuthorized = true; + table.refreshTableInfo(); + } + }); + + return false; + } + + return isGlobalAuthorized; + } +} diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/RecordExtractor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/RecordExtractor.java new file mode 100644 index 0000000..1fe84d0 --- /dev/null +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/RecordExtractor.java @@ -0,0 +1,38 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2009 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.enterprise.gui.coregui.client.components.table; + +import java.util.Collection; + +import com.smartgwt.client.data.Record; + +/** + * Typically used for anaonymous class definition for extracting any data from a set of Records, typically + * ListGridRecords. For example, a utility that needs the resource ids extracted from the record set's attributes + * but does not know what the attributes are, could be passed a RecordExtractor. + * + * @author Jay Shaughnessy + * + */ +public interface RecordExtractor<T extends Object> { + + Collection<T> extract(Record[] records); + +} diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/ResourceAuthorizedTableAction.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/ResourceAuthorizedTableAction.java new file mode 100644 index 0000000..8931446 --- /dev/null +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/ResourceAuthorizedTableAction.java @@ -0,0 +1,101 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2009 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.enterprise.gui.coregui.client.components.table; + +import java.util.Collection; + +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.smartgwt.client.widgets.grid.ListGridRecord; + +import org.rhq.core.domain.authz.Permission; +import org.rhq.core.domain.authz.Permission.Target; +import org.rhq.enterprise.gui.coregui.client.CoreGUI; +import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; + +/** + * This class allows for TableAction (ie. Button) enablement based on row selection and resource perm authorization + * on the selected rows. If possible it is recommended that the table be built using composites that include the + * resource permission information already, as performance will be better. This approach will require an async + * authz call to the server on each refresh of the TableActions (i.e. each time selection changes in the Table). + * + * For Global Perm authorization see {@link AuthorizedTableAction}. + * + * TODO: This class has yet to be tested. + * + * @author Jay Shaughnessy + */ +public abstract class ResourceAuthorizedTableAction extends AbstractTableAction { + + Table<?> table; + Permission requiredPermission; + RecordExtractor<Integer> extractor; + + Boolean isAuthorized; + + protected ResourceAuthorizedTableAction(Table<?> table, Permission requiredPermission, + RecordExtractor<Integer> extractor) { + this(table, TableActionEnablement.ALWAYS, requiredPermission, extractor); + } + + protected ResourceAuthorizedTableAction(Table<?> table, TableActionEnablement enablement, + Permission requiredPermission, RecordExtractor<Integer> extractor) { + super(enablement); + + this.table = table; + this.requiredPermission = requiredPermission; + this.extractor = extractor; + + if (Target.RESOURCE != this.requiredPermission.getTarget()) { + throw new IllegalArgumentException("Does not support Global permission"); + } + } + + @Override + public boolean isEnabled(ListGridRecord[] selection) { + // first make sure row selection enablement passes + if (!super.isEnabled(selection)) { + return false; + } + + // if we've performed the required auth check, return the result and reset. + if (null != isAuthorized) { + boolean result = isAuthorized; + isAuthorized = null; + return result; + } + + // otherwise, kick off the async auth check. return false initially and update when the async call returns + Collection<Integer> resourceIds = extractor.extract(selection); + GWTServiceLookup.getAuthorizationService().hasResourcePermission(requiredPermission, resourceIds, + new AsyncCallback<Boolean>() { + public void onFailure(Throwable caught) { + CoreGUI.getErrorHandler().handleError("", caught); + } + + public void onSuccess(Boolean result) { + isAuthorized = result; + table.refreshTableInfo(); + } + + }); + + return false; + } +} diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/AuthorizationGWTService.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/AuthorizationGWTService.java index 249a655..3d14c3a 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/AuthorizationGWTService.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/gwt/AuthorizationGWTService.java @@ -18,6 +18,7 @@ */ package org.rhq.enterprise.gui.coregui.client.gwt;
+import java.util.Collection; import java.util.Set;
import com.google.gwt.user.client.rpc.RemoteService; @@ -72,4 +73,17 @@ public interface AuthorizationGWTService extends RemoteService { */ Set<Permission> getExplicitGlobalPermissions() throws RuntimeException;
+ /** + * Returns true if the current user possesses either: 1) the specified resource permission for *all* of the + * specified resources, or 2) the global MANAGE_INVENTORY permission which, by definition, gives full access to the + * inventory (all resources and all groups) NOTE: The size of the collection must be less than or equal to 1000 (due + * to an Oracle limitation). + * + * @param permission a resource permission (i.e. permission.getTarget() == Permission.Target.RESOURCE) + * @param resourceIds the ids of some Resources to check permissions against (size of collection must be <= 1000) + * + * @return true if the current user possesses the specified resource permission for the specified resource + */ + boolean hasResourcePermission(Permission permission, Collection<Integer> resourceIds); + } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupListView.java index 8ed410d..066b4a2 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupListView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupListView.java @@ -40,12 +40,14 @@ import com.smartgwt.client.widgets.grid.ListGrid; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord;
+import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.resource.group.GroupCategory; import org.rhq.core.domain.search.SearchSubsystem; import org.rhq.enterprise.gui.coregui.client.CoreGUI; import org.rhq.enterprise.gui.coregui.client.ImageManager; import org.rhq.enterprise.gui.coregui.client.LinkManager; import org.rhq.enterprise.gui.coregui.client.components.table.AbstractTableAction; +import org.rhq.enterprise.gui.coregui.client.components.table.AuthorizedTableAction; import org.rhq.enterprise.gui.coregui.client.components.table.Table; import org.rhq.enterprise.gui.coregui.client.components.table.TableActionEnablement; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; @@ -169,7 +171,8 @@ public class ResourceGroupListView extends Table<ResourceGroupCompositeDataSourc
if (this.showDeleteButton) { addTableAction(extendLocatorId("Delete"), MSG.common_button_delete(), MSG.common_msg_areYouSure(), - new AbstractTableAction(TableActionEnablement.ANY) { + new AuthorizedTableAction(this, TableActionEnablement.ANY, Permission.MANAGE_INVENTORY) { + public void executeAction(ListGridRecord[] selections, Object actionValue) { int[] groupIds = new int[selections.length]; int index = 0; @@ -195,7 +198,8 @@ public class ResourceGroupListView extends Table<ResourceGroupCompositeDataSourc }
if (this.showNewButton) { - addTableAction(extendLocatorId("New"), MSG.common_button_new(), new AbstractTableAction() { + addTableAction(extendLocatorId("New"), MSG.common_button_new(), new AuthorizedTableAction(this, + Permission.MANAGE_INVENTORY) { public void executeAction(ListGridRecord[] selection, Object actionValue) { new GroupCreateWizard(ResourceGroupListView.this).startWizard(); } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java index 27e67d7..32a6227 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java @@ -26,10 +26,12 @@ import static org.rhq.enterprise.gui.coregui.client.inventory.resource.ResourceD import static org.rhq.enterprise.gui.coregui.client.inventory.resource.ResourceDataSourceField.TYPE;
import java.util.ArrayList; +import java.util.Collection; import java.util.List;
import com.google.gwt.user.client.rpc.AsyncCallback; import com.smartgwt.client.data.Criteria; +import com.smartgwt.client.data.Record; import com.smartgwt.client.data.SortSpecifier; import com.smartgwt.client.types.Alignment; import com.smartgwt.client.types.ListGridFieldType; @@ -41,13 +43,15 @@ import com.smartgwt.client.widgets.grid.ListGrid; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord;
+import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.criteria.ResourceCriteria; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.core.domain.search.SearchSubsystem; import org.rhq.enterprise.gui.coregui.client.CoreGUI; import org.rhq.enterprise.gui.coregui.client.LinkManager; -import org.rhq.enterprise.gui.coregui.client.components.table.AbstractTableAction; +import org.rhq.enterprise.gui.coregui.client.components.table.RecordExtractor; +import org.rhq.enterprise.gui.coregui.client.components.table.ResourceAuthorizedTableAction; import org.rhq.enterprise.gui.coregui.client.components.table.ResourceCategoryCellFormatter; import org.rhq.enterprise.gui.coregui.client.components.table.Table; import org.rhq.enterprise.gui.coregui.client.components.table.TableActionEnablement; @@ -100,6 +104,7 @@ public class ResourceSearchView extends Table { * * @param headerIcons 24x24 icon(s) to be displayed in the header */ + @SuppressWarnings("unchecked") public ResourceSearchView(String locatorId, Criteria criteria, String title, SortSpecifier[] sortSpecifier, String[] excludeFields, String... headerIcons) { super(locatorId, title, criteria, sortSpecifier, excludeFields); @@ -177,7 +182,19 @@ public class ResourceSearchView extends Table { categoryField, availabilityField);
addTableAction(extendLocatorId("Uninventory"), MSG.common_button_uninventory(), MSG - .view_inventory_resources_uninventoryConfirm(), new AbstractTableAction(TableActionEnablement.ANY) { + .view_inventory_resources_uninventoryConfirm(), new ResourceAuthorizedTableAction(ResourceSearchView.this, + TableActionEnablement.ANY, Permission.DELETE_RESOURCE, new RecordExtractor<Integer>() { + + public Collection<Integer> extract(Record[] records) { + List<Integer> result = new ArrayList<Integer>(records.length); + for (Record record : records) { + result.add(record.getAttributeAsInt("id")); + } + + return result; + } + }) { + public void executeAction(ListGridRecord[] selection, Object actionValue) { int[] resourceIds = TableUtility.getIds(selection); ResourceGWTServiceAsync resourceManager = GWTServiceLookup.getResourceService(); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/AuthorizationGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/AuthorizationGWTServiceImpl.java index bf56c99..d31b5d8 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/AuthorizationGWTServiceImpl.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/AuthorizationGWTServiceImpl.java @@ -18,11 +18,11 @@ */ package org.rhq.enterprise.gui.coregui.server.gwt;
+import java.util.Collection; import java.util.HashSet; import java.util.Set;
import org.rhq.core.domain.authz.Permission; -import org.rhq.core.util.exception.ThrowableUtil; import org.rhq.enterprise.gui.coregui.client.gwt.AuthorizationGWTService; import org.rhq.enterprise.gui.coregui.server.util.SerialUtility; import org.rhq.enterprise.server.authz.AuthorizationManagerLocal; @@ -83,4 +83,13 @@ public class AuthorizationGWTServiceImpl extends AbstractGWTServiceImpl implemen } }
+ public boolean hasResourcePermission(Permission permission, Collection<Integer> resourceIds) { + try { + boolean result = authorizationManager.hasResourcePermission(getSessionSubject(), permission, resourceIds); + return result; + } catch (Throwable t) { + throw getExceptionToThrowToClient(t); + } + } + } diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties index 1867bf7..26b3bf0 100644 --- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties +++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties @@ -702,7 +702,7 @@ view_adminRoles_permissions_permReadDesc_createChildResources = (IMPLIED) view c view_adminRoles_permissions_permWriteDesc_createChildResources = create new child Resources (for child Resources of types that are creatable) view_adminRoles_permissions_perm_deleteChildResources = Delete Child Resources view_adminRoles_permissions_permReadDesc_deleteChildResources = (IMPLIED) view child Resource deletion history -view_adminRoles_permissions_permWriteDesc_deleteChildResources = delete child Resources (for child Resources of types that are deletable) +view_adminRoles_permissions_permWriteDesc_deleteChildResources = uninventory resources; delete Resources (for Resources of types that are deletable)
# Administration/Topology/RemoteAgentInstall/# #-------------------------------- diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java index 30c2334..fdfb2d1 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java @@ -267,6 +267,9 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage }
// make sure the user is authorized to delete this resource (which implies you can delete all its children) + // TODO: There is a pretty good argument for this being replaced with MANAGE_INVENTORY. It takes an + // inventory manager to import resources, so why not to remove them? But, since no one has complained + // we're timid about making a change that may hamstring existing setups. if (!authorizationManager.hasResourcePermission(user, Permission.DELETE_RESOURCE, resourceId)) { throw new PermissionException("You do not have permission to uninventory resource [" + resourceId + "]"); }