diff --git a/geowebcache/rest/src/main/java/org/geowebcache/rest/service/FormService.java b/geowebcache/rest/src/main/java/org/geowebcache/rest/service/FormService.java index 936b7678f..b8363bc33 100644 --- a/geowebcache/rest/src/main/java/org/geowebcache/rest/service/FormService.java +++ b/geowebcache/rest/src/main/java/org/geowebcache/rest/service/FormService.java @@ -18,6 +18,7 @@ */ package org.geowebcache.rest.service; +import static org.apache.commons.text.StringEscapeUtils.escapeHtml4; import static org.geowebcache.seed.TileBreeder.TILE_FAILURE_RETRY_COUNT_DEFAULT; import static org.geowebcache.seed.TileBreeder.TILE_FAILURE_RETRY_WAIT_TIME_DEFAULT; import static org.geowebcache.seed.TileBreeder.TOTAL_FAILURES_BEFORE_ABORTING_DEFAULT; @@ -356,7 +357,10 @@ private void makeModifiableParameters(StringBuilder doc, TileLayer tl) { String key = pf.getKey(); String defaultValue = pf.getDefaultValue(); List legalValues = pf.getLegalValues(); - doc.append("").append(key.toUpperCase()).append(": ").append(""); + doc.append("") + .append(escapeHtml4(key.toUpperCase())) + .append(": ") + .append(""); String parameterId = "parameter_" + key; if (pf instanceof StringParameterFilter) { Map keysValues = makeParametersMap(defaultValue, legalValues); @@ -487,7 +491,7 @@ private void makeBboxHints(StringBuilder doc, TileLayer tl) { GridSubset subset = tl.getGridSubset(gridSetId); doc.append( "
  • " - + gridSetId + + escapeHtml4(gridSetId) + ": " + subset.getOriginalExtent().toString() + "
  • \n"); @@ -501,11 +505,11 @@ private void makeTextInput(StringBuilder doc, String id, int size) { private void makeTextInput(StringBuilder doc, String id, int size, String defaultValue) { doc.append( ""); } @@ -603,7 +607,7 @@ private void makeGridSetPulldown(StringBuilder doc, TileLayer tl) { private void makePullDown( StringBuilder doc, String id, Map keysValues, String defaultKey) { - doc.append("\n"); Iterator> iter = keysValues.entrySet().iterator(); @@ -612,16 +616,16 @@ private void makePullDown( if (entry.getKey().equals(defaultKey)) { doc.append( "\n"); } else { doc.append( "\n"); } } @@ -631,7 +635,10 @@ private void makePullDown( private void makeFormHeader(StringBuilder doc, TileLayer tl) { doc.append("

    Create a new task:

    \n"); - doc.append("
    \n"); + doc.append( + "\n"); doc.append("\n"); } @@ -720,9 +727,9 @@ private void makeTaskList(StringBuilder doc, TileLayer tl, boolean listAll) { doc.append(""); doc.append("
    ").append(task.getTaskId()).append(""); if (!layerName.equals(task.getLayerName())) { - doc.append(""); + doc.append(""); } - doc.append(task.getLayerName()); + doc.append(escapeHtml4(task.getLayerName())); if (!layerName.equals(task.getLayerName())) { doc.append(""); } @@ -745,7 +752,7 @@ private void makeTaskList(StringBuilder doc, TileLayer tl, boolean listAll) { if (tasks) { doc.append("
    "); } - doc.append("

    Refresh list

    \n"); + doc.append("

    Refresh list

    \n"); } private String toTimeString(long timeSeconds, final long tilesDone, final long tilesTotal) { @@ -786,7 +793,7 @@ private String toTimeString(long timeSeconds, final long tilesDone, final long t private String makeThreadKillForm(Long key, TileLayer tl) { String ret = "" + "" + ""); doc.append("\n"); doc.append("List "); doc.append("\n"); @@ -847,7 +854,7 @@ private String makeKillallThreadsForm(TileLayer tl, boolean listAll) { doc.append("\n"); doc.append("\n"); doc.append("\n"); - doc.append(" Tasks for Layer '").append(layerName).append("'."); + doc.append(" Tasks for Layer '").append(escapeHtml4(layerName)).append("'."); doc.append(""); doc.append("\n"); doc.append("
    \n"); diff --git a/geowebcache/rest/src/test/java/org/geowebcache/rest/service/FormServiceTest.java b/geowebcache/rest/src/test/java/org/geowebcache/rest/service/FormServiceTest.java index 8567714e7..33f3077ec 100644 --- a/geowebcache/rest/src/test/java/org/geowebcache/rest/service/FormServiceTest.java +++ b/geowebcache/rest/src/test/java/org/geowebcache/rest/service/FormServiceTest.java @@ -18,8 +18,11 @@ import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -27,11 +30,15 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections4.iterators.EmptyIterator; import org.easymock.EasyMock; import org.geowebcache.MockWepAppContextRule; +import org.geowebcache.filter.parameters.ParameterFilter; +import org.geowebcache.filter.parameters.RegexParameterFilter; +import org.geowebcache.filter.parameters.StringParameterFilter; import org.geowebcache.grid.BoundingBox; import org.geowebcache.grid.GridSubset; import org.geowebcache.layer.TileLayer; @@ -58,6 +65,41 @@ public void setUp() throws Exception { service.setTileBreeder(breeder); } + @Test + public void testEscaping() throws Exception { + String unescapedLayer = "layer\"><"; + String escapedLayer = "layer"><"; + String unescapedString = "string\"><"; + String escapedString = "string"><"; + String unescapedRegex = "regex\"><"; + String escapedRegex = "regex"><"; + StringParameterFilter stringFilter = new StringParameterFilter(); + stringFilter.setKey(unescapedString); + RegexParameterFilter regexFilter = new RegexParameterFilter(); + regexFilter.setKey(unescapedRegex); + List filters = Arrays.asList(stringFilter, regexFilter); + + TileLayer tl = EasyMock.createMock("tl", TileLayer.class); + expect(breeder.findTileLayer(unescapedLayer)).andReturn(tl); + expect(tl.getName()).andStubReturn(unescapedLayer); + expect(breeder.getRunningAndPendingTasks()).andReturn(Collections.emptyIterator()).times(2); + expect(tl.getGridSubsets()).andReturn(Collections.emptySet()).times(4); + expect(tl.getMimeTypes()).andReturn(Collections.emptyList()); + expect(tl.getParameterFilters()).andReturn(filters); + replay(tl, breeder); + ResponseEntity response = service.handleGet(null, unescapedLayer); + verify(tl, breeder); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + String body = (String) response.getBody(); + assertThat(body, not(containsString(unescapedLayer))); + assertThat(body, containsString(escapedLayer)); + assertThat(body, not(containsString(unescapedString))); + assertThat(body, containsString(escapedString)); + assertThat(body, not(containsString(unescapedRegex))); + assertThat(body, containsString(escapedRegex)); + } + @Test public void testKill() { Map form = new HashMap<>();