/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wfs; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertEquals; import java.util.HashMap; import org.custommonkey.xmlunit.XMLAssert; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.DataStoreInfo; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.catalog.NamespaceInfo; import org.geoserver.config.GeoServerInfo; import org.geoserver.config.ResourceErrorHandling; import org.geoserver.data.test.CiteTestData; import org.geoserver.data.test.SystemTestData; import org.junit.Before; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; public class DescribeFeatureTest extends WFSTestSupport { @Before public void revert() throws Exception { revertLayer(CiteTestData.AGGREGATEGEOFEATURE); } @Override protected void setUpInternal(SystemTestData dataDirectory) throws Exception { DataStoreInfo di = getCatalog().getDataStoreByName(CiteTestData.CITE_PREFIX); di.setEnabled(false); getCatalog().save(di); } @Test public void testGet() throws Exception { Document doc = getAsDOM("wfs?service=WFS&request=DescribeFeatureType&version=1.0.0"); assertEquals("xsd:schema", doc.getDocumentElement().getNodeName()); } @Test public void testSkipMisconfiguredLayers() throws Exception { // make sure AggregateGeoFeature is in the mock data set Document doc = getAsDOM("wfs?service=WFS&request=DescribeFeatureType&version=1.0.0"); assertEquals("xsd:schema", doc.getDocumentElement().getNodeName()); XMLAssert.assertXpathEvaluatesTo("1", "count(//xsd:import[contains(@schemaLocation, 'AggregateGeoFeature')])", doc); // enable skipping of misconfigured layers GeoServerInfo global = getGeoServer().getGlobal(); global.setResourceErrorHandling(ResourceErrorHandling.SKIP_MISCONFIGURED_LAYERS); getGeoServer().save(global); // misconfigure a layer FeatureTypeInfo ftype = getCatalog() .getFeatureTypeByName(CiteTestData.AGGREGATEGEOFEATURE.getLocalPart()); ftype.setNativeName("NOT ACTUALLY THERE"); getCatalog().save(ftype); // check the results again doc = getAsDOM("wfs?service=WFS&request=DescribeFeatureType&version=1.0.0"); assertEquals("xsd:schema", doc.getDocumentElement().getNodeName()); XMLAssert.assertXpathEvaluatesTo("0", "count(//xsd:import[contains(@schemaLocation, 'AggregateGeoFeature')])", doc); } @Test public void testPost() throws Exception { String xml = "<wfs:DescribeFeatureType " + "service=\"WFS\" " + "version=\"1.0.0\" " + "xmlns:wfs=\"http://www.opengis.net/wfs\" />"; Document doc = postAsDOM("wfs", xml); assertEquals("xsd:schema", doc.getDocumentElement().getNodeName()); } @Test public void testPostDummyFeature() throws Exception { String xml = "<wfs:DescribeFeatureType " + "service=\"WFS\" " + "version=\"1.0.0\" " + "xmlns:wfs=\"http://www.opengis.net/wfs\" >" + " <wfs:TypeName>cgf:DummyFeature</wfs:TypeName>" + "</wfs:DescribeFeatureType>"; Document doc = postAsDOM("wfs", xml); assertEquals("ServiceExceptionReport", doc.getDocumentElement().getNodeName()); } @Test public void testWithoutExplicitMapping() throws Exception { String xml = "<DescribeFeatureType xmlns='http://www.opengis.net/wfs'" + " xmlns:gml='http://www.opengis.net/gml'" + " xmlns:ogc='http://www.opengis.net/ogc' version='1.0.0' service='WFS'>" + " <TypeName>cdf:Locks</TypeName>" + " </DescribeFeatureType>"; Document doc = postAsDOM("wfs", xml); assertEquals("xsd:schema", doc.getDocumentElement().getNodeName()); assertEquals(1, doc.getElementsByTagName("xsd:complexType").getLength()); } @Test public void testWithoutTypeName() throws Exception { Document doc = getAsDOM("wfs?request=DescribeFeatureType&version=1.0.0"); NodeList nl = doc.getElementsByTagName("xsd:import"); assertEquals(3, nl.getLength()); HashMap<String, HashMap<String, String>> imprts = new HashMap(); for (int i = 0; i < nl.getLength(); i++) { Element imprt = (Element) nl.item(i); String namespace = imprt.getAttribute("namespace"); String schemaLocation = imprt.getAttribute("schemaLocation"); int query = schemaLocation.indexOf("?"); schemaLocation = schemaLocation.substring(query + 1); String[] sp = schemaLocation.split("&"); HashMap params = new HashMap(); for (int j = 0; j < sp.length; j++) { String[] sp1 = sp[j].split("="); params.put(sp1[0].toLowerCase(), sp1[1].toLowerCase()); } imprts.put(namespace, params); } String[] expected = new String[] { CiteTestData.SF_URI, CiteTestData.CDF_URI, CiteTestData.CGF_URI }; for (String namespace : expected) { assertNotNull(imprts.get(namespace)); HashMap params = imprts.get(namespace); assertEquals("wfs", params.get("service")); assertEquals("1.0.0", params.get("version")); assertEquals("describefeaturetype", params.get("request")); String types = (String) params.get("typename"); assertNotNull(types); Catalog cat = getCatalog(); NamespaceInfo ns = cat.getNamespaceByURI(namespace); System.out.println(ns.getPrefix()); // %2c == , (url-encoded, comma is not considered a safe char) assertEquals(cat.getFeatureTypesByNamespace(ns).size(), types.split("%2c").length); } } @Test public void testWorkspaceQualified() throws Exception { Document doc = getAsDOM("sf/wfs?request=DescribeFeatureType&version=1.0.0"); NodeList nl = doc.getElementsByTagName("xsd:complexType"); assertEquals(3, nl.getLength()); XMLAssert.assertXpathExists("//xsd:complexType[@name = 'AggregateGeoFeatureType']", doc); XMLAssert.assertXpathExists("//xsd:complexType[@name = 'PrimitiveGeoFeatureType']", doc); XMLAssert.assertXpathExists("//xsd:complexType[@name = 'GenericEntityType']", doc); doc = getAsDOM("sf/wfs?request=DescribeFeatureType&version=1.0.0&typename=cdf:Fifteen"); XMLAssert.assertXpathExists("//ogc:ServiceException", doc); } @Test public void testMultipleNamespaceNoTargetNamespace() throws Exception { Document doc = getAsDOM( "wfs?request=DescribeFeatureType&version=1.0.0&typeName=sf:PrimitiveGeoFeature,cgf:Points"); assertEquals("xsd:schema", doc.getDocumentElement().getNodeName()); assertFalse(doc.getDocumentElement().hasAttribute("targetNamespace")); } @Test public void testMethodNameInjection() throws Exception { Document dom = getAsDOM("wfs?service=WFS&version=1.0.0" + "&request=DescribeFeatureType%22%3E%3C/ServiceException%3E%3Cfoo%3EHello,%20World%3C/foo%3E%3CServiceException+foo=%22" + "&typeName=sf:archsites"); // print(dom); // check we have a valid exception XMLAssert.assertXpathExists("/ogc:ServiceExceptionReport/ogc:ServiceException", dom); XMLAssert.assertXpathEvaluatesTo("OperationNotSupported", "/ogc:ServiceExceptionReport/ogc:ServiceException/@code", dom); // the locator has been escaped XMLAssert.assertXpathEvaluatesTo( "DescribeFeatureType\"></ServiceException><foo>Hello, World</foo><ServiceException foo=\"", "/ogc:ServiceExceptionReport/ogc:ServiceException/@locator", dom); // the attack failed and the foo element is not there XMLAssert.assertXpathNotExists("//foo", dom); } }