modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java | 2 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java | 3 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UserEditView.java | 6 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersDataSource.java | 4 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java | 5 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/definitions/AbstractAlertDefinitionsView.java | 13 + modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/definitions/GeneralPropertiesAlertDefinitionForm.java | 4 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentListView.java | 11 + modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java | 7 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationListView.java | 16 +- modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java | 11 - modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java | 5 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundlesListView.java | 11 + modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/revert/GetRevertInfoStep.java | 16 +- modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/tree/BundleTreeDataSource.java | 10 - modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java | 5 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/EnhancedDynamicForm.java | 8 - modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/EscapedHtmlCellFormatter.java | 19 ++ modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/IconField.java | 73 ++++++++++ modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/TableSection.java | 14 + modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tree/EnhancedTreeNode.java | 6 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/recent/problems/ProblemResourcesPortlet.java | 6 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/util/MessagePortlet.java | 11 - modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/history/AbstractOperationHistoryDetailsView.java | 2 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/AbstractOperationScheduleDetailsView.java | 4 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/summary/AbstractActivityView.java | 2 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupTreeView.java | 10 - modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/AncestryUtil.java | 58 ++++--- modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java | 23 +-- modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTitleBar.java | 3 modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java | 8 - modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/StringUtility.java | 65 ++++++++ 32 files changed, 343 insertions(+), 98 deletions(-)
New commits: commit ce940eefcecc42c3a4c545dc17010d7773725a6c Author: Ian Springer ian.springer@redhat.com Date: Thu Mar 31 17:28:25 2011 -0400
...
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/StringUtility.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/StringUtility.java index 0c93099..e14b9db 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/StringUtility.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/StringUtility.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright 2011, Red Hat Middleware LLC, and individual contributors + * Copyright 2010-2011, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * @@ -19,6 +19,9 @@ */ package org.rhq.enterprise.gui.coregui.client.util;
+import java.util.ArrayList; +import java.util.List; + /** * A collection of utility methods for working with Strings. * @@ -27,6 +30,41 @@ package org.rhq.enterprise.gui.coregui.client.util; public class StringUtility {
/** + * Split a string on delimiter boundaries, and place each element into a List. + * + * @param s String to split up + * @param delim Delimiting token, ala StringTokenizer + * + * @return a List comprised of elements split by the tokenizing + */ + public static List<String> explode(String s, String delim) { + List<String> res = new ArrayList<String>(); + if (s == null) + return res; + + String[] tokens = s.split(delim); + for (String token : tokens) { + res.add(token); + } + + return res; + } + + // TODO: I18N. The logic here may need to be pluggable for different localizations. + public static String pluralize(String singularNoun) { + String pluralNoun; + if (singularNoun.endsWith("y") && !singularNoun.endsWith("ay") && !singularNoun.endsWith("ey") + && !singularNoun.endsWith("oy")) { + pluralNoun = singularNoun.substring(0, singularNoun.length() - 1) + "ies"; + } else if (!singularNoun.endsWith("s")) { + pluralNoun = singularNoun + "s"; + } else { + pluralNoun = singularNoun; + } + return pluralNoun; + } + + /** * Escapes HTML in a string to eliminate cross site scripting (XSS) vulnerabilities. Note, this impl is designed * to be highly efficient to minimize the impact on performance. *
commit 170b9a147fce855f8196a7e13803e5a0e3d2f7bb Author: Ian Springer ian.springer@redhat.com Date: Thu Mar 31 17:25:56 2011 -0400
escape or sanitize HTML in user-controlled text, which could be used for XSS attacks
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java index 58cde04..178acd0 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RoleEditView.java @@ -305,11 +305,13 @@ public class RoleEditView extends AbstractRecordEditor<RolesDataSource> implemen
TextItem nameItem = new TextItem(RolesDataSource.Field.NAME); nameItem.setShowTitle(true); + nameItem.setAttribute(EnhancedDynamicForm.OUTPUT_AS_HTML_ATTRIBUTE, true); items.add(nameItem);
TextItem descriptionItem = new TextItem(RolesDataSource.Field.DESCRIPTION); descriptionItem.setShowTitle(true); descriptionItem.setColSpan(form.getNumCols()); + descriptionItem.setAttribute(EnhancedDynamicForm.OUTPUT_AS_HTML_ATTRIBUTE, true); items.add(descriptionItem);
return items; diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java index 46fa148..6aaf418 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java @@ -34,6 +34,7 @@ import org.rhq.enterprise.gui.coregui.client.BookmarkableView; import org.rhq.enterprise.gui.coregui.client.PermissionsLoadedListener; import org.rhq.enterprise.gui.coregui.client.PermissionsLoader; import org.rhq.enterprise.gui.coregui.client.admin.AdministrationView; +import org.rhq.enterprise.gui.coregui.client.components.table.EscapedHtmlCellFormatter; import org.rhq.enterprise.gui.coregui.client.components.table.TableAction; import org.rhq.enterprise.gui.coregui.client.components.table.TableSection; import org.rhq.enterprise.gui.coregui.client.components.view.ViewName; @@ -62,6 +63,7 @@ public class RolesView extends TableSection<RolesDataSource> implements Bookmark final RolesDataSource datasource = RolesDataSource.getInstance(); setDataSource(datasource); setHeaderIcon(HEADER_ICON); + setEscapeHtmlInDetailsLinkColumn(true); }
@Override @@ -108,6 +110,7 @@ public class RolesView extends TableSection<RolesDataSource> implements Bookmark fields.add(nameField);
ListGridField descriptionField = new ListGridField(RolesDataSource.Field.DESCRIPTION); + descriptionField.setCellFormatter(new EscapedHtmlCellFormatter()); fields.add(descriptionField);
return fields; diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UserEditView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UserEditView.java index 4ce9950..ba10fef 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UserEditView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UserEditView.java @@ -137,6 +137,7 @@ public class UserEditView extends AbstractRecordEditor<UsersDataSource> { nameItem = new TextItem(UsersDataSource.Field.NAME); } else { nameItem = new StaticTextItem(UsersDataSource.Field.NAME); + ((StaticTextItem)nameItem).setOutputAsHTML(true); } items.add(nameItem);
@@ -167,20 +168,25 @@ public class UserEditView extends AbstractRecordEditor<UsersDataSource> {
TextItem firstNameItem = new TextItem(UsersDataSource.Field.FIRST_NAME); firstNameItem.setShowTitle(true); + firstNameItem.setAttribute(EnhancedDynamicForm.OUTPUT_AS_HTML_ATTRIBUTE, true); items.add(firstNameItem);
TextItem lastNameItem = new TextItem(UsersDataSource.Field.LAST_NAME); lastNameItem.setShowTitle(true); + lastNameItem.setAttribute(EnhancedDynamicForm.OUTPUT_AS_HTML_ATTRIBUTE, true); items.add(lastNameItem);
TextItem emailAddressItem = new TextItem(UsersDataSource.Field.EMAIL_ADDRESS); emailAddressItem.setShowTitle(true); + emailAddressItem.setAttribute(EnhancedDynamicForm.OUTPUT_AS_HTML_ATTRIBUTE, true); items.add(emailAddressItem);
TextItem phoneNumberItem = new TextItem(UsersDataSource.Field.PHONE_NUMBER); + phoneNumberItem.setAttribute(EnhancedDynamicForm.OUTPUT_AS_HTML_ATTRIBUTE, true); items.add(phoneNumberItem);
TextItem departmentItem = new TextItem(UsersDataSource.Field.DEPARTMENT); + departmentItem.setAttribute(EnhancedDynamicForm.OUTPUT_AS_HTML_ATTRIBUTE, true); items.add(departmentItem);
boolean userBeingEditedIsRhqadmin = (getRecordId() == SUBJECT_ID_RHQADMIN); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersDataSource.java index d6f536b..6bdf6a5 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersDataSource.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersDataSource.java @@ -107,7 +107,9 @@ public class UsersDataSource extends RPCDataSource<Subject, SubjectCriteria> { fields.add(idDataField);
DataSourceTextField usernameField = createTextField(Field.NAME, MSG.dataSource_users_field_name(), 3, 100, true); - + // Don't allow characters that could be used in HTML intended for an XSS attack. + RegExpValidator regExpValidator = new RegExpValidator("[^&<]*"); + usernameField.setValidators(regExpValidator); fields.add(usernameField);
DataSourceTextField ldapField = createBooleanField(Field.LDAP, MSG.dataSource_users_field_ldap(), true); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java index f124703..4fae91e 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java @@ -33,6 +33,7 @@ import org.rhq.core.domain.authz.Permission; import org.rhq.enterprise.gui.coregui.client.PermissionsLoadedListener; import org.rhq.enterprise.gui.coregui.client.PermissionsLoader; import org.rhq.enterprise.gui.coregui.client.admin.AdministrationView; +import org.rhq.enterprise.gui.coregui.client.components.table.EscapedHtmlCellFormatter; import org.rhq.enterprise.gui.coregui.client.components.table.TableAction; import org.rhq.enterprise.gui.coregui.client.components.table.TableSection; import org.rhq.enterprise.gui.coregui.client.components.view.ViewName; @@ -64,6 +65,7 @@ public class UsersView extends TableSection<UsersDataSource> {
setDataSource(dataSource); setHeaderIcon(HEADER_ICON); + setEscapeHtmlInDetailsLinkColumn(true);
fetchManageSecurityPermissionAsync(); } @@ -131,12 +133,15 @@ public class UsersView extends TableSection<UsersDataSource> { fields.add(ldapField);
ListGridField firstNameField = new ListGridField(UsersDataSource.Field.FIRST_NAME, 150); + firstNameField.setCellFormatter(new EscapedHtmlCellFormatter()); fields.add(firstNameField);
ListGridField lastNameField = new ListGridField(UsersDataSource.Field.LAST_NAME, 150); + lastNameField.setCellFormatter(new EscapedHtmlCellFormatter()); fields.add(lastNameField);
ListGridField departmentField = new ListGridField(UsersDataSource.Field.DEPARTMENT, 150); + departmentField.setCellFormatter(new EscapedHtmlCellFormatter()); fields.add(departmentField);
// TODO: instead of fetching roles, use a composite object that will pull the role count across the wire. diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/definitions/AbstractAlertDefinitionsView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/definitions/AbstractAlertDefinitionsView.java index 376d659..4d8b846 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/definitions/AbstractAlertDefinitionsView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/definitions/AbstractAlertDefinitionsView.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2005-2010 Red Hat, Inc. + * Copyright (C) 2005-2011 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -21,6 +21,7 @@ package org.rhq.enterprise.gui.coregui.client.alert.definitions; import com.google.gwt.user.client.rpc.AsyncCallback; import com.smartgwt.client.data.Criteria; import com.smartgwt.client.widgets.Canvas; +import com.smartgwt.client.widgets.grid.CellFormatter; import com.smartgwt.client.widgets.grid.ListGrid; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord; @@ -34,9 +35,11 @@ import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.util.PageList; import org.rhq.enterprise.gui.coregui.client.CoreGUI; import org.rhq.enterprise.gui.coregui.client.components.table.AbstractTableAction; +import org.rhq.enterprise.gui.coregui.client.components.table.EscapedHtmlCellFormatter; import org.rhq.enterprise.gui.coregui.client.components.table.TableActionEnablement; import org.rhq.enterprise.gui.coregui.client.components.table.TableSection; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
/** * Superclass to the different alert definition views. This should be subclassed @@ -48,6 +51,8 @@ public abstract class AbstractAlertDefinitionsView extends TableSection<Abstract
public AbstractAlertDefinitionsView(String locatorId, String tableTitle) { super(locatorId, tableTitle); + + setEscapeHtmlInDetailsLinkColumn(true); }
@Override @@ -66,6 +71,12 @@ public abstract class AbstractAlertDefinitionsView extends TableSection<Abstract listGrid.setFixedRecordHeights(false); //listGrid.getField("id").setWidth(55);
+ // name and description are user-editable, so escape HTML to prevent XSS attacks + ListGridField nameField = listGrid.getField(AbstractAlertDefinitionsDataSource.FIELD_NAME); + nameField.setCellFormatter(new EscapedHtmlCellFormatter()); + ListGridField descriptionField = listGrid.getField(AbstractAlertDefinitionsDataSource.FIELD_DESCRIPTION); + descriptionField.setCellFormatter(new EscapedHtmlCellFormatter()); + boolean permitted = isAllowedToModifyAlertDefinitions();
TableActionEnablement enablement = (permitted) ? TableActionEnablement.ALWAYS : TableActionEnablement.NEVER; diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/definitions/GeneralPropertiesAlertDefinitionForm.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/definitions/GeneralPropertiesAlertDefinitionForm.java index 90f09f4..7d6b0d5 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/definitions/GeneralPropertiesAlertDefinitionForm.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/definitions/GeneralPropertiesAlertDefinitionForm.java @@ -209,11 +209,15 @@ public class GeneralPropertiesAlertDefinitionForm extends LocatableDynamicForm i nameTextField.setWidth(300); nameTextField.setDefaultValue(""); nameStatic = new StaticTextItem("nameStatic", MSG.common_title_name()); + // name is user-editable, so escape HTML to prevent XSS attacks + nameStatic.setOutputAsHTML(true);
descriptionTextField = new TextAreaItem("description", MSG.common_title_description()); descriptionTextField.setWidth(300); descriptionTextField.setDefaultValue(""); descriptionStatic = new StaticTextItem("descriptionStatic", MSG.common_title_description()); + // description is user-editable, so escape HTML to prevent XSS attacks + descriptionStatic.setOutputAsHTML(true);
prioritySelection = new SelectItem("priority", MSG.view_alerts_field_priority()); LinkedHashMap<String, String> priorities = new LinkedHashMap<String, String>(3); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentListView.java index 42711b6..b2763d9 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentListView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentListView.java @@ -40,8 +40,10 @@ import org.rhq.enterprise.gui.coregui.client.CoreGUI; import org.rhq.enterprise.gui.coregui.client.ErrorMessageWindow; import org.rhq.enterprise.gui.coregui.client.LinkManager; import org.rhq.enterprise.gui.coregui.client.bundle.list.BundleVersionDataSource; +import org.rhq.enterprise.gui.coregui.client.components.table.EscapedHtmlCellFormatter; import org.rhq.enterprise.gui.coregui.client.components.table.Table; import org.rhq.enterprise.gui.coregui.client.components.table.TimestampCellFormatter; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
/** * @author Greg Hinkle @@ -76,16 +78,21 @@ public class BundleDeploymentListView extends Table<BundleDeploymentDataSource> // only users that are authorized can see deployments if (canManageBundles) { nameField.setCellFormatter(new CellFormatter() { - public String format(Object o, ListGridRecord record, int i, int i1) { + public String format(Object value, ListGridRecord record, int i, int i1) { return "<a href="" + LinkManager.getBundleDeploymentLink(record .getAttributeAsInt(BundleDeploymentDataSource.FIELD_BUNDLE_ID), record - .getAttributeAsInt(BundleDeploymentDataSource.FIELD_ID)) + "">" + String.valueOf(o) + .getAttributeAsInt(BundleDeploymentDataSource.FIELD_ID)) + "">" + + StringUtility.escapeHtml(String.valueOf(value)) + "</a>"; } }); + } else { + nameField.setCellFormatter(new EscapedHtmlCellFormatter()); }
+ descriptionField.setCellFormatter(new EscapedHtmlCellFormatter()); + bundleVersionField.setCellFormatter(new CellFormatter() { public String format(Object o, ListGridRecord record, int i, int i1) { return "<a href="" diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java index c00a454..62bf4ed 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java @@ -77,6 +77,7 @@ import org.rhq.enterprise.gui.coregui.client.components.tagging.TagEditorView; import org.rhq.enterprise.gui.coregui.client.components.tagging.TagsChangedCallback; import org.rhq.enterprise.gui.coregui.client.gwt.BundleGWTServiceAsync; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.message.Message; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableIButton; @@ -146,7 +147,7 @@ public class BundleDeploymentView extends LocatableVLayout implements Bookmarkab LinkItem bundleName = new LinkItem("bundle"); bundleName.setTitle(MSG.view_bundle_bundle()); bundleName.setValue(LinkManager.getBundleLink(bundle.getId())); - bundleName.setLinkTitle(bundle.getName()); + bundleName.setLinkTitle(StringUtility.escapeHtml(bundle.getName())); bundleName.setTarget("_self");
CanvasItem actionItem = new CanvasItem("actions"); @@ -172,14 +173,14 @@ public class BundleDeploymentView extends LocatableVLayout implements Bookmarkab LinkItem destinationGroup = new LinkItem("group"); destinationGroup.setTitle(MSG.common_title_resource_group()); destinationGroup.setValue(LinkManager.getResourceGroupLink(deployment.getDestination().getGroup().getId())); - destinationGroup.setLinkTitle(deployment.getDestination().getGroup().getName()); + destinationGroup.setLinkTitle(StringUtility.escapeHtml((deployment.getDestination().getGroup().getName()))); destinationGroup.setTarget("_self");
StaticTextItem path = new StaticTextItem("path", MSG.view_bundle_deployDir()); path.setValue(deployment.getDestination().getDeployDir());
StaticTextItem description = new StaticTextItem("description", MSG.common_title_description()); - description.setValue(deployment.getDescription()); + description.setValue(StringUtility.escapeHtml(deployment.getDescription()));
StaticTextItem status = new StaticTextItem("status", MSG.common_title_status()); status.setValue(deployment.getStatus().name()); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationListView.java index d3ca12c..bbd20f6 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationListView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationListView.java @@ -38,6 +38,7 @@ 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.Table; import org.rhq.enterprise.gui.coregui.client.components.table.TimestampCellFormatter; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
/** * @author Greg Hinkle @@ -77,24 +78,27 @@ public class BundleDestinationListView extends Table<BundleDestinationDataSource TimestampCellFormatter.prepareDateField(latestDeploymentDateField);
nameField.setCellFormatter(new CellFormatter() { - public String format(Object o, ListGridRecord listGridRecord, int i, int i1) { + public String format(Object value, ListGridRecord listGridRecord, int i, int i1) { Integer bundleId = listGridRecord.getAttributeAsInt(BundleDestinationDataSource.FIELD_BUNDLE_ID); Integer bundleDestId = listGridRecord.getAttributeAsInt(BundleDestinationDataSource.FIELD_ID); - return "<a href="" + LinkManager.getBundleDestinationLink(bundleId, bundleDestId) + "">" + o + "</a>"; + return "<a href="" + LinkManager.getBundleDestinationLink(bundleId, bundleDestId) + "">" + + StringUtility.escapeHtml(value.toString()) + "</a>"; } });
groupNameField.setCellFormatter(new CellFormatter() { - public String format(Object o, ListGridRecord listGridRecord, int i, int i1) { + public String format(Object value, ListGridRecord listGridRecord, int i, int i1) { Integer groupId = listGridRecord.getAttributeAsInt(BundleDestinationDataSource.FIELD_GROUP_ID); - return "<a href="" + LinkManager.getResourceGroupLink(groupId) + "">" + o + "</a>"; + return "<a href="" + LinkManager.getResourceGroupLink(groupId) + "">" + + StringUtility.escapeHtml(value.toString()) + "</a>"; } });
bundleNameField.setCellFormatter(new CellFormatter() { - public String format(Object o, ListGridRecord listGridRecord, int i, int i1) { + public String format(Object value, ListGridRecord listGridRecord, int i, int i1) { Integer bid = listGridRecord.getAttributeAsInt(BundleDestinationDataSource.FIELD_BUNDLE_ID); - return "<a href="" + LinkManager.getBundleLink(bid) + "">" + o + "</a>"; + return "<a href="" + LinkManager.getBundleLink(bid) + "">" + + StringUtility.escapeHtml(value.toString()) + "</a>"; } });
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java index da52896..0a805e0 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java @@ -57,6 +57,7 @@ import org.rhq.enterprise.gui.coregui.client.components.tagging.TagEditorView; import org.rhq.enterprise.gui.coregui.client.components.tagging.TagsChangedCallback; import org.rhq.enterprise.gui.coregui.client.gwt.BundleGWTServiceAsync; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.message.Message; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableIButton; @@ -89,10 +90,10 @@ public class BundleDestinationView extends LocatableVLayout implements Bookmarka this.bundle = bundleDestination.getBundle();
BackButton backButton = new BackButton(extendLocatorId("BackButton"), MSG.view_bundle_dest_backToBundle() - + ": " + bundle.getName(), "Bundles/Bundle/" + bundle.getId()); + + ": " + StringUtility.escapeHtml(bundle.getName()), "Bundles/Bundle/" + bundle.getId());
HeaderLabel header = new HeaderLabel(Canvas.getImgURL("subsystems/bundle/BundleDestination_24.png"), - destination.getName()); + StringUtility.escapeHtml(destination.getName()));
detail = new Canvas(); detail.setHeight("50%"); @@ -121,7 +122,7 @@ public class BundleDestinationView extends LocatableVLayout implements Bookmarka LinkItem bundleName = new LinkItem("bundle"); bundleName.setTitle(MSG.view_bundle_bundle()); bundleName.setValue(LinkManager.getBundleLink(bundle.getId())); - bundleName.setLinkTitle(bundle.getName()); + bundleName.setLinkTitle(StringUtility.escapeHtml(bundle.getName())); bundleName.setTarget("_self");
CanvasItem actionItem = new CanvasItem("actions"); @@ -136,14 +137,14 @@ public class BundleDestinationView extends LocatableVLayout implements Bookmarka LinkItem destinationGroup = new LinkItem("group"); destinationGroup.setTitle(MSG.view_bundle_dest_group()); destinationGroup.setValue(LinkManager.getResourceGroupLink(destination.getGroup().getId())); - destinationGroup.setLinkTitle(destination.getGroup().getName()); + destinationGroup.setLinkTitle(StringUtility.escapeHtml(destination.getGroup().getName())); destinationGroup.setTarget("_self");
StaticTextItem path = new StaticTextItem("path", MSG.view_bundle_dest_deployDir()); path.setValue(destination.getDeployDir());
StaticTextItem description = new StaticTextItem("description", MSG.common_title_description()); - description.setValue(destination.getDescription()); + description.setValue(StringUtility.escapeHtml(destination.getDescription()));
form.setFields(bundleName, actionItem, created, destinationGroup, path, description); return form; diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java index f4801ea..74eaa68 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java @@ -60,6 +60,7 @@ import org.rhq.enterprise.gui.coregui.client.components.tagging.TagEditorView; import org.rhq.enterprise.gui.coregui.client.components.tagging.TagsChangedCallback; import org.rhq.enterprise.gui.coregui.client.gwt.BundleGWTServiceAsync; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.message.Message; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableIButton; @@ -98,7 +99,7 @@ public class BundleView extends LocatableVLayout implements BookmarkableView {
BackButton backButton = new BackButton(extendLocatorId("BackButton"), MSG.view_bundle_list_backToAll(), BundleTopView.VIEW_ID.getTitle()); - headerLabel = new HeaderLabel("subsystems/bundle/Bundle_24.png", bundle.getName()); + headerLabel = new HeaderLabel("subsystems/bundle/Bundle_24.png", StringUtility.escapeHtml(bundle.getName())); tabs = new LocatableTabSet(getLocatorId()); versionsTab = createVersionsTab(); destinationsTab = createDestinationsTab(); @@ -188,7 +189,7 @@ public class BundleView extends LocatableVLayout implements BookmarkableView { destinationsCountItem.setValue(bundle.getDestinations() != null ? bundle.getDestinations().size() : 0);
StaticTextItem descriptionItem = new StaticTextItem("description", MSG.common_title_description()); - descriptionItem.setValue(bundle.getDescription()); + descriptionItem.setValue(StringUtility.escapeHtml(bundle.getDescription()));
form.setFields(versionCountItem, actionItem, destinationsCountItem, descriptionItem);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundlesListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundlesListView.java index 023fd1f..ea25046 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundlesListView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundlesListView.java @@ -47,6 +47,7 @@ import org.rhq.enterprise.gui.coregui.client.components.table.TableActionEnablem import org.rhq.enterprise.gui.coregui.client.gwt.BundleGWTServiceAsync; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; import org.rhq.enterprise.gui.coregui.client.util.ErrorHandler; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.message.Message; import org.rhq.enterprise.gui.coregui.client.util.message.Message.Severity;
@@ -80,7 +81,6 @@ public class BundlesListView extends Table<BundlesWithLatestVersionDataSource> {
@Override protected void configureTable() { - ListGridField idField = new ListGridField(BundlesWithLatestVersionDataSource.FIELD_ID, MSG.common_title_id()); idField.setType(ListGridFieldType.INTEGER); idField.setWidth("50"); @@ -89,15 +89,20 @@ public class BundlesListView extends Table<BundlesWithLatestVersionDataSource> { .common_title_name()); nameField.setWidth("33%"); nameField.setCellFormatter(new CellFormatter() { - public String format(Object o, ListGridRecord record, int i, int i1) { + public String format(Object value, ListGridRecord record, int i, int i1) { return "<a href="" + record.getAttribute(BundlesWithLatestVersionDataSource.FIELD_NAMELINK) + "">" - + String.valueOf(o) + "</a>"; + + StringUtility.escapeHtml(String.valueOf(value)) + "</a>"; } });
ListGridField descField = new ListGridField(BundlesWithLatestVersionDataSource.FIELD_DESCRIPTION, MSG .common_title_description()); descField.setWidth("33%"); + descField.setCellFormatter(new CellFormatter() { + public String format(Object value, ListGridRecord record, int i, int i1) { + return StringUtility.escapeHtml(String.valueOf(value)); + } + });
ListGridField latestVersionField = new ListGridField(BundlesWithLatestVersionDataSource.FIELD_LATEST_VERSION, MSG.view_bundle_latestVersion()); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/revert/GetRevertInfoStep.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/revert/GetRevertInfoStep.java index 552ab4d..33d20e2 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/revert/GetRevertInfoStep.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/revert/GetRevertInfoStep.java @@ -31,6 +31,7 @@ import org.rhq.enterprise.gui.coregui.client.CoreGUI; import org.rhq.enterprise.gui.coregui.client.components.wizard.AbstractWizardStep; import org.rhq.enterprise.gui.coregui.client.gwt.BundleGWTServiceAsync; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.selenium.Locatable; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm;
@@ -68,24 +69,27 @@ public class GetRevertInfoStep extends AbstractWizardStep { .getId(), // new AsyncCallback<String>() {
- public void onSuccess(String result) { + public void onSuccess(String bundleDeploymentName) { final StaticTextItem nameTextItem = new StaticTextItem("name", MSG .view_bundle_revertWizard_getInfoStep_revertDeployName()); nameTextItem.setWidth(300); - wizard.setSubtitle(result); - nameTextItem.setValue(result); + String escapedBundleDeploymentName = StringUtility.escapeHtml(bundleDeploymentName); + wizard.setSubtitle(escapedBundleDeploymentName); + nameTextItem.setValue(escapedBundleDeploymentName);
final TextAreaItem descriptionTextAreaItem = new TextAreaItem("description", MSG .view_bundle_revertWizard_getInfoStep_revertDeployDesc()); descriptionTextAreaItem.setWidth(300); String liveDesc = wizard.getLiveDeployment().getDescription(); liveDesc = (null == liveDesc) ? wizard.getLiveDeployment().getName() : liveDesc; + String escapedLiveDesc = StringUtility.escapeHtml(liveDesc); String prevDesc = wizard.getPreviousDeployment().getDescription(); prevDesc = (null == prevDesc) ? wizard.getPreviousDeployment().getName() : prevDesc; - wizard.setDeploymentDescription("[REVERT From]\n" + liveDesc + "\n\n[REVERT To]\n" + prevDesc); + String escapedPrevDesc = StringUtility.escapeHtml(prevDesc); + wizard.setDeploymentDescription("[REVERT From]\n" + escapedLiveDesc + "\n\n[REVERT To]\n" + escapedPrevDesc); wizard.setDeploymentDescription(MSG.view_bundle_revertWizard_getInfoStep_revertDeployDescFull( - liveDesc, prevDesc)); - descriptionTextAreaItem.setValue(wizard.getDeploymentDescription()); + escapedLiveDesc, escapedPrevDesc)); + descriptionTextAreaItem.setValue(StringUtility.escapeHtml(wizard.getDeploymentDescription())); descriptionTextAreaItem.addChangedHandler(new ChangedHandler() { public void onChanged(ChangedEvent event) { Object value = event.getValue(); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/tree/BundleTreeDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/tree/BundleTreeDataSource.java index 039bc3e..39b84e7 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/tree/BundleTreeDataSource.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/tree/BundleTreeDataSource.java @@ -49,6 +49,7 @@ import org.rhq.enterprise.gui.coregui.client.CoreGUI; import org.rhq.enterprise.gui.coregui.client.gwt.BundleGWTServiceAsync; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
/** * @author Greg Hinkle @@ -244,7 +245,7 @@ public class BundleTreeDataSource extends RPCDataSource<Object, Criteria> { node.setIsFolder(true); node.setIcon("subsystems/bundle/Bundle_16.png"); node.setID(String.valueOf(bundle.getId())); - node.setName(bundle.getName()); + node.setName(StringUtility.escapeHtml(bundle.getName()));
} else if (from instanceof BundleVersion) { BundleVersion version = (BundleVersion) from; @@ -262,10 +263,11 @@ public class BundleTreeDataSource extends RPCDataSource<Object, Criteria> { parentID = bundleId + "_destinations_" + deployment.getDestination().getId(); node.setParentID(parentID); node.setID(bundleId + "_deployments_" + deployment.getId()); + String name = StringUtility.escapeHtml(deployment.getName()); if (deployment.isLive()) { - node.setName("<span style="color: green; font-weight: bold">(live)</span> " + deployment.getName()); + node.setName("<span style="color: green; font-weight: bold">(live)</span> " + name); } else { - node.setName(deployment.getName()); + node.setName(name); }
} else if (from instanceof BundleDestination) { @@ -275,7 +277,7 @@ public class BundleTreeDataSource extends RPCDataSource<Object, Criteria> { parentID = destination.getBundle().getId() + "_destinations"; node.setParentID(parentID); node.setID(parentID + '_' + destination.getId()); - node.setName(destination.getName()); + node.setName(StringUtility.escapeHtml(destination.getName())); }
return node; diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java index ac2d132..35d61f2 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationEditor.java @@ -1261,7 +1261,10 @@ public class ConfigurationEditor extends LocatableVLayout { // TODO (ips, 03/25/11): We eventually want to use StaticTextItems for read-only PASSWORD props too, but we have // to wait until we implement masking/unmasking of PASSWORD props at the SLSB layer first. if (propertyIsReadOnly && propertyDefinitionSimple.getType() != PropertySimpleType.PASSWORD) { - valueItem = new StaticTextItem(); + StaticTextItem staticItem = new StaticTextItem(); + // Property values are user-editable, so escape HTML to prevent an XSS attack. + staticItem.setOutputAsHTML(true); + valueItem = staticItem; } else { List<PropertyDefinitionEnumeration> enumeratedValues = propertyDefinitionSimple.getEnumeratedValues(); if (enumeratedValues != null && !enumeratedValues.isEmpty()) { diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/EnhancedDynamicForm.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/EnhancedDynamicForm.java index 59c8b9d..02c2752 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/EnhancedDynamicForm.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/form/EnhancedDynamicForm.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2010 Red Hat, Inc. + * Copyright (C) 2010-2011 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -45,6 +45,8 @@ import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm; */ public class EnhancedDynamicForm extends LocatableDynamicForm {
+ public static final String OUTPUT_AS_HTML_ATTRIBUTE = "outputAsHTML"; + private static final String FIELD_ID = "id";
private boolean isReadOnly; @@ -116,6 +118,10 @@ public class EnhancedDynamicForm extends LocatableDynamicForm { staticItem.setTooltip(item.getTooltip()); staticItem.setValue(item.getDisplayValue()); staticItem.setColSpan(item.getAttribute("colSpan")); + Boolean outputAsHtml = item.getAttributeAsBoolean(OUTPUT_AS_HTML_ATTRIBUTE); + if (Boolean.TRUE.equals(outputAsHtml)) { + staticItem.setOutputAsHTML(true); + } // TODO: Any other fields we should copy? icons?
if ((item instanceof BooleanItem) || (item instanceof CheckboxItem)) { diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/EscapedHtmlCellFormatter.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/EscapedHtmlCellFormatter.java new file mode 100644 index 0000000..c60236c --- /dev/null +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/EscapedHtmlCellFormatter.java @@ -0,0 +1,19 @@ +package org.rhq.enterprise.gui.coregui.client.components.table; + +import com.smartgwt.client.widgets.grid.CellFormatter; +import com.smartgwt.client.widgets.grid.ListGridRecord; +import org.rhq.enterprise.gui.coregui.client.ImageManager; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; + +/** + * A cell formatter that escapes any HTML in the cell's value. + * + * @author Ian Springer + */ +public class EscapedHtmlCellFormatter implements CellFormatter { + + public String format(Object value, ListGridRecord record, int rowNum, int colNum) { + return (value != null) ? StringUtility.escapeHtml(value.toString()) : ""; + } + +} diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/IconField.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/IconField.java new file mode 100644 index 0000000..82d6071 --- /dev/null +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/IconField.java @@ -0,0 +1,73 @@ +/* + * RHQ Management Platform + * Copyright 2011, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * 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 com.google.gwt.core.client.JavaScriptObject; +import com.smartgwt.client.types.Alignment; +import com.smartgwt.client.types.ListGridFieldType; +import com.smartgwt.client.widgets.grid.ListGridField; + +/** + * @author Ian Springer + */ +public class IconField extends ListGridField { + + private static final String DEFAULT_NAME = "icon"; + private static final String DEFAULT_TITLE = " "; + private static final int DEFAULT_WIDTH = 25; + + public IconField() { + super(DEFAULT_NAME, DEFAULT_TITLE, DEFAULT_WIDTH); + init(); + } + + public IconField(JavaScriptObject jsObj) { + super(DEFAULT_NAME, DEFAULT_TITLE, DEFAULT_WIDTH); + setJsObj(jsObj); + init(); + } + + public IconField(String name) { + super(name, DEFAULT_TITLE, DEFAULT_WIDTH); + init(); + } + + public IconField(String name, int width) { + super(name, DEFAULT_TITLE, width); + init(); + } + + public IconField(String name, String title) { + super(name, title, DEFAULT_WIDTH); + init(); + } + + public IconField(String name, String title, int width) { + super(name, title, width); + init(); + } + + private void init() { + setType(ListGridFieldType.IMAGE); + setAlign(Alignment.CENTER); + setShowDefaultContextMenu(false); + } + +} diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/TableSection.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/TableSection.java index e551deb..b19abfd 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/TableSection.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/TableSection.java @@ -44,6 +44,7 @@ import org.rhq.enterprise.gui.coregui.client.DetailsView; import org.rhq.enterprise.gui.coregui.client.ViewPath; import org.rhq.enterprise.gui.coregui.client.components.buttons.BackButton; import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout; import org.rhq.enterprise.gui.coregui.client.util.selenium.SeleniumUtility;
@@ -56,6 +57,7 @@ public abstract class TableSection<DS extends RPCDataSource> extends Table<DS> i private VLayout detailsHolder; private Canvas detailsView; private String basePath; + private boolean escapeHtmlInDetailsLinkColumn;
protected TableSection(String locatorId, String tableTitle) { super(locatorId, tableTitle); @@ -110,7 +112,7 @@ public abstract class TableSection<DS extends RPCDataSource> extends Table<DS> i
/** * The default implementation wraps the {@link getDetailsLinkColumnCellFormatter()} column with the - * {@link getDetailsLinkColumnCellFormatter()}. This is typically the 'name' column linking to the detail + * {@link #getDetailsLinkColumnCellFormatter()}. This is typically the 'name' column linking to the detail * view, given the 'id'. Also, establishes a double click handler for the row which invokes * {@link showDetails()}</br> * </br> @@ -146,6 +148,10 @@ public abstract class TableSection<DS extends RPCDataSource> extends Table<DS> i return true; }
+ public void setEscapeHtmlInDetailsLinkColumn(boolean escapeHtmlInDetailsLinkColumn) { + this.escapeHtmlInDetailsLinkColumn = escapeHtmlInDetailsLinkColumn; + } + /** * Override if you don't want FIELD_NAME to be wrapped ina link. * @return the name of the field to be wrapped, or null if no field should be wrapped. @@ -161,9 +167,13 @@ public abstract class TableSection<DS extends RPCDataSource> extends Table<DS> i protected CellFormatter getDetailsLinkColumnCellFormatter() { return new CellFormatter() { public String format(Object value, ListGridRecord record, int i, int i1) { + if (value == null) { + return ""; + } Integer recordId = getId(record); String detailsUrl = "#" + getBasePath() + "/" + recordId; - return SeleniumUtility.getLocatableHref(detailsUrl, value.toString(), null); + String formattedValue = (escapeHtmlInDetailsLinkColumn) ? StringUtility.escapeHtml(value.toString()) : value.toString(); + return SeleniumUtility.getLocatableHref(detailsUrl, formattedValue, null); } }; } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tree/EnhancedTreeNode.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tree/EnhancedTreeNode.java index 15e13fa..1bae1e2 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tree/EnhancedTreeNode.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/tree/EnhancedTreeNode.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2010 Red Hat, Inc. + * Copyright (C) 2010-2011 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ import com.smartgwt.client.widgets.tree.TreeNode; * @author Ian Springer */ public class EnhancedTreeNode extends TreeNode { + public EnhancedTreeNode() { super(); } @@ -55,7 +56,7 @@ public class EnhancedTreeNode extends TreeNode { public void setName(String name) { super.setName(name); if (name != null && getTitle() == null) { - setTitle(name); + super.setTitle(name); } }
@@ -110,4 +111,5 @@ public class EnhancedTreeNode extends TreeNode { private Attributes() { } } + } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/recent/problems/ProblemResourcesPortlet.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/recent/problems/ProblemResourcesPortlet.java index 8fcaba0..f91c4cf 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/recent/problems/ProblemResourcesPortlet.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/recent/problems/ProblemResourcesPortlet.java @@ -49,6 +49,7 @@ import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple; import org.rhq.core.domain.configuration.definition.PropertySimpleType; import org.rhq.core.domain.dashboard.DashboardPortlet; import org.rhq.enterprise.gui.coregui.client.LinkManager; +import org.rhq.enterprise.gui.coregui.client.components.table.IconField; import org.rhq.enterprise.gui.coregui.client.components.table.Table; import org.rhq.enterprise.gui.coregui.client.components.table.TableWidget; import org.rhq.enterprise.gui.coregui.client.dashboard.AutoRefreshPortlet; @@ -139,12 +140,9 @@ public class ProblemResourcesPortlet extends Table<ProblemResourcesDataSource> i
ListGridField alertsField = new ListGridField(ALERTS.propertyName(), ALERTS.title(), 70);
- ListGridField availabilityField = new ListGridField(AVAILABILITY.propertyName(), AVAILABILITY.title(), 70); - availabilityField.setType(ListGridFieldType.IMAGE); - availabilityField.setAlign(Alignment.CENTER); + IconField availabilityField = new IconField(AVAILABILITY.propertyName(), AVAILABILITY.title(), 70);
setListGridFields(resourceField, ancestryField, alertsField, availabilityField); - }
@Override diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/util/MessagePortlet.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/util/MessagePortlet.java index 8da6a8b..ead9cc2 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/util/MessagePortlet.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/util/MessagePortlet.java @@ -34,6 +34,7 @@ import org.rhq.enterprise.gui.coregui.client.dashboard.ConfigurablePortlet; import org.rhq.enterprise.gui.coregui.client.dashboard.Portlet; import org.rhq.enterprise.gui.coregui.client.dashboard.PortletViewFactory; import org.rhq.enterprise.gui.coregui.client.dashboard.PortletWindow; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableHTMLPane;
/** @@ -46,15 +47,17 @@ public class MessagePortlet extends LocatableHTMLPane implements ConfigurablePor // A default displayed, persisted name for the portlet public static final String NAME = MSG.view_portlet_defaultName_message();
+ private static final String MESSAGE_PROPERTY = "message"; + public MessagePortlet(String locatorId) { super(locatorId); setContentsType(ContentsType.PAGE); }
public void configure(PortletWindow portletWindow, DashboardPortlet storedPortlet) { - String contents = storedPortlet.getConfiguration().getSimpleValue("message", null); + String contents = storedPortlet.getConfiguration().getSimpleValue(MESSAGE_PROPERTY, null); if (contents != null) { - setContents(contents); + setContents(StringUtility.sanitizeHtml(contents)); } else { setContents("<br/><i>" + MSG.view_portlet_configure_needed() + "</i>"); } @@ -68,7 +71,7 @@ public class MessagePortlet extends LocatableHTMLPane implements ConfigurablePor ConfigurationDefinition definition = new ConfigurationDefinition(MSG.view_portlet_configure_definitionTitle(), MSG.view_portlet_configure_definitionDesc());
- definition.put(new PropertyDefinitionSimple("message", MSG.view_portlet_message_title(), true, + definition.put(new PropertyDefinitionSimple(MESSAGE_PROPERTY, MSG.view_portlet_message_title(), true, PropertySimpleType.LONG_STRING));
return definition; @@ -78,8 +81,8 @@ public class MessagePortlet extends LocatableHTMLPane implements ConfigurablePor public static PortletViewFactory INSTANCE = new Factory();
public final Portlet getInstance(String locatorId) { - return new MessagePortlet(locatorId); } } + } \ No newline at end of file diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/history/AbstractOperationHistoryDetailsView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/history/AbstractOperationHistoryDetailsView.java index 27b1040..236e994 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/history/AbstractOperationHistoryDetailsView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/history/AbstractOperationHistoryDetailsView.java @@ -167,6 +167,8 @@ public abstract class AbstractOperationHistoryDetailsView<T extends OperationHis
StaticTextItem requesterItem = new StaticTextItem(AbstractOperationHistoryDataSource.Field.SUBJECT, MSG .view_operationHistoryDetails_requestor()); + + requesterItem.setOutputAsHTML(true); requesterItem.setValue(operationHistory.getSubjectName()); items.add(requesterItem);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/AbstractOperationScheduleDetailsView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/AbstractOperationScheduleDetailsView.java index ff577d0..387c4d5 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/AbstractOperationScheduleDetailsView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/operation/schedule/AbstractOperationScheduleDetailsView.java @@ -263,7 +263,9 @@ public abstract class AbstractOperationScheduleDetailsView extends AbstractRecor Integer integerValue = TypeConversionUtility.toInteger(value); timeoutItem.setValue(integerValue, UnitType.TIME);
- FormItem notesItem = this.notesForm.getField(AbstractOperationScheduleDataSource.Field.DESCRIPTION); + StaticTextItem notesItem = (StaticTextItem) this.notesForm.getField(AbstractOperationScheduleDataSource.Field.DESCRIPTION); + // Notes field is user-editable, so escape HTML to prevent an XSS attack. + notesItem.setOutputAsHTML(true); notesItem.setValue(getForm().getValue(AbstractOperationScheduleDataSource.Field.DESCRIPTION));
this.parameters = (Configuration) record.getAttributeAsObject(AbstractOperationScheduleDataSource.Field.PARAMETERS); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/summary/AbstractActivityView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/summary/AbstractActivityView.java index 82ac645..5fec813 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/summary/AbstractActivityView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/common/detail/summary/AbstractActivityView.java @@ -401,7 +401,7 @@ public abstract class AbstractActivityView extends LocatableVLayout implements R
/** Create empty display row(LocatableDynamicForm) that is constently defined and displayed. * - * @param column Locatable parent colum. + * @param locatorId locator ID of Locatable parent column * @param emptyMessage Contents of the empty region * @return */ diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupTreeView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupTreeView.java index 04fbfbd..a469fa9 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupTreeView.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupTreeView.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright (C) 2005-2010 Red Hat, Inc. + * Copyright (C) 2005-2011 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -281,7 +281,9 @@ public class ResourceGroupTreeView extends LocatableVLayout implements Bookmarka ResourceGroupTreeView.this.rootResourceGroup = group; ResourceGroupTreeView.this.rootGroupId = rootResourceGroup.getId(); ResourceGroupEnhancedTreeNode fakeRoot = new ResourceGroupEnhancedTreeNode("fakeRootNode"); - ResourceGroupEnhancedTreeNode rootNode = new ResourceGroupEnhancedTreeNode(group.getName()); + String groupName = group.getName(); + String escapedGroupName = StringUtility.escapeHtml(groupName); + ResourceGroupEnhancedTreeNode rootNode = new ResourceGroupEnhancedTreeNode(escapedGroupName); String icon = ImageManager.getGroupIcon(GroupCategory.MIXED); rootNode.setIcon(icon); rootNode.setID(String.valueOf(rootResourceGroup.getId())); @@ -387,7 +389,9 @@ public class ResourceGroupTreeView extends LocatableVLayout implements Bookmarka ResourceGroupEnhancedTreeNode fakeRoot = new ResourceGroupEnhancedTreeNode("fakeRootNode"); fakeRoot.setID(FAKE_ROOT_ID);
- ResourceGroupEnhancedTreeNode rootNode = new ResourceGroupEnhancedTreeNode(rootResourceGroup.getName()); + String groupName = rootResourceGroup.getName(); + String escapedGroupName = StringUtility.escapeHtml(groupName); + ResourceGroupEnhancedTreeNode rootNode = new ResourceGroupEnhancedTreeNode(escapedGroupName); rootNode.setID(rootKey.getKey()); rootNode.setParentID(fakeRoot.getID());
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/AncestryUtil.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/AncestryUtil.java index 2393132..ba890d4 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/AncestryUtil.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/AncestryUtil.java @@ -34,6 +34,7 @@ import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceType; import org.rhq.enterprise.gui.coregui.client.CoreGUI; import org.rhq.enterprise.gui.coregui.client.LinkManager; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.selenium.SeleniumUtility;
/** @@ -42,6 +43,7 @@ import org.rhq.enterprise.gui.coregui.client.util.selenium.SeleniumUtility; * @author Jay Shaughnessy */ public abstract class AncestryUtil { + // ListGrid Record attribute names expected to be set on records processed by the utility public static final String RESOURCE_ANCESTRY = "resourceAncestry"; public static final String RESOURCE_ANCESTRY_VALUE = "resourceAncestryDecoded"; @@ -115,8 +117,8 @@ public abstract class AncestryUtil { continue; } String[] ancestryEntries = ancestry.split(Resource.ANCESTRY_DELIM); - for (int i = 0; i < ancestryEntries.length; ++i) { - String[] entryTokens = ancestryEntries[i].split(Resource.ANCESTRY_ENTRY_DELIM); + for (String ancestryEntry : ancestryEntries) { + String[] entryTokens = ancestryEntry.split(Resource.ANCESTRY_ENTRY_DELIM); int rtId = Integer.valueOf(entryTokens[0]); result.add(rtId); } @@ -148,7 +150,7 @@ public abstract class AncestryUtil { String[] entryTokens = ancestryEntries[i].split(Resource.ANCESTRY_ENTRY_DELIM); int ancestorTypeId = Integer.valueOf(entryTokens[0]); int ancestorResourceId = Integer.valueOf(entryTokens[1]); - String ancestorName = entryTokens[2]; + String ancestorName = StringUtility.escapeHtml(entryTokens[2]);
sbResources.append((i > 0) ? " < " : ""); //sbResources.append(" < "); @@ -201,17 +203,15 @@ public abstract class AncestryUtil { return ""; }
- Integer resourceId = record.getAttributeAsInt(RESOURCE_ID); - // if not set assume the standard "id" attr is a resourceId - resourceId = (null != resourceId) ? resourceId : record.getAttributeAsInt("id"); + Integer resourceId = getResourceId(record); StringBuilder sbResources = new StringBuilder(); String[] ancestryEntries = ancestry.split(Resource.ANCESTRY_DELIM); for (int i = 0; i < ancestryEntries.length; ++i) { String[] entryTokens = ancestryEntries[i].split(Resource.ANCESTRY_ENTRY_DELIM); int ancestorResourceId = Integer.valueOf(entryTokens[1]); - String ancestorName = entryTokens[2]; + String ancestorName = StringUtility.escapeHtml(entryTokens[2]);
- sbResources.append((i > 0) ? " < " : ""); + sbResources.append((i > 0) ? " < " : ""); if (generateLinks) { String url = LinkManager.getResourceLink(ancestorResourceId); String suffix = resourceId + "_" + entryTokens[1]; @@ -231,18 +231,14 @@ public abstract class AncestryUtil { return ancestryHover; }
- Integer resourceId = listGridRecord.getAttributeAsInt(RESOURCE_ID); - // if not set assume the standard "id" attr is a resourceId - resourceId = (null != resourceId) ? resourceId : listGridRecord.getAttributeAsInt("id"); - String resourceName = listGridRecord.getAttribute(RESOURCE_NAME); - // if not set assume the standard "name" attr is a resourceName - resourceName = (null != resourceName) ? resourceName : listGridRecord.getAttribute("name"); + String resourceName = getResourceName(listGridRecord); + Map<Integer, ResourceType> types = ((MapWrapper) listGridRecord.getAttributeAsObject(RESOURCE_ANCESTRY_TYPES)) .getMap(); Integer resourceTypeId = listGridRecord.getAttributeAsInt(RESOURCE_TYPE_ID); String ancestry = listGridRecord.getAttributeAsString(RESOURCE_ANCESTRY);
- String result = getAncestryHoverHTMLString(resourceId, resourceName, ancestry, resourceTypeId, types, width); + String result = getAncestryHoverHTMLString(resourceName, ancestry, resourceTypeId, types, width);
listGridRecord.setAttribute(RESOURCE_ANCESTRY_HOVER, result); return result; @@ -250,12 +246,12 @@ public abstract class AncestryUtil {
public static String getAncestryHoverHTMLForResource(Resource resource, Map<Integer, ResourceType> types, int width) {
- return getAncestryHoverHTMLString(resource.getId(), resource.getName(), resource.getAncestry(), resource + return getAncestryHoverHTMLString(resource.getName(), resource.getAncestry(), resource .getResourceType().getId(), types, width); }
- private static String getAncestryHoverHTMLString(int resourceId, String resourceName, String ancestry, - int resourceTypeId, Map<Integer, ResourceType> types, int width) { + private static String getAncestryHoverHTMLString(String resourceName, String ancestry, + int resourceTypeId, Map<Integer, ResourceType> types, int width) { ResourceType type = types.get(resourceTypeId); String resourceLongName = getResourceLongName(resourceName, type);
@@ -282,7 +278,7 @@ public abstract class AncestryUtil { for (int i = ancestryEntries.length - 1, j = 0; i >= 0; --i, ++j) { String[] entryTokens = ancestryEntries[i].split(Resource.ANCESTRY_ENTRY_DELIM); int ancestorTypeId = Integer.valueOf(entryTokens[0]); - String ancestorName = entryTokens[2]; + String ancestorName = StringUtility.escapeHtml(entryTokens[2]);
// indent with spaces if (j > 0) { @@ -323,9 +319,10 @@ public abstract class AncestryUtil {
/** * Get a resource name that combines type and resource information. This is useful for when we want to - * use a single column for dispay of the resource "name". The name is wrapped in a navigable link. + * use a single column for display of the resource "name". The name is wrapped in a navigable link. * - * @param resource The resource + * @param record the resource record + * @param width the width, in pixels, of the returned HTML <code>p</code> tag * * @return the long name for the resource */ @@ -335,9 +332,7 @@ public abstract class AncestryUtil { return resourceHover; }
- String resourceName = record.getAttribute(RESOURCE_NAME); - // if not set assume the standard "name" attr is a resourceName - resourceName = (null != resourceName) ? resourceName : record.getAttribute("name"); + String resourceName = getResourceName(record); Map<Integer, ResourceType> types = ((MapWrapper) record.getAttributeAsObject(RESOURCE_ANCESTRY_TYPES)).getMap(); Integer resourceTypeId = record.getAttributeAsInt(RESOURCE_TYPE_ID); ResourceType type = types.get(resourceTypeId); @@ -365,6 +360,21 @@ public abstract class AncestryUtil { return result; }
+ private static Integer getResourceId(Record record) { + Integer resourceId = record.getAttributeAsInt(RESOURCE_ID); + // if not set assume the standard "id" attr is a resourceId + resourceId = (null != resourceId) ? resourceId : record.getAttributeAsInt("id"); + return resourceId; + } + + private static String getResourceName(Record record) { + String resourceName = record.getAttribute(RESOURCE_NAME); + // if not set assume the standard "name" attr is a resourceName + resourceName = (null != resourceName) ? resourceName : record.getAttribute("name"); + resourceName = StringUtility.escapeHtml(resourceName); + return resourceName; + } + // We do not want smargwt to see we are storing our map into an attribute because it barfs on our key/value pairs // so instead we have to wrap it in a non-Map POJO Object so smartgwt just handles it as a java.lang.Object. public static class MapWrapper { 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 32a6227..b53a127 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 @@ -33,8 +33,6 @@ 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; import com.smartgwt.client.widgets.events.DoubleClickEvent; import com.smartgwt.client.widgets.events.DoubleClickHandler; import com.smartgwt.client.widgets.grid.CellFormatter; @@ -52,12 +50,14 @@ 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.RecordExtractor; import org.rhq.enterprise.gui.coregui.client.components.table.ResourceAuthorizedTableAction; +import org.rhq.enterprise.gui.coregui.client.components.table.IconField; 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; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; import org.rhq.enterprise.gui.coregui.client.gwt.ResourceGWTServiceAsync; import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.TableUtility; import org.rhq.enterprise.gui.coregui.client.util.message.Message; import org.rhq.enterprise.gui.coregui.client.util.message.Message.Severity; @@ -125,14 +125,9 @@ public class ResourceSearchView extends Table {
@Override protected void configureTable() { - ListGridField iconField = new ListGridField("icon", MSG.common_title_icon(), 25); - iconField.setType(ListGridFieldType.IMAGE); - iconField.setShowDefaultContextMenu(false); - iconField.setCanSort(false); - iconField.setTitle(" "); + IconField iconField = new IconField(); iconField.setShowHover(true); iconField.setHoverCustomizer(new HoverCustomizer() { - @Override public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) { String resCat = record.getAttribute(CATEGORY.propertyName()); switch (ResourceCategory.valueOf(resCat)) { @@ -149,14 +144,14 @@ public class ResourceSearchView extends Table {
ListGridField nameField = new ListGridField(NAME.propertyName(), NAME.title(), 250); nameField.setCellFormatter(new CellFormatter() { - public String format(Object o, ListGridRecord listGridRecord, int i, int i1) { - String url = LinkManager.getResourceLink(listGridRecord.getAttributeAsInt("id")); - return SeleniumUtility.getLocatableHref(url, o.toString(), null); + public String format(Object value, ListGridRecord record, int rowNum, int colNum) { + String url = LinkManager.getResourceLink(record.getAttributeAsInt("id")); + String name = StringUtility.escapeHtml(value.toString()); + return SeleniumUtility.getLocatableHref(url, name, null); } }); nameField.setShowHover(true); nameField.setHoverCustomizer(new HoverCustomizer() { - public String hoverHTML(Object value, ListGridRecord listGridRecord, int rowNum, int colNum) { return AncestryUtil.getResourceHoverHTML(listGridRecord, 0); } @@ -174,9 +169,7 @@ public class ResourceSearchView extends Table { categoryField.setCellFormatter(new ResourceCategoryCellFormatter()); categoryField.setHidden(true); // the icon field already shows us this, no need to show it in another column
- ListGridField availabilityField = new ListGridField(AVAILABILITY.propertyName(), AVAILABILITY.title(), 70); - availabilityField.setType(ListGridFieldType.IMAGE); - availabilityField.setAlign(Alignment.CENTER); + IconField availabilityField = new IconField(AVAILABILITY.propertyName(), AVAILABILITY.title(), 70);
setListGridFields(iconField, nameField, ancestryField, descriptionField, typeNameField, pluginNameField, categoryField, availabilityField); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTitleBar.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTitleBar.java index bd86104..dcdffd9 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTitleBar.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTitleBar.java @@ -49,6 +49,7 @@ import org.rhq.enterprise.gui.coregui.client.UserSessionManager; import org.rhq.enterprise.gui.coregui.client.components.tagging.TagEditorView; import org.rhq.enterprise.gui.coregui.client.components.tagging.TagsChangedCallback; import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup; +import org.rhq.enterprise.gui.coregui.client.util.StringUtility; import org.rhq.enterprise.gui.coregui.client.util.message.Message; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableHLayout; import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableImg; @@ -310,7 +311,7 @@ public class ResourceTitleBar extends LocatableVLayout { if (!resource.getName().equals(resourceName)) { resource.setName(resourceName); // the name must have been changed by the user via the editable field } - this.title.setContents("<span class="SectionHeader">" + resource.getName() + this.title.setContents("<span class="SectionHeader">" + StringUtility.escapeHtml(resourceName) + "</span> <span class="subtitle">" + resource.getResourceType().getName() + "</span>"); this.title.markForRedraw(); } diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java index 336e12e..6a38008 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceTreeDatasource.java @@ -334,10 +334,14 @@ public class ResourceTreeDatasource extends DataSource { } this.setParentID(parentId);
+ // name and description are user-editable, so escape HTML to prevent XSS attacks String name = resource.getName(); - setName(name); + String escapedName = StringUtility.escapeHtml(name); + setName(escapedName);
- setAttribute(Attributes.DESCRIPTION, resource.getDescription()); + String description = resource.getDescription(); + String escapedDescription = StringUtility.escapeHtml(description); + setAttribute(Attributes.DESCRIPTION, escapedDescription);
Set<ResourceType> childTypes = resource.getResourceType().getChildResourceTypes(); setIsFolder((childTypes != null && !childTypes.isEmpty())); diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/StringUtility.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/StringUtility.java index 984ca22..0c93099 100644 --- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/StringUtility.java +++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/StringUtility.java @@ -1,6 +1,6 @@ /* * RHQ Management Platform - * Copyright 2010, Red Hat Middleware LLC, and individual contributors + * Copyright 2011, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * @@ -19,53 +19,72 @@ */ package org.rhq.enterprise.gui.coregui.client.util;
-import java.util.ArrayList; -import java.util.List; - /** * A collection of utility methods for working with Strings. - * - * TODO: I18N. The logic here may need to be pluggable for different localizations. * * @author Ian Springer */ public class StringUtility {
/** - * Split a string on delimiter boundaries, and place each element into a List. + * Escapes HTML in a string to eliminate cross site scripting (XSS) vulnerabilities. Note, this impl is designed + * to be highly efficient to minimize the impact on performance. * - * @param s String to split up - * @param delim Delimiting token, ala StringTokenizer + * @param string the string to be escaped * - * @return a List comprised of elements split by the tokenizing + * @return the escaped string */ - - public static List<String> explode(String s, String delim) { - List<String> res = new ArrayList<String>(); - if (s == null) - return res; - - String[] tokens = s.split(delim); - for (String token : tokens) { - res.add(token); + public static String escapeHtml(String string) { + if (string == null) { + return null; } - - return res; + StringBuilder buffer = null; + for (int i = 0; i < string.length(); i++) { + char c = string.charAt(i); + if (c == '&') { + if (buffer == null) { + buffer = new StringBuilder(string.substring(0, i)); + } + buffer.append("&"); + } else if (c == '<') { + if (buffer == null) { + buffer = new StringBuilder(string.substring(0, i)); + } + buffer.append("<"); + } else if (c == '>') { + if (buffer == null) { + buffer = new StringBuilder(string.substring(0, i)); + } + buffer.append(">"); + } else { + if (buffer != null) { + buffer.append(c); + } + } + } + return (buffer != null) ? buffer.toString() : string; }
- public static String pluralize(String singularNoun) { - String pluralNoun; - if (singularNoun.endsWith("y") && !singularNoun.endsWith("ay") && !singularNoun.endsWith("ey") - && !singularNoun.endsWith("oy")) { - pluralNoun = singularNoun.substring(0, singularNoun.length() - 1) + "ies"; - } else if (!singularNoun.endsWith("s")) { - pluralNoun = singularNoun + "s"; - } else { - pluralNoun = singularNoun; + /** + * Sanitizes HTML (i.e. removes unsafe HTML such as SCRIPT tags) in a string to eliminate cross site scripting (XSS) + * vulnerabilities. + * + * @param string the string to be sanitized + * + * @return the sanitized string + */ + // TODO (ips, 03/31/11): Replace this lame impl with a much more robust one - easiest way would be to upgrade to GWT + // 2.1 or later and use the new Safe HTML APIs. See also + // http://tomerdoron.blogspot.com/2011/03/less-simple-safe-html-sanitizer.html. + public static String sanitizeHtml(String string) { + if (string == null) { + return null; } - return pluralNoun; + + return string.replaceAll("<script", "<script").replaceAll("<SCRIPT", "<SCRIPT"); }
private StringUtility() { } + }